Static code injection

From Merlin

(Difference between revisions)
Line 8: Line 8:
O mică aplicaţie inofensivă, clasică, ce nu ne deranjează cu nimic:
O mică aplicaţie inofensivă, clasică, ce nu ne deranjează cu nimic:
-
 
+
<pre>
-[BEGIN CODE 0x01]----------------------------------------------------------------
-[BEGIN CODE 0x01]----------------------------------------------------------------
01 .386                                                                           
01 .386                                                                           
Line 90: Line 90:
79 end start                                                                     
79 end start                                                                     
-[ END CODE ]---------------------------------------------------------------------
-[ END CODE ]---------------------------------------------------------------------
-
 
+
</pre>
Acum vom insera lucrurile pe care vom dori să le ştergem apoi direct din fişierul binar:
Acum vom insera lucrurile pe care vom dori să le ştergem apoi direct din fişierul binar:

Revision as of 15:39, 14 January 2007

În acest articol voi încerca să descriu cât mai pe înţelesul tuturor tehnica numită injectarea codului binar în mod static - tehnică aplicată în software patching.

În primul rând vom crea o aplicaţie al cărei fişier binar urmează apoi să îl modificăm. Pentru aceasta voi folosi masm32 şi ollydbg. Ca fapt divers folosesc WinAsm ca editor.

Lectură plăcută!

O mică aplicaţie inofensivă, clasică, ce nu ne deranjează cu nimic:

-[BEGIN CODE 0x01]----------------------------------------------------------------
01	.386                                                                          
02	.model flat,stdcall                                                           
03	option casemap:none                                                           
04	                                                                              
05	include windows.inc                                                           
06	include kernel32.inc                                                          
07	includelib kernel32.lib                                                       
08	include user32.inc                                                            
09	includelib user32.lib                                                         
10	                                                                              
11	WinMain proto :DWORD,:DWORD,:DWORD,:DWORD                                     
12	                                                                              
13	.DATA                                                                         
14		ClassName		db "an annoying class",NULL                               
15		AppName			db "window title",NULL                                    
16	.DATA?                                                                        
17		hInstance		HINSTANCE ?                                               
18		CommandLine	LPSTR ?                                                       
19	.CODE                                                                         
20	start:                                                                        
21	invoke GetModuleHandle,NULL                                                   
22	mov hInstance,eax                                                             
23	invoke GetCommandLine                                                         
24	mov CommandLine,eax                                                           
25	; procedura main a programelor windows                                        
26	invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT                      
27	invoke ExitProcess,eax                                                        
28	; --------------------------------------------------------------------------- 
29	WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,cmdLine:LPSTR,CmdShow:DWORD  
30		LOCAL wc:WNDCLASSEX                                                         
31		LOCAL msg:MSG                                                               
32		LOCAL hwnd:HWND                                                             
33		                                                                            
34		mov wc.cbSize, SIZEOF WNDCLASSEX                                            
35		mov wc.style, CS_HREDRAW OR CS_VREDRAW                                      
36		;functia ce proceseaza mesajele GUI, apelata in bucla while de mai jos      
37		mov wc.lpfnWndProc, OFFSET WndProc                                          
38		mov wc.cbWndExtra,  NULL                                                    
39		mov wc.cbClsExtra,  NULL                                                    
40		push hInstance                                                              
41		pop wc.hInstance                                                            
42		mov wc.hbrBackground,COLOR_APPWORKSPACE + 1                                 
43		mov wc.lpszMenuName,NULL                                                    
44		mov wc.lpszClassName,OFFSET ClassName                                       
45		invoke LoadIcon,NULL,IDI_WINLOGO                                            
46		mov wc.hIcon,eax                                                            
47		mov wc.hIconSm,eax                                                          
48		invoke LoadCursor,NULL,IDC_ARROW                                            
49		mov wc.hCursor,eax                                                          
50		invoke RegisterClassEx,addr wc                                              
51		invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,\\
52					CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,\\  
53					NULL,hInst,NULL                                                 
54		mov hwnd,eax                                                                
55		invoke ShowWindow,hwnd,CmdShow                                              
56		invoke UpdateWindow,hwnd                                                    
57		.WHILE TRUE                                                                 
58			invoke GetMessage,ADDR msg,NULL,0,0                                     
59			.break .if(!eax)                                                        
60			invoke TranslateMessage,ADDR msg                                        
61			; apeleaza WndProc                                                        
62			invoke DispatchMessage,ADDR msg                                         
63		.ENDW                                                                       
64		mov eax,msg.wParam                                                          
65		ret                                                                         
66	WinMain endp                                                                  
67	; --------------------------------------------------------------------------- 
68	WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM                  
69		.IF uMsg == WM_DESTROY                                                    
70			invoke PostQuitMessage, NULL                                          
71		.ELSE                                                                     
72			invoke DefWindowProc,hWnd,uMsg,wParam,lParam                          
73			ret                                                                   
74		.ENDIF                                                                    
75		xor eax,eax                                                               
76		ret                                                                       
77	WndProc endp                                                                  
78	; --------------------------------------------------------------------------- 
79	end start                                                                     
-[ END CODE ]---------------------------------------------------------------------

