|
Ecco un altro esempio di utilizzo della tecnica di Code Injection esposta
nell'articolo Code Injection.
1. Implementazione
function RemoteCreateProcess(
PID: Cardinal; //PID del processo remoto
//dichiarazione di tutti i parametri che vogliamo
NomeProg: PAnsiChar;
NomeDesktop: 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
TRemoteCreateProcessData = 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
pGetLastError: function(): Cardinal; stdcall;
pCreateProcessA: function (lpApplicationName: PAnsiChar;
lpCommandLine: PAnsiChar;
lpProcessAttributes: PSecurityAttributes;
lpThreadAttributes: PSecurityAttributes;
bInheritHandles: Boolean;
dwCreationFlags: Cardinal;
lpEnvironment: Pointer;
lpCurrentDirectory: PAnsiChar;
const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation): Boolean; stdcall;
pCloseHandle: function (hObject: Cardinal): Boolean; stdcall;
//Puntatori a dati; Es. tutte le stringhe vanno messe qui dentro
//Es. pNomeDll: Pointer;
pProgName: Pointer;
pDesktopName: Pointer;
end;
var
hProcess: Cardinal; //handle al processo remoto
RemoteCreateProcessData: TRemoteCreateProcessData;
//indirizzo del record nello spazio di memoria del processo remoto
pRemoteCreateProcessData: Pointer;
//indirizzo della funzione del thread nello spazio di memoria del processo remoto
pRemoteCreateProcessThread: Pointer;
output_value: Cardinal;
error_code: Cardinal;
functionSize, parameterSize: Cardinal;
procedure RemoteCreateProcessThread(lpParameter: pointer); stdcall;
var
//qui posso definire delle variabili locali
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
with TRemoteCreateProcessData(lpParameter^) do
begin
//implementazione: tutte le API vengono chiamate tramite i puntatori nel record
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.lpReserved := nil;
StartupInfo.lpDesktop := pDesktopName;
StartupInfo.lpTitle := nil;
StartupInfo.dwX := 0;
StartupInfo.dwY := 0;
StartupInfo.dwXSize := 0;
StartupInfo.dwYSize := 0;
StartupInfo.dwXCountChars := 0;
StartupInfo.dwYCountChars := 0;
StartupInfo.dwFillAttribute := 0;
StartupInfo.dwFlags := 1;
StartupInfo.wShowWindow := 5;
StartupInfo.cbReserved2 := 0;
StartupInfo.lpReserved2 := nil;
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := 0;
StartupInfo.hStdError := 0;
if not pCreateProcessA(nil,
pProgName,
nil,
nil,
False,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil,
nil,
StartupInfo,
ProcessInfo) then
begin
errorcod := pGetLastError;
pExitThread(0);
end
else
begin
//come output metto il PID del processo creato
output := ProcessInfo.dwProcessId;
pCloseHandle(ProcessInfo.hProcess);
pExitThread(1);
end;
end;
end;
//dealloco la memoria in remoto
function RemoteCreateProcessUnloadData(): Boolean;
begin
Result := False;
with RemoteCreateProcessData do
begin
//chiamo UnloadData su tutti i puntatori a dati inclusi nel record
UnloadData(hProcess, pDesktopName);
UnloadData(hProcess, pProgName);
end;
//deallocazione spazio per il parametro
UnloadData(hProcess, pRemoteCreateProcessData);
//deallocazione spazio per la funzione
UnloadData(hProcess, pRemoteCreateProcessThread);
Result := True;
end;
//definisco i valori dei campi del record e copio i dati in remoto
function RemoteCreateProcessInjectData(): Boolean;
begin
Result := False;
try
//inizializzazione valori campi del record:
with RemoteCreateProcessData do
begin
errorcod := 0;
output := 0;
//assegno i valori ai puntatori a funzione (tramite GetModuleHandle e GetProcAddress)
//Es. pLoadLibraryA := GetProcAddress(GetModuleHandle('kernel32'),
'LoadLibraryA');
pExitThread := GetProcAddress(GetModuleHandle('kernel32'),
'ExitThread'); //API Obbligatoria
pGetLastError := GetProcAddress(GetModuleHandle('kernel32'),
'GetLastError');
pCreateProcessA := GetProcAddress(GetModuleHandle('kernel32'),
'CreateProcessA');
pCloseHandle := GetProcAddress(GetModuleHandle('kernel32'),
'CloseHandle');
//assegno i valori ai puntatori ai dati (tramite InjectData);
//N.B. se una InjectData ritorna False allora bisogna chiamare Exit
if not InjectData(hProcess,
NomeProg,
Length(NomeProg),
False,
pProgName) then
begin
Exit;
end;
if not InjectData(hProcess,
NomeDesktop,
Length(NomeDesktop),
False,
pDesktopName) then
begin
Exit;
end;
end;
//copio il parametro
parameterSize := SizeOf(RemoteCreateProcessData);
if not InjectData(hProcess,
@RemoteCreateProcessData,
parameterSize,
False,
pRemoteCreateProcessData) then
begin
Exit;
end;
//copio la funzione
functionSize := SizeOfProc(@RemoteCreateProcessThread);
if not InjectData(hProcess,
@RemoteCreateProcessThread,
functionSize,
True,
pRemoteCreateProcessThread) then
begin
Exit;
end;
Result := True;
finally
if not Result then
begin
RemoteCreateProcessUnloadData;
end;
end;
end;
begin
//inizializzo a zero le variabili locali
hProcess := 0;
pRemoteCreateProcessData := nil;
pRemoteCreateProcessThread := 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 RemoteCreateProcessInjectData() then
Exit;
if not InjectThread(hProcess,
pRemoteCreateProcessThread,
pRemoteCreateProcessData,
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
RemoteCreateProcessUnloadData;
end;
if hProcess <> 0 then
begin
if not CloseHandle(hProcess) then
begin
ErrStr('CloseHandle');
end;
end;
end;
end;
e di seguito un semplice esempio di utilizzo
procedure TfrmMain.btnCreateClick(Sender: TObject);
var
success: Boolean;
output: Cardinal;
err: Cardinal;
begin
if not RemoteCreateProcess(PidProcesso(edtNomeEXE.Text),
PAnsiChar(edtProcessoFiglioEXE.Text),
'winsta0\default',
output,
err,
True) then
begin
mmoLog.Lines.Add('errore nella procedura');
end
else
begin
if err <> 0 then
mmoLog.Lines.Add('Errore nella creazione del processo figlio; Cod errore: '
+ IntToStr(err))
else
mmoLog.Lines.Add('Creato proceso figlio con il seguente PID: '
+ IntToStr(output));
end;
end;
RemoteCreateProcess
|