#INCLUDE "NFO.h"
#INCLUDE "DISCLAIMER.h"
USING NAMESPACE REVERSE_ENGINEERING

char szTajuk[]		= "TooLZ Of The Trade [Part 1]"
char szPenulis[]	= "Ancient One"
char szWeb[]		= "http://www26.brinskter.com/paipx"
char szMod[]		= "+n +g +c"


VOID MAIN () {

Tak kira siapa pun korang, korang perlukan tools yang betul untuk melakukan kerja2 korang. Sebagai pengaturcara komputer, sudah tentu korang perlukan sebijik komputer yang sesuai dengan keperluan korang dan sudah tentu korang jugak memerlukan pakej pengkompil untuk membangunkan perisian yang korang tulis. Jadik tutorial ini secara ringkasnya akan menerangkan beberapa tools yang korang akan gunakan dalam karier korang sebagai software reverse engineer ataupun bagi yang lebih suka memanggilnya sebagai "cracker". Untuk bahagian pertama ini, aku cuma akan membincangkan mengenai tools kita yang utama iaitu "DEBUGGER". Jika korang merupakan programmer, then you probably already knows about this beast. Actually, sebagai programmer, korang mesti tau apa menatangnya ni. Kalau korang tak tau, then simply korang bukannya seorang programmers. Well.. kalau korang dah tau, then skip section di bawah ni.

Debugger? apa tu???
Dalam mengaturcara sebuah perisian, kita akan melalui apa yang dipanggil software development cycle di mana di dalam kitaran ini kita akan mengkod, mencuba, membaiki, mendokumenkan dan sebagainya perisian tersebut. Semakin kompleks aturcara yang kita buat, maka semakin banyaklah kesilapan yang akan kita buat. Kesilapan ini dipanggil "BUG(S)" atau dalam BMnya pepijat. Terdapat pelbagai jenis bugs yang akan kita hasilkan samada secara sengaja ataupun tidak. Contoh bugs yang paling mudah ialah operasi matematik divide by zero. Kemudian jika kita memanipulasikan array, kadangkala (atau selalunya) kita akan mengakses elemen array di luar array tersebut yang sudah tentu akan memberi kesan pada program execution kita yang selanjutnya. Ada di antara bugs ini kita tidak akan dapat detect semasa kompil. Bugs seperti ini amat berbahaya kerana kita tidak sedar mengenai bugs tersebut selepas program tersebut dipakejkan dan dijual kepada pengguna. Thats why dalam perisian kita selalu dengar mengenai versi BETA (dan ALPHA, GAMMA dan sebagainya) yang menandakan program versi tersebut sedang berada dalam keadaan "TESTING" dan kemungkinan besar terdapatnya BUGS adalah tinggi. Jika dalam tempoh BETA version ini tidak dilaporkan mengenai bugs walaupun satu, maka perkataan BETA tersebut akan dibuang dan dijual semula. Tapi biasanya versi BETA memang mempunyai bugs kerana developernya mungkin menggunakan untested code atau algorithm baru yang belum dibuktikan berkesan dalam certain part of their programs. So.. apa dia debugger? Secara ringkasnya, debugger adalah perisian pembantu kepada para pengaturcara dalam mencari bugs di dalam perisian mereka. Debugger membenarkan pengaturcara mengawal program mereka dan melaksanakan kod satu demi satu. Semasa debugging, perisian akan dilaksanakan di bawah kawalan debugger. Dalam tempoh ini, pengaturcara boleh melihat bagaimana setiap arahan dalam kod sumber mereka mempengaruhi variables dalam program mereka. Program's flow juga boleh diubah dan kandungan variables/memory/registers juga boleh dilihat dan dimanipulasikan. Dengan debugger, pengaturcara berkuasa penuh ke atas program yang sedang mereka debug. Akan tetapi debugger tidak boleh mencari bugs untuk korang. Koranglah yang akan mencari bugs tersebut... dengan bantuan debugger. Ya.. dengan bantuan debugger, kerja2 mencari tersebut akan menjadi lebih mudah.

Apa gunanya kepada cracker?
Biasanya debugger akan disertakan sekali dengan pakej pengkompil dan diintergratekan ke dalam IDE pengkompil tersebut. Kebanyakannya debugger juga boleh digunakan berasingan dan debugger yang berguna kepada cracker ialah debugger yang boleh memaparkan assembly code program tersebut. Seperti yang kita tau, assembly code adalah 1-1 dengan machine code, jadi debugger boleh tunjukkan kod assembly dengan mudah. Dengan debugger, cracker boleh melihat kod assembly sesuatu program tersebut (ya... walaupun tanpa kod asalnya). Kod ini memang kod program tersebut, cuma ia diwakili dengan assembly op-codes. Sebagai contoh, satu line dalam C :

	char s;
	int x;

	s = 'd';
	x = 100;

akan diwakili dengan assembly opcode seperti berikut :

	mov	byte ptr [406700], 100
	mov	[406702], 100
	..
	..

seperti yang kita lihat di atas, variables s dan x hanyalah lokasi memory dlaam komputer kita. Dengan char dan int sebagai penentu storage capacity (samada byte, word, dword, qword dan sebagainya). Lokasi memori ini mungkin berlainan di dalam pc korang. So.. biasanya dalam debugger, cracker akan menemui lokasi di mana korang, sebagai pengatucara membandingkan no. siri pendaftaran untuk perisian korang dengan no. siri yang dimasukkan oleh pengguna. Di sini, cracker tersebut boleh 'menampal' (patch) op-code pada lokasi tersebut dengan op-code yang lain dan sekaligus 'memesongkan' flow program korang daripada sepatutnya. Cuba lihat kod assembly di bawah :

	push	DWORD PTR [406702]
	CALL	432100
	cmp	eax, 0
	jz	471000
	..
	..

kod di atas adalah contoh. CALL 432100 akan mengesahkan samada no. siri yang dimasukkan pengguna adalah betul, dengan nilai no. siri (DWORD value) sebagai argument. Dalam C kita akan lihat seperti di bawah :

	if (ValidateSerial(no_siri)) {
	//serial number correct.. continue here
	}

	else {
	//serial number incorrect.. continue here
	}

dan prototaip untuk ValidateSerial adalah
bool ValidateSerial(unsigned int);

Kod di atas akan menentukan samada serial tersebut adalah sah dengan men'check' return value (return value daripada function sentiasa diletakkan pada register eax). Assume that TRUE adalah nilai yang bukan 0, dan FALSE adalah nilai 0, jz (jump if zero) di atas akan dilaksanakan jika no. siri yang diberikan adalah salah. Cracker yang menemui lokasi ini cuma perlu patch op-code jz 471000 di atas supaya ia tidak dilaksanakan..Well.. ni cuma salah satu daripada kelebihan debugger. As you developin ur skills in reverse engineering, korang akan dapati debugger korang adalah asset paling berharga :).

