Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Analisi della Export Directory in un PE Binary.
Parte2: elenco delle funzioni esportate da un modulo mappato nello spazio di memoria di un processo remoto

 

Nel precedente articolo (articolo82.htm) abbiamo visto come determinare il Virtual Address di una funzione nello spazio di memoria di un processo remoto ossia un GetProcAddress in remoto. Ora ci porremo un obiettivo molto simile: enumerare gli exports di un modulo mappato nello spazio di memoria di un processo remoto. Per ogni export andremo a restituire le seguenti informazioni:

1) Ordinal

2) Nome (stringa <senza_nome> nel caso in cui la funzione in questione non abbia nome)

3) RVA (Relative Virtual Address) o ForwardName

1. Implementazione

Anche in questo caso, è inutile descrivere i passaggi e la cosa migliore è una bella sbrodolata di codice commentato

type ExportedInfo = record Ordinal: Cardinal; Name: string; ForwardName: string; RVA: Cardinal; end; TElencoFunzioniEsportateCallBackFunc = procedure(var info: ExportedInfo); ... function RemoteModuleExported( //handle al processo hProcess: Cardinal; //Indirizzo di base del modulo (ottenuto con RemoteGetModuleHandle) hModule: Cardinal; //NomeModulo: string; //NomeFunzione: string; //puntatore ad una stringa che definisce il nome della funzione callbackfunc: TElencoFunzioniEsportateCallBackFunc): Boolean; var DosHeader : TImageDosHeader; //Dos Header NtHeaders : TImageNtHeaders; //PE Header DataDirectory : TImageDataDirectory; //Data Directory ExportDirectory : TImageExportDirectory; //Export Directory BytesRead: Cardinal; //var per ReadProcessMemory //estremo inferiore e superiore della Export Directory ExportDataDirectoryLow, ExportDataDirectoryHigh: cardinal; //valore Base di IMAGE_EXPORT_DIRECTORY: valore base degli Ordinal BaseOrdinal: Cardinal; // NumberOfFunctions: Cardinal; NumberOfNames: Cardinal; //puntatori ai 3 array First_AddressOfFunctions: Cardinal; First_AddressOfNames: Cardinal; First_AddressOfNameOrdinals: Cardinal; Actual_AddressOfFunctions: Cardinal; Actual_AddressOfNames: Cardinal; Actual_AddressOfNameOrdinals: Cardinal; // //indice della funzione nell'array puntato da //IMAGE_EXPORT_DIRECTORY.AddressOfFunctions: //l'elemento dell'array che si trova in questa //posizione contiene l'RVA della funzione FunctionIndex: Cardinal; //Ordinal della funzione: FunctionIndex + BaseOrdinal FunctionOrdinal: Cardinal; //RVA presente in un elemento dell'array puntato //da IMAGE_EXPORT_DIRECTORY.AddressOfNames FunctionNameRVA: Cardinal; //nome puntato dall'RVA presente in un //elemento dell'array puntato da //IMAGE_EXPORT_DIRECTORY.AddressOfNames FunctionName: PAnsiChar; FunctionNameFound: Boolean; //RVA della funzione che cerchiamo: è presente //in un elemento dell'array puntato da //IMAGE_EXPORT_DIRECTORY.AddressOfFunctions FunctionRVA: Cardinal; //Forwarding FunctionForwardName: PAnsiChar; ForwardPuntoPos: Cardinal; ExportForward: Boolean; // i: Cardinal; info: ExportedInfo; IsFunctionNamed: array of Boolean; begin Result := False; //verifica sui valori dei parametri if (hProcess = 0) or (hModule = 0) then begin Exit; end; try //prelevo il Dos Header if not ReadProcessMemory( hProcess, Pointer(hModule), @DosHeader, sizeof(DosHeader), BytesRead ) then begin ErrStr('ReadProcessMemory'); Exit; end; //verifica della validità if (DosHeader.e_magic <> IMAGE_DOS_SIGNATURE) then Exit; //prelevo il PE Header if not ReadProcessMemory( hProcess, Pointer(hModule + DosHeader._lfanew), @NtHeaders, sizeof(NtHeaders), BytesRead ) then begin ErrStr('ReadProcessMemory'); Exit; end; //verifica della validità if (NtHeaders.Signature <> IMAGE_NT_SIGNATURE) then Exit; //se il modulo non ha la directory di Export allora esco //valuto l' RVA della directory di export if NTHeaders.OptionalHeader.DataDirectory[0].VirtualAddress = 0 then Exit; //calcolo il range di definizione della Export Directory //mi servirà per valutare se l'RVA di una funzione punta alla definizione //della funzione (valore esterno all'intervallo) oppure punta ad una stringa //del tipo nome_dll.nome_funzione (valore interno all'intervallo) with NTHeaders.OptionalHeader.DataDirectory[0] do begin ExportDataDirectoryLow := VirtualAddress; ExportDataDirectoryHigh := VirtualAddress + Size; end; //prelevo la Export Directory if not ReadProcessMemory( hProcess, Pointer(hModule + ExportDataDirectoryLow), @ExportDirectory, sizeof(ExportDirectory), BytesRead ) then begin ErrStr('ReadProcessMemory'); Exit; end; //Determino il valore base degli Ordinal BaseOrdinal := ExportDirectory.Base; // NumberOfFunctions := ExportDirectory.NumberOfFunctions; NumberOfNames := ExportDirectory.NumberOfNames; //inizializzo l'array che, per ogni funzione esportata, memorizza se ha //un nome associato SetLength(IsFunctionNamed, NumberOfFunctions); ZeroMemory(IsFunctionNamed, NumberOfFunctions * SizeOf(Boolean)); // First_AddressOfFunctions := hModule + Cardinal(ExportDirectory.AddressOfFunctions); First_AddressOfNames := hModule + Cardinal(ExportDirectory.AddressOfNames); First_AddressOfNameOrdinals := hModule + Cardinal(ExportDirectory.AddressOfNameOrdinals); //allocazione di memoria per puntatori che riceveranno stringhe di caratteri GetMem(FunctionName, 100); GetMem(FunctionForwardName, 100); //scanno l'array puntato da IMAGE_EXPORT_DIRECTORY.AddressOfNames //che contiene i nomi delle funzioni esportate con associato un nome; //ogni elemento dell'array è 4 byte (è infatti l'RVA del nome della funzione) for i := 0 to NumberOfNames - 1 do {for each export do} begin Actual_AddressOfNames := First_AddressOfNames + SizeOf(Cardinal) * i; //prelevo l'RVA del nome: FunctionNameRVA ReadProcessMemory( hProcess, Pointer(Actual_AddressOfNames) , @FunctionNameRVA, 4, BytesRead); //prelevo il nome: FunctionName ReadProcessMemory( hProcess, Pointer(hModule + FunctionNameRVA) , FunctionName, 100, BytesRead ); //vado nell'array puntato da IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals: //l'elemento di posizione i contiene l'indice della funzione nell'array //puntato da IMAGE_EXPORT_DIRECTORY.AddressOfFunctions Actual_AddressOfNameOrdinals := First_AddressOfNameOrdinals + SizeOf(Word) * i; FunctionIndex := 0; //prelevo l'indice: FunctionIndex ReadProcessMemory( hProcess, Pointer(Actual_AddressOfNameOrdinals) , @FunctionIndex, 2, BytesRead ); //la funzione di indice FunctionIndex ossia la funziona esaminata //attualmente dispone di un nome IsFunctionNamed[FunctionIndex] := True; //Perfetto ho ottenuto l'indice nell'array puntato //da IMAGE_EXPORT_DIRECTORY.AddressOfFunctions; a questo //punto posso prelevare l'RVA della funzione; prima però calcolo //l'Ordinal FunctionOrdinal := FunctionIndex + BaseOrdinal; Actual_AddressOfFunctions := First_AddressOfFunctions + SizeOf(Cardinal) * FunctionIndex; //prelevo l'RVA ReadProcessMemory( hProcess, Pointer(Actual_AddressOfFunctions) , @FunctionRVA, 4, BytesRead ); //Bene: ho l'RVA della funzione; devo ora vedere se //rientra nella Export Directory: in tal caso punta //ad una stringa del tipo nome_dll.nome_funzione //(Forwarding) ExportForward := False; if (FunctionRVA > ExportDataDirectoryLow) and (FunctionRVA <= ExportDataDirectoryHigh) then //questo è un forwarding begin ExportForward := True; //prelevo la stringa modello nome_dll.nome_funzione ReadProcessMemory( hProcess, Pointer(hModule + FunctionRVA) , FunctionForwardName, 100, BytesRead ); end; with info do begin Ordinal := FunctionOrdinal; Name := FunctionName; if ExportForward then ForwardName := FunctionForwardName else ForwardName := ''; RVA := FunctionRVA; end; //chiamata alla funzione di CallBack callbackfunc(info); end; //scanno le funzioni esportate che non hanno associato un nome for i := 0 to NumberOfFunctions - 1 do begin if not IsFunctionNamed[i] then begin FunctionIndex := i; FunctionOrdinal := FunctionIndex + BaseOrdinal; Actual_AddressOfFunctions := First_AddressOfFunctions + SizeOf(Cardinal) * FunctionIndex; //prelevo l'RVA ReadProcessMemory( hProcess, Pointer(Actual_AddressOfFunctions) , @FunctionRVA, 4, BytesRead ); //Bene: ho l'RVA della funzione; devo ora vedere se //rientra nella Export Directory: in tal caso punta //ad una stringa del tipo nome_dll.nome_funzione //(Forwarding) ExportForward := False; if (FunctionRVA > ExportDataDirectoryLow) and (FunctionRVA <= ExportDataDirectoryHigh) then //questo è un forwarding begin ExportForward := True; //prelevo la stringa modello nome_dll.nome_funzione ReadProcessMemory( hProcess, Pointer(hModule + FunctionRVA) , FunctionForwardName, 100, BytesRead ); end; with info do begin Ordinal := FunctionOrdinal; Name := ''; if ExportForward then ForwardName := FunctionForwardName else ForwardName := ''; RVA := FunctionRVA; end; //chiamata alla funzione di CallBack callbackfunc(info); end; end; Result := True; finally if FunctionName <> nil then FreeMem(Pointer(FunctionName)); if FunctionForwardName <> nil then FreeMem(Pointer(FunctionForwardName)); end; end;

Behh, anche qui un esempio di applicazione può aiutare

RemoteModuleExports.7z

 

 

 
 
Your Ad Here