Tutorial 14: I Processi
From UIC
Tutorial 14: I Processi
Contents |
| Tutorial 14: I Processi | |
|---|---|
| Author: | Iczelion |
| Email: | Traduttore: -NeuRaL_NoiSE |
| Website: | Mirror |
| Date: | 07/01/2009 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Formattazione Wiki: Antelox |
Introduzione
Impareremo cos'è un processo, come crearlo e come terminarlo.
Tools
Preliminari
Cos'e' un processo? Cito questa definizione dalla Win32 API reference:
"Un processo e' un'applicazione in esecuzione che consiste di un address space virtuale privato, codice, dati, e altre risorse del sistema operativo, come files, pipes, e synchronization objects che sono visibili per il processo."
Come potete capire dalla definizione di cui sopra, un processo "possiede" diversi oggetti: l'address space, i/il modulo/i in esecuzione, e qualsiasi cosa che i moduli in esecuzione aprano o creino. Come minimo, un processo deve essere costituito da un modulo in esecuzione, un address space privato e un thread. Ogni processo deve avere almeno un thread. Cos'e' un thread? Un thread e' in realta' una "coda di esecuzione". Quando Windows crea per la prima volta un processo, crea solo UN thread per processo. Questo thread solitamente comincia ad essere eseguito dalla prima istruzione nel modulo. Se il processo successivamente ha bisogno di piu' threads, esso puo' esplicitamente crearli. Quando Windows riceve un comando per creare un processo, crea il memory address space privato per quel processo e quindi mappa il file eseguibile in tale spazio. Dopo di cio', crea il thread primario per il processo. Sotto Win32, potete anche creare processi per i vostri programmi chiamando la funzione CreateProcess. CreateProcess ha la seguente sintassi:
LPCTSTR lpApplicationName, // puntatore al nome del modulo eseguibile
LPTSTR lpCommandLine, // puntatore alla stringa della riga di comando
LPSECURITY_ATTRIBUTES lpProcessAttributes, // puntatore agli attributi di sicurezza del processo
LPSECURITY_ATTRIBUTES lpThreadAttributes, // puntatore agli attributi di sicurezza del thread
BOOL bInheritHandles, // flag di "eredita' degli handle" (handle inherit flag)
DWORD dwCreationFlags, // flags di creazione
LPVOID lpEnvironment, // puntatore al nuovo blocco di environment (ambiente, NdT)
LPCTSTR lpCurrentDirectory, // puntatore al nome della directory corrente
LPSTARTUPINFO lpStartupInfo, // puntatore a STARTUPINFO
LPPROCESS_INFORMATION lpProcessInformation // puntatore a PROCESS_INFORMATION
);
Non vi preoccupate per il numero dei parametri. Ne possiamo ignorare la maggior parte.
lpApplicationName --> Il nome del file eseguibile (con o senza la path) che volete eseguire. Se questo parametro e' NULL, dovete fornire il nome del file eseguibile nel parametro lpCommandLine.
lpCommandLine --> Gli argomenti della riga di comando del programma che volete eseguire. Notate che se lpApplicationName e' NULL, questo parametro deve contenere anche il nome del file eseguibile. Come questo : "notepad.exe readme.txt"
lpProcessAttributes e lpthreadAttributes --> Specificano gli attributi di sicurezza per i processi e per il thread primario. Se sono NULLs, verranno usati gli attributi di sicurezza predefiniti.
bInheritHandles --> Una flag che specifica se volete che il nuovo processo erediti tutti gli handle aperti dal vostro processo.
dwCreationFlags --> Diverse flags che determinano il comportamento del processo che volete creare; ad esempio, volete che il processo venga creato ma immediatamente sospeso, in modo tale da permettervi di esaminarlo o modificarlo prima che parta? Potete anche specificare la classe di priorita' del/i thread(s) nel nuovo processo. Questa classe di priorita' e' usata per determinare la priorita' di comparsa dei threads all'interno del processo. Normalmente usiamo le flags CREATE_NEW_CONSOLE e NORMAL_PRIORITY_CLASS.
lpEnvironment --> Un puntatore all'environment block che contiene diverse stringhe di environment per il nuovo processo. Se questo parametro e' NULL, il nuovo processo eredita l'environment block dal parent process (processo precedente che gli ha dato inizio, NdT).
lpCurrentDirectory --> Un puntatore alla stringa che specfica il drive e la directory correnti per il child process (il processo nuovo, quello appena creato, NdT). NULL se volete che il child process erediti dal parent process.
lpStartupInfo --> Punta ad una struttura STARTUPINFO che specifica come dovra' apparire la finestra principale del nuovo processo. La struttura STARTUPINFO contiene molti membri che specificano l'apparenza della finestra principale del child process. Se non volete niente di speciale, potete riempire la struttura STARTUPINFO con i valori dal parent process chiamando la funzione GetStartupInfo.
lpProcessInformation --> Punta ad una struttura PROCESS_INFORMATION che riceve informazioni di identificazione circa il nuovo processo. La struttura PROCESS_INFORMATION ha i seguenti membri:
hProcess HANDLE ? ; handle del child process
hThread HANDLE ? ; handle del thread primario del child process
dwProcessId DWORD ? ; ID del child process
dwThreadId DWORD ? ; ID del thread primario del child process
PROCESS_INFORMATION ENDS
L'handle del processo e la ID del processo sono due cose diverse. Una process ID e' un identificatore unico per il processo nel sistema. Un process handle e' un valore restituito da Windows per essere utilizzato con altre funzioni API legate ai processi. Un process handle non puo' essere usato per identificare un processo poiche' non e' unico.
Dopo la chiamata a CreateProcess, un nuovo processo viene creato e la chiamata a CreateProcess ritorna immediatamente. Potete controllare se il nuovo processo e' ancora attivo chiamando la funzione GetExitCodeProcess che ha la seguente sintassi:
HANDLE hProcess, // handle del processo
LPDWORD lpExitCode // indirizzo che riceve lo stato di chiusura
);
Se questa chiamata ha successo, lpExitCode contiene il termination status (stato di chiusura, NdT) del processo in questione. Se il valore in lpExitCode e' uguale a STILL_ACTIVE, allora il processo e' ancora in esecuzione.
Potete terminare a piacimento un processo chiamando la funzione TerminateProcess che ha la seguente sintassi:
HANDLE hProcess, // handle del processo
UINT uExitCode // codice di uscita per il processo
);
Potete specificare il codice di uscita desiderato per il processo, qualsiasi valore vogliate. TerminateProcess non e' un modo pulito di terminare un processo poiche' nessuna dll relativa al processo sara' informata che questo e' stato terminato.
Essay
L'esempio che segue creera' un nuovo processo quando l'utente seleziona il menu item "create process". Il programma cercera' di eseguire "msgbox.exe". Se l'utente vuole terminare il nuovo processo, puo' selezionare il menu item "terminate process". Il programma controllera' prima se il nuovo processo e' gia' stato distrutto, e se no, chiamera' la funzione TerminateProcess per distruggerlo.
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
.const
IDM_CREATE_PROCESS equ 1
IDM_TERMINATE equ 2
IDM_EXIT equ 3
.data
ClassName db "Win32ASMProcessClass",0
AppName db "Win32 ASM Process Example",0
MenuName db "FirstMenu",0
processInfo PROCESS_INFORMATION <>
programname db "msgbox.exe",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu HANDLE ?
ExitCode DWORD ? ; contiene il codice di uscita del processo, dalla chiamata
; GetExitCodeProcess.
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,0
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,300,200,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
invoke GetMenu,hwnd
mov hMenu,eax
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL startInfo:STARTUPINFO
mov eax,uMsg
.IF eax==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF eax==WM_INITMENUPOPUP
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.if lParam==0
.if ax==IDM_CREATE_PROCESS
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
.else
invoke DestroyWindow,hWnd
.endif
.endif
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
Analisi
Il programma crea la finestra principale e rileva il menu handle per uso futuro. Quindi aspetta che l'utente selezioni un comando dal menu. Quando l'utente seleziona il menu item "Process" dal menu principale, noi elaboriamo il messaggio WM_INITMENUPOPUP per modificare i menu items dentro il menu di popup prima che venga mostrato.
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
Perche' vogliamo elaborare questo messaggio ? Perche' vogliamo preparare i menu items del menu di popup prima che l'utente li possa vedere. Nel nostro esempio, se il nuovo processo non e' ancora cominciato, vogliamo abilitare il menu item "start process" e disabilitare "terminate process". Facciamo il contrario se il nuovo processo e' gia' attivo. Prima controlliamo se il nuovo processo e' ancora in esecuzione chiamando la funzione GetExitCodeProcess con l'handle del processo che e' stato riempito dalla funzione CreateProcess. Se GetExitCodeProcess restituisce FALSE, significa che il processo non e' partito ancora, e quindi disabilitiamo il menu item "terminate process". Se GetExitCodeProcess restituisce TRUE, sappiamo che un nuovo processo e' stato avviato, ma dobbiamo sapere se e' ancora in esecuzione. Percio' compariamo il valore in ExitCode con il valore STILL_ACTIVE, e se sono uguali, il processo e' ancora in esecuzione: dobbiamo disabilitare pertanto il menu item "start process" poiche' non vogliamo far cominciare piu' processi contemporaneamente.
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
Quando l'utente seleziona il menu item "start process", chiamiamo la funzione GetStartupInfo per riempire la struttura startupinfo che passeremo alla funzione CreateProcess. Dopo di cio' chiamiamo la funzione CreateProcess per avviare il nuovo processo.
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
Quando l'utente seleziona il menu item "terminate process", controlliamo se il nuovo processo e' ancora attivo chiamando la funzione GetExitCodeProcess. Se e' ancora attivo, chiamiamo la funzione TerminateProcess per "ucciderlo".
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.