Ciri2 debugger yang perlu ada adalah seperti executing op-code by op-code, tracing into call, setting breakpoint on execution, memory access..etc..etc. Breakpoint adalah ciri yang wajib ada dalam setiap debugger kerana tanpanya, korang terpaksa mendebug program korang sentiasa daripada permulaan program. Dengan breakpoint korang boleh berhenti pada lokasi tertentu dan membiarkan kod lain dilaksanakan. Sebagai contoh.. kod di atas tadi :

	..
	..
	push	DWORD PTR [406702]
	CALL	432100
	cmp	eax, 0
	jz	471000
	..
	..

assume that sebelum push DWORD PTR [406702] tersebut, terdapat berjuta-juta lagi opcodes. korang boleh step over every instructions selama berjam-jam atau korang boleh setkan breakpoint pada arahan push di atas dan biarkan op-code sebelumnya dilaksanakan tanpa korang perlu trace over setiap op-codes. Apabila EIP point kepada lokasi push di atas, program akan terhenti dan debugger korang mengambilalih di mana korang boleh continue execution atau trace setiap op-codes. Terdapat pelbagai jenis debugger yang telah diprogram dan di antaranya ada yang sesuai hanya untuk language tertentu sahaja. When using debugger yang boleh disassemble cpu instructions, korang perlu tahu assembly language dan organisasi platform di mana korang menjalankan aktiviti debugging tersebut. Biasanya debugger ini mempunyai beberapa tetingkap iaitu :

