|
Nell'articolo Dll
Injection ho analizzato un pò come mappare una dll nello spazio di
memoria di un processo; l'articolo è focalizzato sull'utilizzo dell'api win32
CreateRemoteThread che consente la creazione e l'esecuzione di un thread nel
contesto di un processo remoto (nel caso specifico si tratta di un thread che
che esegue fondamentalmente l'api win32 LoadLibrary per caricare la dll). Per
creare un processo esiste la famosa api win32 CreateProcess (e le sue varianti
CreateProcessAsUser, CreateProcessWithLogon, CreateProcessWithtoken) per cui
l'accoppiata CreateProcess e CreateRemoteThread potrebbe già risolvere tutto; ed
in effetti risolve a grandi linee la questione. Il problema però è il seguente:
spesso si vuole che la dll sia mappata il prima possibile nello spazio di
memoria del processo remoto; questo perchè magari la dll implementa api hooking
su un determinato set di api win32 e si vuole iniziare a tracciare la chiamata
di tali api il prima possibile: se eseguiamo semplicemente CreateProcess e poi
CreateRemoteThread , nulla ci garantisce che all'atto della chiamata dell'entrypoint
della dll non sia già stato chiamato l'entrypoint dell'exe lanciato dalla
CreateProcess; ciò significherebbe ovviamente che ci siamo potenzialmente persi
alcune delle chiamate (per non parlare poi del codice eseguito nell'entrypoint
delle dll importate). Allora si è soliti chiamare la CreateProcess con la Flag
CREATE_SUSPENDED (valore 0x00000004) nell'ambito del 6° parametro (dwCreationFlags).
In questo modo si crea un processo sospeso: in questo stato nel suo spazio di
memoria saranno mappati l'exe e le dll kernel32.dll e ntdll.dll. E qui si arriva
al problema: usare CreateRemoteThread su un processo in questo stato comporta
un'alta probabilità di crash del processo all'atto del resume tramite l'api
win32 ResumeThread. Quindi bisogna ricorrere ad altre tecniche: ve ne sono
diverse e quella che esporrò nel seguito è probabilmente la più classica; si
basa essenzialmente sulle api win32 GetThreadContext e SetThreadContext. Ho
utilizzato direttamente l'ottima implementazione ad oggetti di Max Artemev
nell'ambito del suo applicativo FreeCap. Ho estrapolato la unit dal contesto
dell'applicativo originale eliminando del codice non necessario. Il risultato
finale è una funzione che ho nominato CreateProcessAndMapDllA che è equivalente
alla CreateprocessA con l'aggiunta di un ulteriore parametro alla fine che
specifica appunto il nome della dll da mappare.
unit uCreateWith;
interface
uses
Windows;
function CreateProcessAndMapDllA(
lpApplicationName: PAnsiChar;
lpCommandLine: PAnsiChar;
lpProcessAttributes: PSecurityAttributes;
lpThreadAttributes: PSecurityAttributes;
bInheritHandles: Boolean;
dwCreationFlags: Cardinal;
lpEnvironment: Pointer;
lpCurrentDirectory: PAnsiChar;
const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation;
lpDllName: PAnsiChar
): Boolean; stdcall;
implementation
uses
uInjector;
function CreateProcessAndMapDllA(
lpApplicationName: PAnsiChar;
lpCommandLine: PAnsiChar;
lpProcessAttributes: PSecurityAttributes;
lpThreadAttributes: PSecurityAttributes;
bInheritHandles: Boolean;
dwCreationFlags: Cardinal;
lpEnvironment: Pointer;
lpCurrentDirectory: PAnsiChar;
const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation;
lpDllName: PAnsiChar
): Boolean; stdcall;
var
Injector: TSuspendInjector;
bSuspended: Boolean;
begin
bSuspended := ((dwCreationFlags and CREATE_SUSPENDED) <> 0);
if not bSuspended then
dwCreationFlags := dwCreationFlags or CREATE_SUSPENDED;
result := CreateProcessA(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
if result then
begin
Injector := TSuspendInjector.Create;
Injector.ProcessInformation := lpProcessInformation;
Injector.SetDLLToInject(lpDllName);
Injector.ShouldRunAfter := not bSuspended;
Injector.Run();
end;
end;
end.
Di seguito i sorgenti di un semplice esempio CreateProcessAndMapDll.7z Altri modi per eseguire dll injection su un processo da creare sono i seguenti 1) Creare il processo in forma Suspended ed eseguire un runtime patching della tabella IAT del .exe aggiungendo nell'elenco delle dll da importare anche la nostra dll: al Resume il loader di windows si troverà con la IAT del .exe modificata ed eseguirà il suo consueto lavoro di caricamento delle dll ivi incluse coinvolgendo quindi anche la nostra dll. Questa tecnica viene usata dalla Detours Library 2) Utilizzare il Thread Local Storage (TLS): questa tecnica viene discussa ad esempio all'indirizzo http://blog.dkbza.org/2007/03/pe-trick-thread-local-storage.html 3) Eseguire l'overwriting dell'entrypoint del .exe inserendo codice che carica la dll ed al termine esegue il codice originale. Questa tecnica viene usata dalla MadCodeHook di Madshi.
| |
| |
|