Acum vom insera lucrurile pe care vom dori să le ştergem apoi direct din fişierul binar:

După linia 70: -[BEGIN CODE 0x02]---------------------------------------------------------------- .ELSEIF uMsg == WM_LBUTTONUP invoke MessageBox,hWnd,addr ClassName,addr AppName,MB_OK -[ END CODE ]--------------------------------------------------------------------- Acest apel la MessageBox va deschide un nou box enervant la fiecare eliberare a butonului stâng al mouse-ului. După linia 56: -[BEGIN CODE 0x03]---------------------------------------------------------------- invoke MessageBox,hwnd,addr ClassName,addr AppName,MB_OK -[ END CODE ]--------------------------------------------------------------------- Imediat după ce arătăm fereastra pe desktop vrem să mai apară un MessageBox enervant pe care să avem apoi plăcerea de a-l şterge direct din fişierul binar

După linia 24: -[BEGIN CODE 0x04]---------------------------------------------------------------- invoke MessageBox,NULL,addr ClassName,addr AppName,MB_OK -[ END CODE ]--------------------------------------------------------------------- Din nou, acelaşi mesaj enervant înainte de toate :-)

Acum să ne uităm mai atent la codul nostru. Linia -[BEGIN CODE 0x05]---------------------------------------------------------------- 02 .model flat,stdcall -[ END CODE ]--------------------------------------------------------------------- ne spune că memoria este tratată linear (flat) şi că parametrii funcţiilor apelate sunt puse pe stack în ordine inversă (stdcall). Aşadar un apel de genul -[BEGIN CODE 0x06]---------------------------------------------------------------- invoke MessageBox,hwnd,addr ClassName,addr AppName,MB_OK -[ END CODE ]--------------------------------------------------------------------- rezultă în realitate în codul: -[BEGIN CODE 0x07]---------------------------------------------------------------- push MB_OK push addr AppName push addr ClassName push hwnd call MessageBox -[ END CODE ]--------------------------------------------------------------------- aşa cum vom vedea în timp ce vom face debugging JIT (Just In Time) cu ollydbg. Compilează şi testează programul să te asiguri că funcţionează mai întâi. Poţi adăuga instrucţiunea -[BEGIN CODE 0x08]---------------------------------------------------------------- int 3 -[ END CODE ]--------------------------------------------------------------------- înaintea apelurilor MessageBox inserate anterior pentru a instrucţiona ollydbg (cu setările standard) să facă o mică pauză.Dacă vrei să testezi programul direct fără ollydbg va trebui să comentezi liniile cu interrupt 3 si să recompilezi. Acum deschide programul cu ollydbg şi apasă F9 pentru a-l rula. Se va opri automat după instrucţiunea "int 3" lucru care ne va da ocazia să analizăm fişierul binar rezultat în urma compilării. Codul binar din ollydbg fără interrupt 3: -[BEGIN CODE 0x09]---------------------------------------------------------------- 00401000 >/$ 6A 00 PUSH 0  ; /pModule = NULL 00401002 |. E8 91010000 CALL <JMP.&kernel32.GetModuleHandleA> ; \\GetModuleHandleA 00401007 |. A3 20304000 MOV DWORD PTR DS:[403020],EAX 0040100C |. E8 81010000 CALL <JMP.&kernel32.GetCommandLineA>  ; [GetCommandLineA 00401011 |. A3 24304000 MOV DWORD PTR DS:[403024],EAX 00401016 6A 00 PUSH 0  ; /Style = MB_OK|MB_APPLMODAL 00401018 68 12304000 PUSH demo_app.00403012  ; |Title = "window title" 0040101D 68 00304000 PUSH demo_app.00403000  ; |Text = "an annoying class" 00401022 6A 00 PUSH 0  ; |hOwner = NULL 00401024 E8 99010000 CALL <JMP.&user32.MessageBoxA>  ; \\MessageBoxA 00401029 |. 6A 0A PUSH 0A  ; /Arg4 = 0000000A 0040102B |. FF35 24304000 PUSH DWORD PTR DS:[403024]  ; |Arg3 = 00000000 00401031 |. 6A 00 PUSH 0  ; |Arg2 = 00000000 00401033 |. FF35 20304000 PUSH DWORD PTR DS:[403020]  ; |Arg1 = 00000000 00401039 |. E8 06000000 CALL demo_app.00401044  ; \\demo_app.00401044 0040103E |. 50 PUSH EAX  ; /ExitCode 0040103F \\. E8 48010000 CALL <JMP.&kernel32.ExitProcess>  ; \\ExitProcess -[ END CODE ]--------------------------------------------------------------------- Corespunde codului nostru asm: -[BEGIN CODE 0x0A]---------------------------------------------------------------- 20 start: 21 invoke GetModuleHandle,NULL 22 mov hInstance,eax 23 invoke GetCommandLine 24 mov CommandLine,eax 25 invoke MessageBox,NULL,addr ClassName,addr AppName,MB_OK 26 ; procedura main a programelor windows 27 invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT 28 invoke ExitProcess,eax -[ END CODE ]--------------------------------------------------------------------- Ceea ce ne interesează este să observăm că într-adevăr parametrii sunt puşi pe stack în ordine inversă - vezi offseturile 00401016-00401022, deci MB_OK e o constantă cu valoarea 0, aşa cum poţi vedea şi în masm32/include/windows.inc. Să zicem că vrem să nu apară acest MessageBox. Nu trebuie teoretic decât să nu apelăm MessageBoxA, dar cum? Putem înlocui acest apel cu instrucţiunea NOP (no operation) care spune procesorulului să nu facă nimic. Motivul pentru care nu putem şterge pur şi simplu apelul MessageBoxA din program este că prin asta am decala adresele instrucţiunilor şi datelor ce urmează, facând astfel programul inutil - deşi am putea teoretic repara manual toate referinţele la adrese, acest lucru ar fi o muncă prea costisitoare. Click dreapta pe offseturile 00401016 - 00401024 -> "Binary" -> "Fill with NOPs". Deschide din nou meniul contextual al ferestrei cu segmentul .code şi alege "Copy to executable" -> "All modifications". Se va deschide o fereastra; inchide-o, acceptând să salvezi modificările, apoi lansează în execuţie această nouă versiune modificată a programului. Vei observa că nu mai apare niciun MessageBox înainte de afişarea ferestrei. Următorul apel MessageBox arată cam aşa (ollydbg îţi arată pe coloana din dreapta unde se face un apel MessageBox şi lista de parametri cu un fel de paranteză): -[BEGIN CODE 0x0B]---------------------------------------------------------------- 004010FE 6A 00 PUSH 0  ; /Style = MB_OK|MB_APPLMODAL 00401100 68 12304000 PUSH demo_app.00403012  ; |Title = "window title" 00401105 68 00304000 PUSH demo_app.00403000  ; |Text = "an annoying class" 0040110A FF75 B0 PUSH DWORD PTR SS:[EBP-50]  ; |hOwner 0040110D E8 B0000000 CALL <JMP.&user32.MessageBoxA>  ; \\MessageBoxA -[ END CODE ]--------------------------------------------------------------------- Sper că ştii că hOwner e hwnd - pentru că aşa am compilat noi fişierul asm. Asta înseamnă că MessageBox-ul va avea ca ferestră părinte fereastra noastră principală a aplicaţiei. Nu trebuie decât să punem valoarea NULL în stack în loc de cea de la adresa SS:[EBP-50] -[BEGIN CODE 0x0A]---------------------------------------------------------------- -[ END CODE ]---------------------------------------------------------------------

Personal tools