1. registers window :- pada tetingkap ini korang akan dapat melihat
   kandungan setiap register in real time. korang juga boleh melihat
   flags register di sini dan biasanya debugger membenarkan korang
   mengubah setiap kandungan register.
2. memory dump window :- di sini korang boleh melihat kandungan
   memory pada lokasi yang korang mahu. Ia biasanya dipaparkan dalam
   nombor hex dengan saiz byte dan juga dipaparkan ASCII equivalent
   untuk memory dump tersebut. Dan hex 00 biasanya akan diwakili
   dengan '.' (dot).
3. code window :- di sini korang akan dapat melihat instructions
   dalam asm, dan biasanya disertakan dengan lokasinya dan juga
   machine code untuk instruction tersebut dalam hex.
4. command window :- di sini korang boleh memberi arahan kepada
   debugger korang.
5. lain2 window :- bergantung pada kelebihan debugger yang korang
   gunakan. Akan tetapi biasanya no. 1 - no. 4 di atas sepatutnya
   ada pada setiap debugger.
Dua jenis debugger ialah system-level debugger dan application-level debugger. System-level debugger juga biasa dipanggil sebagai kernel-mode debugger manakala application-level debugger pula sebagai user-mode debugger. Application-level debugger boleh digunakan untuk debug apa sahaja program yang dilaksanakan dalam user-mode seperti any GUI applications, NT services dan lain2. Secara amnya, Application-level debugger (ALD) mempunyai GUI since ia adalah seperti program lain dalam user mode yang boleh menggunakan API yang disediakan untuk Windows programmers. ALD menggunakan debugging API yang disediakan oleh Microsoft. Dengan debug API, korang boleh create process as debug process dan start debugging, atau boleh juga attach kepada currently running programs. Tapi sebaik sahaja program berada di bawah kawalan debugger, maka debugger tidak boleh detach itself from that process. Jadi apabila debugger dihentikan, maka debuggee tersebut juga akan dihentikan. Terdapat banyak contoh ALD, antaranya ialah Visual C++ debugger (terdapat dalam pakej Visual Studio), Borland Delphi dan C++ Builder debugger, OllyDbg, TRW dan sebagainya. Aku taknak la bagitau kat mana korang boleh dapat mana2 debugger ni. Mudah sangat dengan adanya Internet.. dan dengan keadaan industri pirate yang tak pernah pudar di Malaysia ni, korang boleh pergi kat mana2 kedai CD dan ask the tauke pasal benda ni. Aku pasti 99.99% diaorang akan dapat carikan untuk korang. Satu lagi jenis debugger ialah system-level debugger (SLD). Berbanding dengan ALD, SLD mengawal keseluruhan operating system korang. Pada bila2 masa kita invoke SLD, OS akan terhenti dan cuma kod SLD sahaja yang dilaksanakan manakala kod2 OS kesemuanya akan terhenti. Dengan penerangan ringkas ini, korang pasti merasakan yang SLD adalah yang terbaik untuk reversing purpose. Ini bergantung pada keadaan. Akan tetapi, biasanya ALD sudah cukup untuk tujuan ini. SLD digunakan apabila sesetengah program menggunakan feature pada OS architecture dan kadangkala they didn't play by the rules. SLD juga digunakan untuk mendalami carakerja OS itu sendiri. Tidak banyak SLD yang boleh digunakan. Sepanjang pengetahuan aku, satu2nya SLD yang komersial dan boleh digunakan dalam single machine (all SLD requires 2 pcs connected to each other) ialah SoftIce daripada Compuware Corp. Dan tidak dinafikan lagi.. this is the best SLD for reversers.


