Compago

...free knowledge

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Manuali Programmazione Una GetProcAddress non importata

Una GetProcAddress non importata

E-mail Stampa PDF

In questo articolo verrà descritta una funzione, utile per conoscere l'indirizzo di una funzione esportata da una libreria, partendo dal suo Image Base Address.

Ora tanto per essere chiari, non ha molto senso usare questa funzione in fase di compilazione, dato che potremo sempre usare la funzione del kernel32 GetProcAddress, il problema sorge quando il codice che devo preparare deve trovare le funzioni da chiamare a runtime e in quel caso non potrebbe utilizzare la GetProcAddress dato che non ne conoscerebbe neppure l'indirizzo.

Nel seguente esempio useremo anche la funzione GetModuleHandleKernel32 per trovare l'IBA della libreria kernel32.dll, dopo di che al suo interno cercheremo l'indirizzo della funzione LoadLibraryA.

program KernelLoadLibraryAddress2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function GetModuleHandleKernel32:cardinal;
begin
  asm
    xor edx,edx
    mov edx,fs:[edx]    
    mov ebx,[edx+4]
    jmp @1
   @2:
    mov ebx,[edx+4]
    mov edx,[edx]
   @1:
    cmp edx,$FFFFFFFF
    jnz @2
    shr ebx,12
    shl ebx,12
   @3:
    cmp word[ebx],$5A4D   
    je @4                 
    add ebx,-$FFF         
    add ebx,-$1
    jmp @3
   @4:
    mov result,ebx
  end;
end;

function GetAddressFunction(IBA:cardinal;nome:PChar;Dim:cardinal):cardinal;
var
 N,i,j:cardinal;
 OK:boolean;
 NAT,FAT:Cardinal;
 P:PChar;
begin
  asm
    mov eax,IBA
    mov eax,[eax+$3c]   // trova il PE offset
    add eax,IBA
    add eax,$78
    mov eax,[eax]       // trova l'offset della Export Directory
    add eax,IBA         // Indirizzo della Export Directory
    mov ecx,[eax+$18]   // Numero delle funzioni esportate      (N)
    mov N,ecx
    mov edx,[eax+$1C]   // offset della tabella delle funzioni
    add edx,IBA         // Indirizzo della tabella delle funzioni (FAT)
    mov FAT,edx
    mov ebx,[eax+$20]   // offset della tabella dei nomi
    add ebx,IBA         // Indirizzo della tabella dei nomi    (NAT)
    mov NAT,ebx
  end;
  i:=0;
  OK:=false;
  while i<=n do begin //percorre tutta la lista dei nomi fino a trovare quello esatto
    P:=PChar(PCardinal(NAT)^+IBA);
    ok:=false;
    j:=0;
    while j<=Dim do begin
      if nome[j]=#0 then begin
        if P[j]=#0 then begin
          ok:=true;
          break;
        end
        else
          break;
      end
      else begin
        if P[j]<>nome[j] then
          break;
      end;
      inc(j);
    end;
    if ok then
      break;
    NAT:=NAT+4;
    inc(i);
  end;
//uno volta trovato l'indice lo usiamo per trovare
//l'indirizzo esatto della funzione esportata

  if ok then begin
    result:=Pcardinal(FAT+4*i)^+IBA;
  end
  else
    result:=0;
end;

var
  IBA:cardinal;
  Indirizzo:cardinal;
begin
  IBA:=GetModuleHandleKernel32;
  writeln(format('Indirizzo modulo kernel32.dll: %xh',[IBA]));
  Indirizzo:=GetAddressFunction(IBA,'LoadLibraryA',12);
  writeln(format('Indirizzo modulo kernel32.dll: %xh',[Indirizzo]));
  readln;
end.

questo metodo è molto diretto, e devo dire che la ricerca tra i nomi delle funzioni si sarebbe potuta fare anche usando un valore di hash del nome, cioè prima avremo dovuto calcolare il valore di hash del nome cercato, e dopo avremo dovuto calcolare il valore di hash di tutte le funzioni fino a quando questo non avrebbe avuto lo stesso valore di quello originario. Questo sicuramente avrebbe reso molto meno complicato l'algoritmo.

Vediamo una sua implementazione:

function GetAddressFunction(IBA:cardinal;nome:PChar):cardinal;
begin
  asm
    mov ebx,IBA
    mov ebx,[ebx+$3c]   // trova il PE offset
    add ebx,IBA
    add ebx,$78
    mov ebx,[ebx]       // trova l'offset della Export Directory
    add ebx,IBA         // Indirizzo della Export Directory
    mov ecx,[ebx+$18]   // Numero delle funzioni esportate      (N)  ecx
    mov edx,[ebx+$20]   // offset della tabella dei nomi
    add edx,IBA         // Indirizzo della tabella dei nomi    (NAT) edx

    xor ebx,ebx         //calcola hash nome funzione da trovare
    mov esi,nome
   @2:
    xor eax,eax
    lodsb
    cmp al,ah           // fine stringa?
    je @1
    add ebx,eax
    jmp @2
   @1:                  //percorre la lista dei nomi delle funzioni
    mov esi,[edx+ecx*4] //calcolandone l'hash
    add esi,IBA
    xor edi,edi
   @3:
    xor eax,eax
    lodsb
    cmp al,ah           // fine stringa?
    je @4
    add edi,eax
    jmp @3
   @4:
    cmp ebx,edi         //confronta hash
    je @5
    test ecx,ecx
    jz @7
    dec ecx
    jmp @1
   @7:
    xor eax,eax
    mov result,eax
    jmp @6
   @5:
    mov ebx,IBA         // se ha trovato un riscontro:
    mov ebx,[ebx+$3c]   // trova il PE offset
    add ebx,IBA
    add ebx,$78
    mov ebx,[ebx]       // trova l'offset della Export Directory
    add ebx,IBA         // Indirizzo della Export Directory
    mov edx,[ebx+$1C]   // offset della tabella delle funzioni
    add edx,IBA         // Indirizzo della tabella delle funzioni (FAT) edx

    shl ecx,2           //Indirizzo funzione = [FAT+4*i]+IBA;
    add edx,ecx         //
    mov edx,[edx]       //
    add edx,IBA         //
    mov result,edx      //
   @6:
    lea ebx,ebp-$0c
  end;
