|
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
|