#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