end;

Riporto anche il relativo codice macchina:

// begin
00408B84 55 push ebp
00408B85 8BEC mov ebp,esp
00408B87 83C4F4 add esp,-$0c
00408B8A 53 push ebx
00408B8B 8955F8 mov [ebp-$08],edx
00408B8E 8945FC mov [ebp-$04],eax
00408B91 8D5DF4 lea ebx,[ebp-$0c]

00408B94 8B5DFC mov ebx,[ebp-$04] // mov ebx,IBA
00408B97 8B5B3C mov ebx,[ebx+$3c] // trova il PE offset
00408B9A 035DFC add ebx,[ebp-$04] // add ebx,IBA
00408B9D 83C378 add ebx,$78 // add ebx,$78
00408BA0 8B1B mov ebx,[ebx] // trova l'offset della Export Directory
00408BA2 035DFC add ebx,[ebp-$04] // add ebx,IBA - Indirizzo della Export Directory
00408BA5 8B4B18 mov ecx,[ebx+$18] // Numero delle funzioni esportate (N) ecx
00408BA8 8B5320 mov edx,[ebx+$20] // offset della tabella dei nomi
00408BAB 0355FC add edx,[ebp-$04] // add edx,IBA - Indirizzo della tabella dei nomi (NAT) edx
00408BAE 31DB xor ebx,ebx //calcola hash nome funzione da trovare
00408BB0 8B75F8 mov esi,[ebp-$08] // mov esi,nome
00408BB3 31C0 xor eax,eax
00408BB5 AC lodsb
00408BB6 38E0 cmp al,ah // fine stringa?
00408BB8 7404 jz $00408bbe // je @1
00408BBA 01C3 add ebx,eax
00408BBC EBF5 jmp $00408bb3 // jmp @2
00408BBE 8B348A mov esi,[edx+ecx*4] //calcola l'hash
00408BC1 0375FC add esi,[ebp-$04] // add esi,IBA
00408BC4 31FF xor edi,edi
00408BC6 31C0 xor eax,eax
00408BC8 AC lodsb
00408BC9 38E0 cmp al,ah // fine stringa?
00408BCB 7404 jz $00408bd1 // je @4
00408BCD 01C7 add edi,eax
00408BCF EBF5 jmp $00408bc6 // jmp @3
00408BD1 39FB cmp ebx,edi //confronta hash
00408BD3 740E jz $00408be3 // je @5
00408BD5 85C9 test ecx,ecx
00408BD7 7403 jz $00408bdc // jz @7
00408BD9 49 dec ecx
00408BDA EBE2 jmp $00408bbe // jmp @1
00408BDC 31C0 xor eax,eax
00408BDE 8945F4 mov [ebp-$0c],eax // mov result,eax
00408BE1 EB24 jmp $00408c07 // jmp @6
00408BE3 8B5DFC mov ebx,[ebp-$04] // mov ebx,IBA - se ha trovato un riscontro:
00408BE6 8B5B3C mov ebx,[ebx+$3c] // trova il PE offset
00408BE9 035DFC add ebx,[ebp-$04] // add ebx,IBA
00408BEC 83C378 add ebx,$78
00408BEF 8B1B mov ebx,[ebx] // mov ebx,[ebx] - trova l'offset della Export Directory
00408BF1 035DFC add ebx,[ebp-$04] // add ebx,IBA - Indirizzo della Export Directory
00408BF4 8B531C mov edx,[ebx+$1c] // offset della tabella delle funzioni
00408BF7 0355FC add edx,[ebp-$04] // add edx,IBA - Indirizzo della tabella delle funzioni (FAT) edx
00408BFA C1E102 shl ecx,$02 //Indirizzo funzione = [FAT+4*i]+IBA;
00408BFD 01CA add edx,ecx
00408BFF 8B12 mov edx,[edx]
00408C01 0355FC add edx,[ebp-$04] // add edx,IBA
00408C04 8955F4 mov [ebp-$0c],edx // mov result,edx

00408C07 8D5DF4 lea ebx,[ebp-$0c]

00408C0A 8B03 mov eax,[ebx] // end;
00408C0C 5B pop ebx
00408C0D 8BE5 mov esp,ebp
00408C0F 5D pop ebp
00408C10 C3 ret

Naturalmente per poter essere usato bisognerà adattarlo al contesto, ma la parte centrale dovrebbe rimanere la stessa.

Ultimo aggiornamento ( Sabato 19 Giugno 2010 17:19 )