Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

LoadLibrary e FreeLibrary su un processo remoto usando le api Native per la gestione delle dll


In questo articolo vengono uniti tra loro i concetti esposti nell'articolo sul CodeInjection (all'interno del quale alla fine vengono presentate 2 procedure per caricare e scaricare una dll relativamente allo spazio di memoria di un processo remoto) e nell'articolo sulle Native Api dedicate alla gestione delle dll: in pratica andremo a riscrivere l'implementazione della funzione del thread remoto usando le Native API. Ho fatto un pò di prove (senza esagerare lo ammetto) e non ho trovato differenze sostanziali tra una implementazione e l'altra: del resto non mi aspettavo nulla di speciale, più che altro ho deciso di implementare il tutto per puro divertimento.

1. Implementazione

I concetti di riferimento sono quelli approfonditi nel 2 articoli sopra citati: si può quindi passare direttamente al codice

1.1 RemoteLoadLibraryNative

function RemoteLoadLibraryNative( PID: Cardinal; //PID del processo remoto NomeDll: PAnsiChar; var outValue: Cardinal; //valore importante ottenuto dalla funzione remota var codError: Cardinal; //errore riscontrato dalla funzione remota synch: Boolean): Boolean; //esecuzione sincrona del thread remoto type TRemoteLoadLibraryNativeData = record errorcod: Cardinal; //codice di errore rilevato nella funzione remota output: Cardinal; //risultato significativo nella funzione remota //Indirizzi delle API usate: elenco puntatori a funzioni; N.B. rigorosamente stdcall //Es. pLoadLibraryA: function(pLibFileName: PAnsiChar): Cardinal; stdcall; pExitThread: procedure (dwExitCode: Cardinal); stdcall; //API obbligatoria pRtlAnsiStringToUnicodeString: function( DestinationString : PUNICODE_STRING; SourceString : PANSI_STRING; AllocateDestinationString : Boolean ): Integer; stdcall; pLdrGetDllHandle: function( pwPath : PWORD; Unused : pointer; ModuleFileName : PUNICODE_STRING; pHModule : pCardinal ): Integer; stdcall; pLdrLoadDll: function( PathToFile : PWideChar; Flags : Cardinal; ModulFileName : PUNICODE_STRING; ModuleHandle : pCardinal ): integer; stdcall; pRtlFreeUnicodeString: procedure( UnicodeString : PUNICODE_STRING ); stdcall; pRtlNtStatusToDosError: function( const Status : Integer ): Cardinal; stdcall; //Puntatori a dati; Es. tutte le stringhe vanno messe qui dentro //Es. pNomeDll: Pointer; pNomeDll: Pointer; NomeDllLength: Cardinal; //ModuleFileNameLength: Cardinal; //ModuleHandle: Cardinal; end; var hProcess: Cardinal; //handle al processo remoto RemoteLoadLibraryNativeData: TRemoteLoadLibraryNativeData; pRemoteLoadLibraryNativeData: Pointer; //indirizzo del record nello //spazio di memoria del processo remoto pRemoteLoadLibraryNativeThread: Pointer; //indirizzo della funzione del thread //nello spazio di memoria del processo remoto output_value: Cardinal; error_code: Cardinal; functionSize, parameterSize: Cardinal; procedure RemoteLoadLibraryNativeThread(lpParameter: pointer); stdcall; var //qui posso definire delle variabili locali AnsString: ANSI_STRING; UncString: UNICODE_STRING; status: Integer; hModule: Cardinal; begin with TRemoteLoadLibraryNativeData(lpParameter^) do begin //implementazione: tutte le API vengono chiamate tramite i puntatori nel record AnsString.Buffer := pNomeDll; AnsString.Length := NomeDllLength; AnsString.MaximumLength := NomeDllLength; status := pRtlAnsiStringToUnicodeString( @UncString, @AnsString, True); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); pExitThread(0); end; status := pLdrGetDllHandle(nil, nil, @UncString, @output); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); if errorcod <> 126 then pExitThread(0); end else pExitThread(1); status := pLdrLoadDll(nil, 0, @UncString, @output); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); pExitThread(0); end; pRtlFreeUnicodeString(@UncString); pExitThread(1); //N.B. chiamare sempre pExitCodeThread per definire il codice di uscita del thread //Es. pExitCodeThread(1) significa successo // pExitCodeThread(0) significa fallimento end; end; //dealloco la memoria in remoto function RemoteLoadLibraryNativeUnloadData(): Boolean; begin Result := False; with RemoteLoadLibraryNativeData do begin //chiamo UnloadData su tutti i puntatori a dati inclusi nel record UnloadData(hProcess, pNomeDll); end; //deallocazione spazio per il parametro UnloadData(hProcess, pRemoteLoadLibraryNativeData); //deallocazione spazio per la funzione UnloadData(hProcess, pRemoteLoadLibraryNativeThread); Result := True; end; //definisco i valori dei campi del record e copio i dati in remoto function RemoteLoadLibraryNativeInjectData(): Boolean; begin Result := False; try //inizializzazione valori campi del record: with RemoteLoadLibraryNativeData do begin errorcod := 0; output := 0; //assegno i valori ai puntatori a funzione //(tramite GetModuleHandle e GetProcAddres) //Es. pLoadLibraryA := GetProcAddress(GetModuleHandle('kernel32'), 'LoadLibraryA'); pExitThread := GetProcAddress(GetModuleHandle('kernel32'), 'ExitThread'); //API Obbligatoria pRtlAnsiStringToUnicodeString := GetProcAddress(GetModuleHandle('ntdll'), 'RtlAnsiStringToUnicodeString'); pLdrGetDllHandle := GetProcAddress(GetModuleHandle('ntdll'), 'LdrGetDllHandle'); pLdrLoadDll := GetProcAddress(GetModuleHandle('ntdll'), 'LdrLoadDll'); pRtlFreeUnicodeString := GetProcAddress(GetModuleHandle('ntdll'), 'RtlFreeUnicodeString'); pRtlNtStatusToDosError := GetProcAddress(GetModuleHandle('ntdll'), 'RtlNtStatusToDosError'); NomeDllLength := Length(NomeDll) + 1; //assegno i valori ai puntatori ai dati (tramite InjectData); //N.B. se una InjectData ritorna False allora bisogna chiamare Exit if not InjectData(hProcess, NomeDll, Length(NomeDll), False, pNomeDll) then begin Exit; end; end; //copio il parametro parameterSize := SizeOf(RemoteLoadLibraryNativeData); if not InjectData(hProcess, @RemoteLoadLibraryNativeData, parameterSize, False, pRemoteLoadLibraryNativeData) then begin Exit; end; //copio la funzione functionSize := SizeOfProc(@RemoteLoadLibraryNativeThread); if not InjectData(hProcess, @RemoteLoadLibraryNativeThread, functionSize, True, pRemoteLoadLibraryNativeThread) then begin Exit; end; Result := True; finally if not Result then begin RemoteLoadLibraryNativeUnloadData; end; end; end; begin //inizializzo a zero le variabili locali hProcess := 0; pRemoteLoadLibraryNativeData := nil; pRemoteLoadLibraryNativeThread := nil; output_value := 0; error_code := 0; try hProcess := OpenProcessEx(PROCESS_CREATE_THREAD + PROCESS_QUERY_INFORMATION + PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, PID ); if hProcess = 0 then begin ErrStr('OpenProcessEx'); Exit; end; if not RemoteLoadLibraryNativeInjectData() then Exit; if not InjectThread(hProcess, pRemoteLoadLibraryNativeThread, pRemoteLoadLibraryNativeData, output_value, error_code, synch) then Exit; //output_value e error_code sono stati inizializzati a 0. //sono stati modificati dalla InjectThread solo se synch = true; //se synch=false sono rimasti uguali a zero outvalue := output_value; codError := error_code; Result := True; finally if synch or (not Result) then begin RemoteLoadLibraryNativeUnloadData; end; if hProcess <> 0 then begin if not CloseHandle(hProcess) then begin ErrStr('CloseHandle'); end; end; end; end;

1.2 RemoteFreeLibraryNative

function RemoteFreeLibraryNative(PID: Cardinal; //PID del processo remoto NomeDll: PAnsiChar; var outValue: Cardinal; //valore importante ottenuto dalla funzione remota var codError: Cardinal; //errore riscontrato dalla funzione remota synch: Boolean): Boolean; //esecuzione sincrona del thread remoto type TRemoteFreeLibraryNativeData = record errorcod: Cardinal; //codice di errore rilevato nella funzione remota output: Cardinal; //risultato significativo nella funzione remota //Indirizzi delle API usate: elenco puntatori a funzioni; N.B. rigorosamente stdcall //Es. pLoadLibraryA: function(pLibFileName: PAnsiChar): Cardinal; stdcall; pExitThread: procedure (dwExitCode: Cardinal); stdcall; //API obbligatoria pRtlAnsiStringToUnicodeString: function( DestinationString : PUNICODE_STRING; SourceString : PANSI_STRING; AllocateDestinationString : Boolean ): Integer; stdcall; pLdrGetDllHandle: function( pwPath : PWORD; Unused : pointer; ModuleFileName : PUNICODE_STRING; pHModule : pCardinal ): Integer; stdcall; pLdrUnLoadDll: function( ModuleHandle: Cardinal ): Integer; stdcall; pRtlFreeUnicodeString: procedure( UnicodeString : PUNICODE_STRING ); stdcall; pRtlNtStatusToDosError: function( const Status : Integer ): Cardinal; stdcall; //Puntatori a dati; Es. tutte le stringhe vanno messe qui dentro //Es. pNomeDll: Pointer; pNomeDll: Pointer; NomeDllLength: Cardinal; //ModuleFileNameLength: Cardinal; //ModuleHandle: Cardinal; end; var hProcess: Cardinal; //handle al processo remoto RemoteFreeLibraryNativeData: TRemoteFreeLibraryNativeData; pRemoteFreeLibraryNativeData: Pointer; //indirizzo del record nello //spazio di memoria del processo remoto pRemoteFreeLibraryNativeThread: Pointer; //indirizzo della funzione del thread //nello spazio di memoria del processo remoto output_value: Cardinal; error_code: Cardinal; functionSize, parameterSize: Cardinal; procedure RemoteFreeLibraryNativeThread(lpParameter: pointer); stdcall; var //qui posso definire delle variabili locali AnsString: ANSI_STRING; UncString: UNICODE_STRING; status: Integer; hModule: Cardinal; begin with TRemoteFreeLibraryNativeData(lpParameter^) do begin //implementazione: tutte le API vengono chiamate tramite i puntatori nel record AnsString.Buffer := pNomeDll; AnsString.Length := NomeDllLength; AnsString.MaximumLength := NomeDllLength; status := pRtlAnsiStringToUnicodeString( @UncString, @AnsString, True); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); pExitThread(0); end; status := pLdrGetDllHandle(nil, nil, @UncString, @output); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); pExitThread(0); end; status := pLdrUnLoadDll(output); if status < 0 then begin errorcod := pRtlNtStatusToDosError(status); pExitThread(0); end; pRtlFreeUnicodeString(@UncString); pExitThread(1); //N.B. chiamare sempre pExitCodeThread per definire il codice di uscita del thread //Es. pExitCodeThread(1) significa successo // pExitCodeThread(0) significa fallimento end; end; //dealloco la memoria in remoto function RemoteFreeLibraryNativeUnloadData(): Boolean; begin Result := False; with RemoteFreeLibraryNativeData do begin //chiamo UnloadData su tutti i puntatori a dati inclusi nel record UnloadData(hProcess, pNomeDll); end; //deallocazione spazio per il parametro UnloadData(hProcess, pRemoteFreeLibraryNativeData); //deallocazione spazio per la funzione UnloadData(hProcess, pRemoteFreeLibraryNativeThread); Result := True; end; //definisco i valori dei campi del record e copio i dati in remoto function RemoteFreeLibraryNativeInjectData(): Boolean; begin Result := False; try //inizializzazione valori campi del record: with RemoteFreeLibraryNativeData do begin errorcod := 0; output := 0; //assegno i valori ai puntatori a funzione (tramite GetModuleHandle e GetProcAddres) //Es. pLoadLibraryA := GetProcAddress(GetModuleHandle('kernel32'), 'LoadLibraryA'); pExitThread := GetProcAddress(GetModuleHandle('kernel32'), 'ExitThread'); //API Obbligatoria pRtlAnsiStringToUnicodeString := GetProcAddress(GetModuleHandle('ntdll'), 'RtlAnsiStringToUnicodeString'); pLdrGetDllHandle := GetProcAddress(GetModuleHandle('ntdll'), 'LdrGetDllHandle'); pLdrUnloadDll := GetProcAddress(GetModuleHandle('ntdll'), 'LdrUnloadDll'); pRtlFreeUnicodeString := GetProcAddress(GetModuleHandle('ntdll'), 'RtlFreeUnicodeString'); pRtlNtStatusToDosError := GetProcAddress(GetModuleHandle('ntdll'), 'RtlNtStatusToDosError'); NomeDllLength := Length(NomeDll) + 1; //assegno i valori ai puntatori ai dati (tramite InjectData); //N.B. se una InjectData ritorna False allora bisogna chiamare Exit if not InjectData(hProcess, NomeDll, Length(NomeDll), False, pNomeDll) then begin Exit; end; end; //copio il parametro parameterSize := SizeOf(RemoteFreeLibraryNativeData); if not InjectData(hProcess, @RemoteFreeLibraryNativeData, parameterSize, False, pRemoteFreeLibraryNativeData) then begin Exit; end; //copio la funzione functionSize := SizeOfProc(@RemoteFreeLibraryNativeThread); if not InjectData(hProcess, @RemoteFreeLibraryNativeThread, functionSize, True, pRemoteFreeLibraryNativeThread) then begin Exit; end; Result := True; finally if not Result then begin RemoteFreeLibraryNativeUnloadData; end; end; end; begin //inizializzo a zero le variabili locali hProcess := 0; pRemoteFreeLibraryNativeData := nil; pRemoteFreeLibraryNativeThread := nil; output_value := 0; error_code := 0; try hProcess := OpenProcessEx(PROCESS_CREATE_THREAD + PROCESS_QUERY_INFORMATION + PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, PID ); if hProcess = 0 then begin ErrStr('OpenProcessEx'); Exit; end; if not RemoteFreeLibraryNativeInjectData() then Exit; if not InjectThread(hProcess, pRemoteFreeLibraryNativeThread, pRemoteFreeLibraryNativeData, output_value, error_code, synch) then Exit; //output_value e error_code sono stati inizializzati a 0. //sono stati modificati dalla InjectThread solo se synch = true; //se synch=false sono rimasti uguali a zero outvalue := output_value; codError := error_code; Result := True; finally if synch or (not Result) then begin RemoteFreeLibraryNativeUnloadData; end; if hProcess <> 0 then begin if not CloseHandle(hProcess) then begin ErrStr('CloseHandle'); end; end; end; end;

RemoteLoadUnloadNative.7z

 

 

 

  

 
 
Your Ad Here