#INCLUDE "NFO.h"
#INCLUDE "DISCLAIMER.h"
USING NAMESPACE REVERSE_ENGINEERING
char szTajuk[] = "TooLZ Of The Trade [Part 2]"
char szPenulis[] = "Ancient One"
char szWeb[] = "http://www26.brinskter.com/paipx"
char szMod[] = "+n +g"
VOID MAIN () {
Pada part pertama saya dah bincangkan mengenai debugger. Bagaimana anda boleh mengubah
sesuatu program tersebut dengan menggunakan debugger dan menyaksikan bagaimana program
itu dilaksanakan arahan demi arahan secara langsung di dalam debugger. Di masa akan datang
saya akan meneruskan dengan tutorial mengenai debugger since ia amat penting dalam
cracking activity. Kali ini saya akan membincangkan pula mengenai satu lagi tools yang
penting dalam aktiviti ini, iaitu disassembler.
DISASSEMBLER.
Secara basicnya, fungsi disassembler dan debugger sama sahaja. Ia akan keluarkan disassembly
output bagi program tersebut. Akan tetapi, berbanding dengan debugger, disassembler tidak
melaksanakan atau mengawal program tersebut, sebaliknya cuma menghuraikan kembali nombor2
binari dalam program tersebut kepada kod2 assembly yang sepadan. Dengan disassembler, program
tersebut akan dianalisis dari byte pertama hingga akhir dan keseluruhan assembly code untuk
program tersebut akan dikeluarkan. Dengan debugger, kita boleh berinteraksi dengan kod2
di dalam program tersebut, ini yang kita panggil sebagai live approach. Dengan disassembler
kita cuma mempunyai kod program tersebut dalam assembly tetapi tidak boleh berinteraksi
dengannya pada masa itu juga. Ini yang kita panggil sebagai dead-list approach.
Terdapat banyak jenis disassembler bergantung pada keupayaannya. Disassembler yang baik
akan membenarkan analisis format fail, struktur kod dan mengeluarkan output untuk
pemproses yang dikehendaki. Pengesanan format fail amat penting kerana terdapat beberapa
format fail yang berbeza digunakan dalam pelbagai platform. Dalam Windows, format fail terbaru
untuk executable ialah PE (Portable Executable). Sebelumnya ialah NE (New Executable) akan
tetapi ia tetap disokong oleh platform Windows terbaru. Dengan penganalisaan format fail,
disassembler berupaya mengeluarkan output disassembly yang betul seperti program entry
point, mengeluarkan maklumat export dan import table daripada program dan juga tidak
mengeluarkan disassembly untuk seksyen2 yang tidak berkenaan. Ini kerana executable file
terdiri daripada sections seperti data, kod, resource, dan sebagainya. Jadi jika
disassembler berupaya membezakan dan menganalisa format file ini, kod disassembly yang
betul dan optimum mampu dikeluarkan.
Berbeza dengan disassembler yang hanya mengeluarkan disassembly program tersebut secara
membuta tuli, disassembler yang bijak juga mampu mengenali compiler program tersebut
berdasarkan signature bytes dalam program tersebut. Ia juga mampu untuk mengenali loop
seperti c language for loop, while, do..while, if..else if.. dan sebagainya sekaligus
menukarkan kod assembly kepada c. Ini banyak membantu kita dalam menganalisa sesuatu
program tersebut bukan pada masa nyata.
Bergantung kepada keperluan anda, debugger dan disassembler masing-masing mempunyai
kelebihannya sendiri. Apa yang penting adalah mencari debugger atau disassembler yang
bagus. Terdapat banyak disassembler yang bagus boleh didapati di internet dan di
antaranya ialah W32DASM, IDA Pro, HIEW dan sebagainya. Jika anda hendak mengetahui
mana satukah yang terbaik, just download them all dan try satu persatu. Secara personal,
saya sukakan HIEW dan W32DASM. Saya cuma gunakan IDA Pro untuk program yang bersaiz besar.
Untuk mengetahui bagaimana disassembler berfungsi, mari kita lihat satu program
PE yang telah di'disassemble' di dalam W32DASM. Pertama sekali saya tunjukkan kod sumber
di dalam assembly yang telah dikompil dengan Microsoft MASM :
;main.asm test program for disassembler
;$ml /c /Cp /coff main.asm
;$link /SUBSYSTEM:WINDOWS main.obj
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
include ..\..\include\windows.inc
include ..\..\include\user32.inc
includelib ..\..\lib\user32.lib
.DATA
szIsi BYTE "Hello World!", 0
szTajuk BYTE "Test", 0
.CODE
mula :
INVOKE MessageBox, 0, OFFSET szIsi, OFFSET szTajuk, MB_OK
RET
end mula
Ini kod yang teringkas saya boleh fikirkan yang keluarkan message box. Ini adalah program
Windows yang valid, selepas sahaja message box di'invoke', kita letakkan ret so ia kembali
kepada operating system (program kita exit). Jika anda hendak compile program di atas, anda perlu
mengubah include dan includelib supaya ia boleh mencarinya di dalam sistem anda. Kod ini dicompile
oleh MASM v7.0. Di bawah pula ialah kod yang dikeluarkan oleh W32DASM :
Disassembly of File: C:\Developments\MASM32\Projects\New Folder\main.exe
Code Offset = 00000400, Code Size = 00000200
Data Offset = 00000800, Data Size = 00000200
Number of Objects = 0003 (dec), Imagebase = 00400000h
Object01: .text RVA: 00001000 Offset: 00000400 Size: 00000200 Flags: 60000020
Object02: .rdata RVA: 00002000 Offset: 00000600 Size: 00000200 Flags: 40000040
Object03: .data RVA: 00003000 Offset: 00000800 Size: 00000200 Flags: C0000040
+++++++++++++++++++ MENU INFORMATION ++++++++++++++++++
There Are No Menu Resources in This Application
+++++++++++++++++ DIALOG INFORMATION ++++++++++++++++++
There Are No Dialog Resources in This Application
+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules = 1 (decimal)
Import Module 001: USER32.dll
+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++
Import Module 001: USER32.dll
Addr:00002038 hint(01BB) Name: MessageBoxA
+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++
Number of Exported Functions = 0000 (decimal)
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++
//********************** Start of Code in Object .text **************
Program Entry Point = 00401000 (C:\Developments\MASM32\Projects\New Folder\main.exe File Offset:00001600)
//******************** Program Entry Point ********
:00401000 6A00 push 00000000
:00401002 680D304000 push 0040300D
* Possible StringData Ref from Data Obj ->"Hello World!"
|
:00401007 6800304000 push 00403000
:0040100C 6A00 push 00000000
* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:0040100E E801000000 Call 00401014
:00401013 C3 ret
* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:00401014 FF2500204000 Jmp dword ptr [00402000]
:0040101A 00000000000000000000 BYTE 10 DUP(0)
:00401024 00000000000000000000 BYTE 10 DUP(0)
:0040102E 00000000000000000000 BYTE 10 DUP(0)
:00401038 00000000000000000000 BYTE 10 DUP(0)
:00401042 00000000000000000000 BYTE 10 DUP(0)
:0040104C 00000000000000000000 BYTE 10 DUP(0)
:00401056 00000000000000000000 BYTE 10 DUP(0)
:00401060 00000000000000000000 BYTE 10 DUP(0)
:0040106A 00000000000000000000 BYTE 10 DUP(0)
:00401074 00000000000000000000 BYTE 10 DUP(0)
:0040107E 00000000000000000000 BYTE 10 DUP(0)
:00401088 00000000000000000000 BYTE 10 DUP(0)
:00401092 00000000000000000000 BYTE 10 DUP(0)
:0040109C 00000000000000000000 BYTE 10 DUP(0)
:004010A6 00000000000000000000 BYTE 10 DUP(0)
:004010B0 00000000000000000000 BYTE 10 DUP(0)
:004010BA 00000000000000000000 BYTE 10 DUP(0)
:004010C4 00000000000000000000 BYTE 10 DUP(0)
:004010CE 00000000000000000000 BYTE 10 DUP(0)
:004010D8 00000000000000000000 BYTE 10 DUP(0)
:004010E2 00000000000000000000 BYTE 10 DUP(0)
:004010EC 00000000000000000000 BYTE 10 DUP(0)
:004010F6 00000000000000000000 BYTE 10 DUP(0)
:00401100 00000000000000000000 BYTE 10 DUP(0)
:0040110A 00000000000000000000 BYTE 10 DUP(0)
:00401114 00000000000000000000 BYTE 10 DUP(0)
:0040111E 00000000000000000000 BYTE 10 DUP(0)
:00401128 00000000000000000000 BYTE 10 DUP(0)
:00401132 00000000000000000000 BYTE 10 DUP(0)
:0040113C 00000000000000000000 BYTE 10 DUP(0)
:00401146 00000000000000000000 BYTE 10 DUP(0)
:00401150 00000000000000000000 BYTE 10 DUP(0)
:0040115A 00000000000000000000 BYTE 10 DUP(0)
:00401164 00000000000000000000 BYTE 10 DUP(0)
:0040116E 00000000000000000000 BYTE 10 DUP(0)
:00401178 00000000000000000000 BYTE 10 DUP(0)
:00401182 00000000000000000000 BYTE 10 DUP(0)
:0040118C 00000000000000000000 BYTE 10 DUP(0)
:00401196 00000000000000000000 BYTE 10 DUP(0)
:004011A0 00000000000000000000 BYTE 10 DUP(0)
:004011AA 00000000000000000000 BYTE 10 DUP(0)
:004011B4 00000000000000000000 BYTE 10 DUP(0)
:004011BE 00000000000000000000 BYTE 10 DUP(0)
:004011C8 00000000000000000000 BYTE 10 DUP(0)
:004011D2 00000000000000000000 BYTE 10 DUP(0)
:004011DC 00000000000000000000 BYTE 10 DUP(0)
:004011E6 00000000000000000000 BYTE 10 DUP(0)
:004011F0 00000000000000000000 BYTE 10 DUP(0)
:004011FA 00000000000038200000 BYTE 10 DUP(0)
:FFFFFFFF End Of Listing
Seperti yang anda lihat, W32DASM mengeluarkan output seperti di atas kerana ia tahu
yang program main.exe kita adalah dalam format PE. Jika W32DASM tidak mengenali format
ini maka sudah tentu ia akan mengeluarkan kod disassembly bermula daripada offset 0
program kita iaitu bermula pada 'MZ' signature. Jika anda lihat output di atas,
W32DASM bukan sahaja mengeluarkan output disassembly, tetapi juga menganalisa program
ini seperti menunjukkan saiz kod dan data sections. Menunjukkan samada terdapat menu
dan dialog resource dan sebagainya. Ia memulakan disassembly listing bermula pada
program entry point (PEP) WIn32 program. Untuk mengetahui apakah maksud2 output di atas
atau memudahkan anda menggunakan disassembler dengan berkesan, anda haruslah tahu
keupayaan disassembler yang anda gunakansamada ia mengenali format file yang anda
hendak disassemble. Seperti yang anda lihat pad akod saya, ia mengimport satu function
daripada user32.dll iaitu MessageBoxA dan ini dapat dikenalpasti oleh W32DASM dengan
menganalisa import table dalam seksyen tertentu dalam program kita. Ia akan dapat mengetahui
function dan library yang kita gunakan dengan menganalisa bahagian ini mengikut seperti
yang didokumenkan oleh Microsoft untuk format PE. Kadangkala disassembler tidak mampu
untuk mengeluarkan output yang betul kerana program tersebut telah di'pack' atau
di'encrypt'kan dan dengan itu ia tidak dapat menganalisa seksyen di dalam program
dengan betul. Program tersebut dapat dilaksanakan kerana terdapat 'loader' di dalam
program tersebut yang akan mengembalikan struktur asal program tersebut semasa runtime.
Anda akan dapat melihatnya dengan menggunakan debugger. Anda sepatutnya tahu mengenai
format PE atau apa sahaj format fail yang anda hendak reverse engineer supaya anda
tahu apa yang anda boleh lakukan.
Kod disassembly untuk memaparkan message box :
:00401000 6A00 push 00000000
:00401002 680D304000 push 0040300D
* Possible StringData Ref from Data Obj ->"Hello World!"
|
:00401007 6800304000 push 00403000
:0040100C 6A00 push 00000000
* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:0040100E E801000000 Call 00401014
:00401013 C3 ret
Daripada listing di atas kita tahu bahawa 403000 adalah lokasi untuk string "Hello World!"
manakala 40300D adalah lokasi untuk string "Test". Jika anda perhatikan, call kepada
messagebox still berada dalam program kita instead of terus ke user32.dll. Sebenarnya apa
yang berlaku ialah, linker menyediakan satu jump table yang akan jump ke fungsi dalam dll
yang berkenaan. table ini akan diisi oleh Windows executable loader semasa program tersebut
dilaksanakan. Oleh itu, program tidak perlu risau semasa compilation. Anda akan memahami semua
ini dengan mudah jika anda memahami format PE. Anda juga akan tahu mengapa terdapat banyak
0 bytes selepas kod kita dah berakhir selepas membaca tentangnya :). Saya akan membincangkan
lebih lanjut mengenai penggunaan disassembler di masa akan datang dan juga mengenai disassembler
lain seperti HIEW dan IDA yang selalu saya gunakan.
}
Kembali ke Isi Kandungan