SoftIce : From A Cracker's POV.
Pada bahagian ini aku akan tuliskan sedikit sebanyak mengenai SoftIce. Pengetahuan menggunakan SoftIce adalah kritikal untuk Windows reversers. Korang wajib mengetahuinya. Actually SoftIce sudah wujud sejak zaman MS-DOS lagi dan sehingga sekarang ia tetap menjadi tools utama untuk pengaturcara (dan juga crackers). SoftIce sekarang adalah sebahagian daripada DriverStudio (pakej untuk device driver writers). Saya tak tau mengenai DevPartner.. aku rasa kat dalam tu ader gak. Lama tak tengok web Compuware. Korang boleh cari SoftIce versi standalone (bukan dipakejkan sekali dengan Driver Studio) dengan mudah dari internet. Sepanjang pengetahuan aku, latest version of Driver Studio ialah 2.7 dan aku rasa dah fully compatible with XP. Jika korang expert menggunakan search engine... korang boleh dapatkannya dari internet juga.. sudah tentu pirate ;). Jangan tanya saya kat mana nak cari. Aku tak tau. Kalau korang gunakan Win9x, maka jangan lupa untuk dapatkan IceDump, great extension for SoftIce.. they really are great programmers and crackers.

Ramai orang beranggapan SoftIce adalah tool for crackers. Dengan itu ramai pengaturcara yang menyertakan kod 'anti-softice' dalam program mereka kerana beranggapan yang SoftIce dalam machine seseorang bermakna dia adalah cracker. Tu contoh pemikiran yang sempit :). Saya juga pernah menggunakan satu perisian yang membantu dalam software developments.. tetapi ia juga dibenamkan dengan kod anti-softice. Memang bodoh! Tapi, yang sebetulnya, SoftIce adalah tool untuk crackers :). Ia lebih popular di kalangan crackers. Ia juga tool yang gerenti ada pada mana2 ftp/http site yang menyediakan tool for crackers. Jadi dapatkan satu dan pasang pada sistem korang sekarang :). Saya taknak sentuh mengenai pemasangan SoftIce sebab ianya straight-forward, sama seperti pemasangan perisian lain. Cuma dalam sistem 2K/XP korang mempunyai pilihan untuk memulakan SoftIce samada secara manual, automatik, boot dan sebagainya. Figure that out yourself. Pakej SoftIce disertakan dengan dokumentasi yang agak bagus dan korang boleh membaca mengenai SoftIce daripadanya. Jika korang menghadapi masalah dalam pemasangan SoftIce atau benar2 tak tahu bagaimana hendak memasangnya, then ask me for another tuto :).

Assume korang dah install SoftIce ke dalam sistem korang dengan betul dan SoftIce telah disetkan untuk dimulakan semasa boot. Pada masa ini SoftIce akan sit idle between your OS and the CPU. Korang boleh invoke SoftIce dengan default hotkey <CTRL><D>. Hotkey ini boleh ditukar dengan arahan ALTKEY (to make it permanent, edit winice.dat). Beberapa arahan/default hotkey yang penting dalam SoftIce ialah :

"x" return to program (exit SoftIce) (F5, <CTRL><D>)
"p" step skipping calls, int, etc (F10)
"t" single step one instruction (F8)
"wr" toggle register window
"wd" toggle data window
"wc" toggle code window
"bpx <address>" Set breakpoint on execution at <address>
"bl" list current breakpoint
"bh" breakpoint history
"bc <list> | *" clear breakpoint(s)
"bd list | *" disable breakpoint(s)
"bpm[size] <address> r|w" Set breakpoint on memory access
"d <address>" display memory contents at <address>/td>
"e <address>" edit memory at <address>
"code on|off" paparkan instructions byte dalam code window


dan banyak lagi arahan2 yang boleh korang lihat dalam documentation. Jadi untuk membiasakan korang menggunakan SoftIce, maka saya akan menerangkan dengan contoh apa yang kita boleh buat dengan SoftIce :).

Latihan
Target : Zephyr crackme#1.
Tools : SoftIce + Win32 API Reference.

Pastikan korang sudah load export table untuk frequently used system dll such as kernel32, user32, etc. Dengan export table ini korang boleh setkan breakpoint seperti bpx GetWindowTextA yang lebih mudah difahami berbanding bpx 77D5C13A :). Laksanakan crackme#1 dan ia akan paparkan message box. Kemungkinan besar, message box ini dipaparkan dengan function MessageBoxA (kita tak sure sangat about that, sebab terdapat lagi fuctions lain yang boleh digunakan untuk tujuan ini). Jadi kita try setting breakpoint at first byte of MessageBoxA function. Dalam SoftIce, arahan yang diberikan ialah "bpx MessageBoxA" . Laksanakan crackme#1 sekali lagi dan SoftIce akan berhenti pada permulaan function MessageBoxA somewhere in user32.dll. korang boleh return ke kod korang dengan hotkey F11. Pada masa ini, korang akan berada pada lokasi seperti berikut :

00401032   .  56			PUSH	ESI
00401033   .  57			PUSH	EDI
00401034   .  6A 00			PUSH	0                                ; /Style = MB_OK|MB_APPLMODAL
00401036   .  68 5C514000		PUSH	crackme1.0040515C                ; |Title = "Warning!!"
0040103B   .  68 24514000		PUSH	crackme1.00405124                ; |Text = "Aku adalah 'nag screen' dan menyusahkan..plz remove me"
00401040   .  55			PUSH	EBP                              ; |hOwner
00401041   .  FF15 C0404000		CALL	[<&USER32.MessageBoxA>]          ; \MessageBoxA
00401047   .  FF15 C4404000		CALL	[<&USER32.CreateMenu>]           ; [CreateMenu
0040104D   .  8BF8			MOV	EDI, EAX
0040104F   .  FF15 C8404000 	CALL	[<&USER32.CreatePopupMenu>]      ; [CreatePopupMenu
00401055   .  8B35 CC404000 	MOV	ESI, [<&USER32.AppendMenuA>]     ;  USER32.AppendMenuA
0040105B   .  68 1C514000   		PUSH	crackme1.0040511C                ; /pItem = "E&xit"
00401060   .  8BD8          		MOV	EBX, EAX                         ; |
00401062   .  68 29230000   		PUSH	2329                             ; |ItemID = 2329 (9001.)
00401067   .  6A 00         		PUSH	0                                ; |Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
00401069   .  53            		PUSH	EBX                              ; |hMenu
0040106A   .  FFD6          		CALL	ESI                              ; \AppendMenuA
0040106C   .  68 14514000   		PUSH	crackme1.00405114                ; /pItem = "&File"
00401071   .  53            		PUSH	EBX                              ; |ItemID
00401072   .  6A 10			PUSH	10                            ; |Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING|MF_POPUP
00401074   .  57            		PUSH	EDI                              ; |hMenu
00401075   .  FFD6          		CALL	ESI                              ; \AppendMenuA
00401077   .  FF15 C8404000 	CALL	[<&USER32.CreatePopupMenu>]      ; [CreatePopupMenu
0040107D   .  68 0C514000   		PUSH	crackme1.0040510C                ; /pItem = "&Secret"
00401082   .  8BD8          		MOV	EBX, EAX                         ; |
00401084   .  68 2B230000   		PUSH	232B                             ; |ItemID = 232B (9003.)
00401089   .  6A 01         		PUSH	1                                ; |Flags = MF_BYCOMMAND|MF_GRAYED|MF_STRING
0040108B   .  53            		PUSH	EBX                              ; |hMenu
0040108C   .  FFD6          		CALL	ESI                              ; \AppendMenuA
0040108E   .  68 04514000   		PUSH	crackme1.00405104                ; /pItem = "&About"
00401093   .  68 2A230000   		PUSH	232A                             ; |ItemID = 232A (9002.)
00401098   .  6A 00         		PUSH	0                                ; |Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
0040109A   .  53            		PUSH	EBX                              ; |hMenu
0040109B   .  FFD6          		CALL	ESI                              ; \AppendMenuA
0040109D   .  68 FC504000   		PUSH	crackme1.004050FC                ; /pItem = "&Help"
004010A2   .  53            		PUSH	EBX                              ; |ItemID
004010A3   .  6A 10         		PUSH	10                               ; |Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING|MF_POPUP
004010A5   .  57            		PUSH	EDI                              ; |hMenu
004010A6   .  FFD6          		CALL	ESI                              ; \AppendMenuA
004010A8   .  57            		PUSH	EDI                              ; /hMenu
004010A9   .  55            		PUSH	EBP                              ; |hWnd
004010AA   .  FF15 D0404000 	CALL	[<&USER32.SetMenu>]              ; \SetMenu

Line yang saya tandakan adalah EIP di mana korang berada selepas return daripada user32.dll. Kita tau bahawa MessageBoxA API memerlukan 4 arguments di mana prototaipnya dalam assembly (MASM syntax) :

	MessageBoxA PROTO hWND:DWORD,lpText:DWORD,lpCaption:DWORD,uType:DWORD
	
Akan tetapi, dalam assembly, since almost all WIN32 functions menggunakan STDCALL calling convention, iaitu argument akan dipush dari kanan ke kiri dan function yang akan clearkan stack. Jadi, kita akan dapat lihat seperti dalam kod di atas :

	push	uType
	push	OFFSET lpCation
	push	OFFSET lpText
	push	hWND
	call	MessageBoxA
	
kita hendak menghilangkan message box. Jadi apa yang perlu kita buat adalah mengubah beberapa bytes supaya arahan ini tidak akan dilaksanakan sama sekali. Kali ini setkan breakpoint pada 401034 dan restart crackme#1. SoftIce akan pop-up dan EIP akan point ke lokasi ini. Korang boleh mengubah EIP dan sekaligus mengalihkan code flow ke tempat lain. Sebagai contoh, ubah register EIP kepada 401047 (arahan r eip 401047) dan teruskan perlaksanaan kod program tersebut. Korang akan dapati message box tersebut tidak dipaparkan. Ada pelbagai cara untuk patch area ini. Mungkin korang boleh NOP out semua kod untuk display MessageBox di atas. Jika korang lihat instruction push 0, ia memerlukan 2 bytes (6A 00). Di sini kita boleh mengubahnya kepada jmp near iaitu EB XX, di mana XX adalah sesaran positif atau negatif FF/2 (approximately). Since kita cuma perlu jump ke 401047, maka nilai XX ialah

401047-401036 = 11

So we can patch bytes pada 401034 dari 6A00 ke EB11 untuk mengelak daripada melaksanakan kod pemaparan message box tersebut. Apa yang perlu korang ingat ialah instructions baru yang korang hendak gantikan pada instruction lama perlulah mempunyai sama saiz. Jika korang hendak patch push 0 di atas dengan NOP, maka korang memerlukan 2 NOP since arahan NOP bersaiz 1 byte sahaja (but don't patch it with NOP in this case :).

Masalah pertama telahpun selesai. Kemudian kita perlu enable semula menu Secret yang telah disable. korang boleh step over arahan di atas sehinggalah pada lokasi 40107D. Function AppendMenuA memerlukan 4 arguments :

	AppendMenuA PROTO hMenu:DWORD,uFlags:DWORD,uIDNewItem:DWORD,lpNewItem:DWORD
	
Jika korang perhatikan pada kod di atas, menu Secret di'append'kan pada menu dengan flag MF_GRAYED jadi it can't be selected. Jadi apa yang perlu kita buat untuk enable kembali menu ini ialah patch lokasi 401089 dengan push 0.

Seperti yang korang lihat, dengan debugger, kita boleh mengubah program's flow dan juga data semasa run time. Apabila kita melakukan perubahan, ia cuma applied dalam memory dan bukan ke dalam file program tersebut dalam disk. Jadi sebaik sahaja kita exit daripada program, perubahan tersebut akan dilupakan di lain masa program tersebut dilaksanakan. Oleh itu, patch yang korang lakukan di dalam SoftIce dalam contoh di atas tidak kekal dan apa yang korang perlu buat adalah mencari bytes tersebut di dalam fail program tersebut dengan binary editor dan mengubahnya di sana dan save the changes you've made. korang boleh tengok dengan menggunakan debugger, we've complete control on the programs being debug. Itulah sebabnya mengapa kita perlukan debugger as our main tool in reverse engineering.

}

Kembali ke Isi Kandungan