Jump to content
Ancient One

Reverse Code Engineering

Recommended Posts

intro

Assalamualaikum... Tutorial ni adalah mengenai Reverse Code Engineering (RCE). Ringkasnya, dalam tutorial ni aku akan cuba mendedahkan kepada korang bagaimana untuk menganalisis program binari, dalam kes di mana kita tidak mempunyai akses kepada kod sumber asal program tersebut. Aku hanya fokuskan tutorial ni kepada platform Windows. So kalau aku citer pasal kernel misalnya, aku maksudkan kernel Windows, bukannya Linux, BSD ataupun maner2 OS yang lain. Lebih spesifik lagi, aku personally hanya guna Windows XP Pro (dengan SP2), sebab OS lain.. secara ikhlasnya... takde umphhh!

Dalam bahagian pertama ni aku akan citerkan mengenai beberapa jenis dan kategori tools yang akan kita gunakan dalam sesi menganalisis dan tugas asas setiapnya. Bahagian ni lebih kepada memberi gambaran kepada korang apa yang korang akan buat atau tengok kelak, iaitu apabila korang dah ader pengetahuan asas mengenai RCE. So korang bleh laa anggap bahagian ni sebagai pemanas otak untuk membuka minda korang supaya dapat menerima maklumat2 asas dalam bahagian2 seterusnya. Dalam bahagian2 seterusnya aku akan citer plak basic knowledge dalam RCE dan maklumat2 yang lebih spesifik. Pengetahuan ni amat penting untuk korang yang makan PC, tido PC, mandi PC dan kawin ngan PC korang. Tools yang aku citer kat sini digunakan untuk pelbagai tujuan, di mana asasnya sama sahaja, iaitu untuk membantu menganalisis carakerja program binari. Tools sebegini digunakan oleh security expert untuk mengkaji kod sistem operasi, server, dan komponen2 kritikal suatu program. Tools ni jugak digunakan oleh crackers untuk mengalahkan skim perlindungan suatu perisian. Tools yang sama juga digunakan untuk cheat dalam game. Tools yang sama jugak korang bleh gunakan untuk analisis virus atau aper2 "makhluk asing" yang selalu sangat singgah kat PC korang tuh. Ye laa.. kita sepatutnya jadik tuan kepada PC kita, PC tu cuma hamba abdi dan menatang ni sepatutnya ikut perintah kita, bukan sebaliknya. Tak perlu takut dengan program2 "hantu" yang berlambak2 tu selagi kita penuhkan kepala otak kita dengan ilmu2 ghaib pasal PC ni. Aper2 pun aku harap korang bleh mempelajari sesuatu daripada tutorial yang tak sebrape ni.

disassembler

First sekali aku nak citer pasal disassembler. Tugas asas sebijik disassembler adalah menerima program binari sebagai input dan menghasilkan perwakilan program tersebut dalam bahasa himpunan sebagai output. Output yang kita dapat dari disassembler blehla dikatakan "kod sumber" program tersebut, cuma ia bukannya dalam bentuk yang asal, tapi dalam bahasa himpunan. Contoh2 disassembler adalah IDA (Interactive DisAssembler), PEBrowse Professional, BDASM, W32DASM dan lain2. Untuk mendapat sedikit idea mengenai menatang bahasa himpunan ni, kat bawah aku tunjukkan screenshot dari PC aku, di mana IDA dan Minesweeper tengan berjalan, dan aku tengah analisis kod Minesweeper menggunakan IDA (errr.. kotak2 dan garis2 kaler merah, kuning, ping dan hijau tu aku tambah laaa).

rce00qp1.th.png

Baris2 teks "push ...", "mov ...", "call ..." dan lain2 tu laa yang kita panggil sebagai bahasa himpunan. Nanti aku citer details lagi pasal ni. Cebisan kod dalam gambar di atas merupakan kod yang digunakan oleh Minesweeper untuk memaparkan "about box" game ni (iaitu menu help->About Minesweeper). Simbol2 teks "LoadIconW", dan "ShellAboutW" dalam prosedur tersebut adalah 2 daripada ribuan Windows API (Application Programming Interface). Semer Windows program gunakan Windows API untuk berinteraksi dengan Windows dan kebanyakannya didokumenkan dalam Platform SDK (Software Development Kit). Memahami Windows API merupakan salah satu kunci untuk memahami fungsi suatu prosedur dalam program Windows. Contohnya, dalam prosedur di atas, kod yang ditandakan dalam petak merah digunakan untuk load string dari string table resource program tersebut (bleh dilihat dengan mana2 program resource viewer, seperti Resource penggodam) ke ruang alamat (virtual memory) winmine dan string tersebut adalah "Minesweeper". Kod yang ditandakan dengan warna kuning plak sama dengan kod sebelum ni, tapi string yang dimuatkan ke memori adalah "by Robert Donner and Curt Johnson". Kod bertanda pink plak digunakan untuk load icon Minesweeper (jugak dari resource) dan akhir sekali, fungsi ShellAboutW digunakan untuk memaparkan "about box" Minesweeper. Kod yang aku tak tanda tu merupakan prolog dan epilog untuk prosedur tersebut, untuk setup storage untuk local variables. Seperti yang dapat dilihat, prosedur ni dinamakan secara automatik oleh IDA dengan nama sub_1003D1D. Bila dah dapat kesan tugas suatu prosedur tu, biasanya kita akan namakannya dengan nama yang lebih bermakna, e.g "DisplayAboutBox" atau sebagainya. IDA dipanggil "interactive" disebabkan kebolehannya menerima input dari kita untuk membantu dalam analisis di mana kebanyakan disassembler lain tidak mampu lakukan. Kolum yang ader teks ".text:xxxxxxxx" tu adalah virtual address untuk kod ni, ".text" means ia ader dalam seksyen bernama ".text". Teks yang ditandakan dengan semikolon tu adalah komen (biasa digunakan dalam pengaturcaraan bahasa himpunan). Note that IDA secara automatik membantu memberikan komen untuk setiap cebisan kod yang dia tahu maknanya. Bukan tu ajer, kita bleh masukkan komen kita jugak. Biasanya dalam RCE kita akan convert laa prosedur ni dalam bentuk yang lebih kita fahami (biasanya high-level language yang kita familiar atau pseudocode). Contohnya, aku bleh convert prosedur ni ke bahasa C seperti berikut :

        void DisplayAboutBox() {
            TCHAR str1[128], str2[128];
            sub_10039E7(12, str1, 128);
            sub_10039E7(13, str2, 128);
            ShellAbout(hWnd, str1, str2, LoadIcon(hInstance, 100));
        }
    

Akhir sekali, untuk memahami output disassembler ni kita kena laa faham mengenai pengaturcaraan. Untuk contoh ni, kita kena faham pengaturcaraan bahasa himpunan, pengaturcaraan Windows dan juga struktur fail format PE (Portable Executable), iaitu format rasmi program executable dalam Microsoft Windows. Ni laa benda yang kita akan pelajari dalam bahagian2 seterusnya. Korang tak paham penerangan di atas sekarang ni takpe. Lain kali korang akan paham.

Kita perlu menggunakan disassembler yang betul untuk sistem yang betul kerana terdapat pelbagai senibina pemproses untuk komputer, begitu juga dengan format fail program yang biasa disertakan dengan pengepala (header) untuk membantu OS melaksanakan fail program tersebut dengan betul. Kebanyakan disassembler adalah spesifik kepada satu fail format dan satu senibina. IDA pula menyokong pelbagai jenis fail format dan senibina pemproses. Ini bermakna jika kita menggunakan IDA versi Windows, kita masih boleh memproses fail program ELF, yang biasa digunakan dalam Linux, ataupun fail program class, iaitu format yang digunakan oleh Java, dan bermacam-macam lagi laaa...

Satu perkara yang perlu diingati adalah disassembler hanya memproses isi fail program seperti mana ia terdapat dalam fail tersebut (analisis statik). Disassembler sesuai digunakan untuk analisis kod program yang "normal" dan linear. Kebanyakan virus zaman sekarang biasanya encrypt diaorang nyer code, atau guna poly/metamorphic engine yang surely disassembler takleh nak analisis. Untuk melakukan analisis secara dinamik, di mana kita bleh mengawal aliran kod dan ruang alamat sesuatu program, kita perlukan debugger.

debugger

Debugger ni memang tak asing laaa untuk para programmers, sebab ia salah satu tools yang digunakan oleh programmer dalam sesi debugging. Istilah "bug" ni digunakan untuk merujuk kepada "kesilapan" dalam program binari. Tapi tak semestinya ia disebabkan oleh kod program tu. Bleh jadik disebabkan oleh program lain yang berinteraksi dengan program tu, atau bleh jadik kod sistem operasi jugak. Kalau kod program tu tak dapat handle pelbagai cara bagaimana pengguna menggunakannya pun dikira mempunyai bug jugak. Bila dah nampak kesan kesilapan ni (e.g keluar error message ke, tiba2 hang ke), programmer biasanya gunakan debugger untuk kesan punca masalah. Debugger ni basically cam disassembler laaa.. bezanya kita laksanakan program tu di bawah kawalan debugger, maknanya kita bleh tengok setiap baris kod dilaksanakan dan setiap variable atau register berubah in real time.

Contoh2 debugger yang biasa digunakan untuk analisis program binari adalah seperti SoftIce, WinDbg (Platform SDK), OllyDbg, PEBrowse Professional Interactive dan lain2 laaa.. Kalau korang tanya mana2 cracker kat dunia nih, diaorang tentu kenal ngan SoftIce. Rasanya development SoftIce dah stop dah, maknanya takde laa lagi SoftIce baru dari company yang bikin menatang ni. Tapi ader gak rasanya bakal pengganti SoftIce, yang dipanggil Syser. Ni screenshot dari PC aku - SoftIce, tengah stop kat entrypoint (permulaan kod program) Minesweeper.

rce01mb2.th.png

Seperti yang korang dapat lihat di atas, bahagian yang ditandakan dengan no. 3 tu adalah perwakilan kod program tersebut dalam bahasa himpunan. No. 1 plak tunjukkan registers (storan sementara dalam CPU). No. 2 plak adalah ruang ingatan dan no. 4 tempat kita berikan arahan untuk SoftIce (contohnya arahan "cls" tu laaa). Dari permulaan kod program ni, aku bleh "single step" setiap baris kod assembly ni atau modify kod ni untuk mengubah kelakuan program. Actually ader lagi resources lain yang aku tak tunjuk, contohnya FPU registers, MMX, XMM registers dan lain2 lagi.

Dengan debugger, aku bleh execute program arahan demi arahan, modify memory dan variables yang digunakan dalam program malah mengubah arahan dan banyak lagi laa. Biasanya programmer nyer debugging session disertakan dengan kod sumber dan basically dia debug kod dalam high level language, bukannya level assembly. Dan most programming language system ader debugger khas, terutamanya yang tak kompil ke native machine code. Nanti laa aku citer lagi banyak pasal ni.

hex editor/viewer

hex editor/viewer membolehkan kita melihat isi kandungan sebenar (mentah) sesuatu fail dalam sistem. Kita tau yang setiap fail, tak kira la fail imej ke, audio ke, video ke, exe ke semernya terdiri daripada nombo2 binari 0 dan 1 sahaja. Nombor2 ni mempunyai makna kepada program2 yang memahaminya, memprosesnya dan menterjemahkannya kepada bentuk yang lebih bermakna (e.g Winamp untuk mp3 files). Hex editor/viewer tidak memproses isi kandungan fail ni dan hanya memaparkan nombor2 binari yang membentuk fail tersebut. Contoh2 hex editor adalah seperti WinHex, Hex Workshop, BIEW, AXE, 010Editor dan banyak lagi. Kebanyakan hex editor bukan hanya mampu memaparkan isi kandungan fail, tapi juga disk dan memori. Sebagai contoh, screenshot di bawah adalah dari 010Editor (feveret aku) yang tengah memaparkan isi kandungan sektor pertama hard disk aku, atau yang kita kenali sebagai Master Boot Record (MBR).

rce02bp7.th.png

Tetingkap utama dalam hex editor tu laa yang ader 3 kolum tu. Yang first untuk address/offset, yang kedua adalah isi kandungan fail dalam asas perenambelas (hex) dan yang ketiga adalah perwakilan ASCII (control character ngan ascii code > 127 dia wakili dengan dot jer). Hex editor/viewer memang sesuai laa kalau nak kaji format2 fail tertentu. Daripada gambar di atas, aku bleh nampak yang hard disk 40 GB aku cuma ader 1 partition jer, dengan ID 7 (NTFS filesystem). Ader jugak hex editor yang bleh paparkan isi fail selain daripada asas perenambelas (yang biasa adalah asas 2, 8 dan 10), dan kebanyakan hex editor jugak sediakan data interpreter (cam 010Editor Inspector kat sebelah kiri tu) untuk memudahkan analisis. Lain kali aku citer plak lebih details lagi mengenai hex editor feveret aku, terutama mengenai "template" feature.

monitoring programs

Program2 yang monitor system resources ni memang sangat berguna laa terutama untuk detect masalah dalam sistem dan melakukan pra-analisis. Terdapat banyak jenis resources yang kita bleh monitor, bergantung kepada keperluan kita. Contoh paling mudah adalah task manager di mana kita bleh tengok pelbagai maklumat mengenai proseses, users dan network connections dalam sistem. Dalam bahagian ni aku citer sikit jer dulu..

First sekali, aku perkenalkan korang dengan tools feveret aku, iaitu Process Explorer. Process Explorer ni bleh dikatakan cam Task Manager laa, cuma dia fokus kepada proses monitoring. Maknanya kita bleh dapatkan pelbagai maklumat mengenai setiap proses yang wujud dalam sistem, termasuklah fail program dan dll yang terlibat dan handles yang dipegang oleh setiap proses. Aku akan sentuh lagi pasal ni nanti.

Then kita ader File Monitor, yang monitor aktiviti filesystem, so kalau ader program sentuh fail2 sensitif korang bleh nampak laa dalam log File Monitor ni.

Kemudian kita ader Registry Monitor, yang monitor aktiviti registry, so kalau korang nak tau samada suatu program simpan data dalam registry korang, bleh laa tengok dengan Registry Monitor. Contohnya, dalam screenshot di bawah adalah tetingkap Registry Monitor tengah monitor registry access oleh Minesweeper.

rce03vm0.th.png

Kita bleh nampak Minesweeper simpan settings kat subkey "HKCU\Software\Microsoft\winmine\" (HKCU means HKEY_CURRENT_USER). Dan nampak gayanya dia try QueryValue ke atas Tick dan Menu value tapi tidak berjaya (dua2nya takde dalam registry). Kita jugak bleh nampak kegunaan key lain seperti Time*, Name*, Height dan yang pastinya Minesweeper menggunakan registry untuk menyimpan setting dia. Bila kita ubah setting dalam game, ia akan menulis ke registry setting yang baru.

Actually ader banyak lagi monitoring programs yang lain yang sangat2 laa berguna dalam menganalisis program binari. Errr.. antivirus pun monitor gak, tapi ni menatang lain sama sekali, sebab virus bukan system resources. Dan sebenarnya ader banyak lagi tools yang tugasnya very specific dan sangat membantu dalam keje2 kotor kita ni. Tapi aku cuma akan perkenalkan korang kepada tools ni bila kita nak gunakannya dalam analisis contoh2 program dalam bahagian2 seterusnya.

----- tamat bahagian 1 -----

bersambung...

Edited by Ancient One

Share this post


Link to post
Share on other sites

Sapa-sapa yang dapat menguasai assembler/disassembler (ASM), nanti senang je nak reverse program (krack), terutamanya menerusi penggunaan OllyDBg. Belajar dari asasnya supaya dapat memahami setiap kod binary dan bagaimana program berfungsi. Kebanyakkan cracker hari ini menggunakan tools tersebut untuk menganalisa program untuk dibuat kracknya. Kalau dulu SoftIce yang paling masyhur sekarang OllyDbg pulak.

Reverse Engineering ni dianggap satu 'seni' juga, bukannya untuk melakukan krack semata2. Ini yang perlu diambil perhatian oleh setiap orang yang berminat dalam bidang ni. Sebaiknya kena ada asas untuk programming juga( samada VB, C, C++, Java, Delphi/Borland, Pascal, .Net dan lain-lain) bagi mereka yang berminat untuk belajar disassembler atau debugger. Walaubagaimanapun seseorang masih boleh menguasai Disassembler atau Debugger walaupun tidak tahu langsung bahasa programming kerana ilmu ini boleh berdiri dengan sendirinya.

Sekadar pendapat, betul tidak aku mana tau, aku sendiri pun tak tau. :lol:

Share this post


Link to post
Share on other sites

hmmm gogogo ader jgk org yang bijok hal2 reverse-mereverse ni .....ok2.....dah lama tak main kut blkg nih...hahaha :lol:

leh gak refresh skit2 hehe ;)

Share this post


Link to post
Share on other sites

leh bagi jadual?takut terlepas kelas tutorial la.....:)

Share this post


Link to post
Share on other sites

Bahagian I : Asas pengaturcaraan

intro

Sebelum ni aku citer mukadimah jer (bahagian 0). Sekarang meh kita start dengan basic. RCE, secara umumnya bleh laa dikatakan songsangan untuk proses pembinaan program. Kalau dalam proses pembinaan program kita bermula daripada kod sumber dan berakhir menjadi program binari, songsangannya plak adalah untuk mendapatkan semula kod sumber daripada program binari ni. So, tak dapat dinafikan lagi memahami proses pembinaan program adalah sangat penting untuk memahami RCE. Tu sebab dalam bahagian ni kita akan belajar mengenai asas pengaturcaraan, khususnya untuk PC kita. Tapi sebelum aku citer pasal pengaturcaraan, meh kita kembali semula ke sekolah untuk belajar matematik. Ni kira matematik tahap tadika laa ni, sebab sebenarnya kita nak belajar mengira semula.

sistem pernomboran

Aku tak tau laa brape banyak bangsa manusia yang wujud kat dunia nih, tapi aku rasa laa kebanyakannya (kalau tak semer) sekarang mengira menggunakan sistem pernomboran asas 10 (decimal). Dalam sistem decimal, 10 simbol digunakan untuk mewakili kuantiti, iaitu angka 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 (ni kita nyer simbol laa.. lain bangsa lain plak simbolnya). Walaupun kecik2 dulu kita selalu start kira dengan nombor 1, rasanya sekarang ni kita tau laa yang simbol pertama dalam sistem ni adalah 0. Untuk mewakili nombor yang lebih besar dari 9 plak, kita cuma recycle simbol2 0 hingga 9 ni, iaitu turutan simbol ni kita ulang semula tapi dengan bilangan digit yang semakin bertambah. Contohnya penambahan sebanyak 1 kepada 9 kita tulis sebagai 10. "1" dalam "10" tu maksudnya turutan simbol asas dah disempurnakan sekali, dan "0" dalam "10" tu plak menandakan kita sedang berada pada simbol pertama untuk turutan yang baru nih.

Konsep yang perlu difahami di sini adalah dengan simbol2 asas ni, kita gunakannya untuk mewakili kuantiti yang semakin bertambah mengikut urutan, sehinggalah semernya telah digunakan, dan kemudian tambah satu digit lagi dan ikut semula turutan tersebut. Ni laa prinsip utama yang digunakan dalam semer sistem nombor, yang berbeza hanyalah bilangan simbol asas yang digunakan. Bila dah paham konsep ni, meh aku perkenalkan plak 2 lagi sistem pernomboran yang sangat penting dalam subjek RCE kita nih, iaitu sistem pernomboran asas 2 (binary) dan sistem pernomboran asas 16 (hexadecimal).

sistem binary
. Dalam sistem binary, kita hanya gunakan dua simbol asas, iaitu 0 dan 1. Dengan mengikut konsep yang aku sebut kat atas tadi, jadual di bawah menunjukkan 10 nombor pertama dalam sistem decimal dan perwakilannya dalam sistem binary :

  decimal        binary   -------        ------      0             0      1             1      2             10      3             11      4             100      5             101      6             110      7             111      8             1000      9             1001   
sistem hexadecimal
. Oleh kerana hanya ader 2 simbol dalam sistem binary, dah tentu banyak sangat laa digit yang perlu digunakan untuk mewakili nombor yang besar, dan dah tentu jugak payah kita nak manipulasi. So, wujud laa plak sistem hexadecimal, atau ringkasnya hex, menggunakan 16 simbol asas untuk mewakili kuantiti. Oleh kerana kita cuma ader 10 simbol jer untuk mewakili angka, iaitu 0-9, maka sistem hex, selain dari menggunakan 0-9, jugak menggunakan abjad A, B, C, D, E dan F untuk mewakili 6 simbol lagi, so kita ader turutan 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, dan F sebagai simbol asas. Aku letakkan plak kat bawah 20 nombor pertama dalam sistem decimal, binary dan jugak hexadecimal sebagai perbandingan :
  decimal        binary        hexadecimal   -------        ------        -----------      0             0                0      1             1                1      2             10               2      3             11               3      4             100              4      5             101              5      6             110              6      7             111              7      8             1000             8      9             1001             9      10            1010             A      11            1011             B      12            1100             C      13            1101             D      14            1110             E      15            1111             F      16            10000            10      17            10001            11      18            10010            12      19            10011            13   
*Note that 1 digit nombor hex (0 hingga F) bleh mewakili maner2 4 digit nombor binary (0 hingga 1111)*. Tu jer laa yang aku nak citer pasal sistem pernomboran ni. Tak details lagi tu, just untuk memperkenalkan jer. Yang penting di sini kita patut paham yang sistem pernomboran yang berbeza-beza ni hanyalah kaedah yang berbeza untuk mewakili kuantiti. Kuantitinya tak berubah, cuma simbol yang kita gunakan untuk mewakilinya saja yang berbeza. Perhatikan jugak nombor yang dinyatakan dalam asas sistem tersebut, e.g asas
2
,
10
,
16
dan sebagainya adalah bilangan simbol asas yang digunakan dalam sistem tersebut. So kalau aku guna asas 36 misalnya, ader 36 simbol asas laa, maknanya 1 digit dalam simbol asas 36 ni bleh mewakili 36 nombor pertama dalam sistem decimal. Aku bleh guna simbol2 0-9 dan A-Z sebagai simbol untuk mewakili nombor2 dalam asas 36 ni. Tu contoh laa. In case korang tertanya-tanya aper kepentingan aku kenalkan 2 sistem nombor - binary dan hex ni, meh laa pakat2 bacer topik seterusnya kat bawah.
kenali PC kita
Errr.. tak masuk lagi sebenarnya topik pengaturcaraan. Kita berkenalan dulu dengan lebih rapat dengan PC kita. Ye laa.. orang cakap... tak kenal maka tak cinta
:)
. PC, secara dasarnya mempunyai 3 komponen utama iaitu
CPU
,
memori
dan
alat input/output
(I/O) dan CPU bleh berkomunikasi dengan memori dan I/O secara terus.
CPU
. CPU (Central Processing Unit) adalah komponen yang bertanggungjawab melaksanakan arahan komputer dan memproses data2 yang terlibat semasa perlaksanaan arahan2 ni. Aku guna istilah CPU untuk merujuk kepada pemproses utama dalam PC. CPU ni la menatang paling penting dalam PC kita dan ia bleh laa dianggap "otak" untuk PC. Errr.. komponen lain pun penting gak, tapi keadaan kat dalam CPU jer laa yang paling meriah. CPU amik arahan yang perlu dilaksanakan daripada memori dan data plak bleh disimpan/dibaca ke/dari memori atau I/O. CPU ni sebenarnya blehlaa kita anggap sebagai koleksi suis2 elektronik. Aku yakin korang penah nampak suis lampu kat maner2 yang bleh mempunyai 2 keadaan, samada On atau Off. Kalau kiter On, lampu menyala dan kekal camtu selagi kita tak ubah suis ke Off, dan sebaliknya. Camtu laa jugak suis2 elektronik dalam CPU ni. Bezanya suis ni takde laa beso cam suis lampu, tapi dalam saiz mikroskopik, kena guna mikroskop baru bleh nampak. Dalam CPU, suis2 elektronik ni dibentuk daripada transistor. Kita bleh perhatikan yang sifat suis elektronik ni yang hanya bleh bezakan 2 keadaan fizikal memang "ngam" sangat laa dengan sistem binary yang aku citer kat atas tadi. Kita bleh anggap yang keadaan On mewakili 1 dan keadaan Off mewakili 0. So, secara matematiknya, CPU (dan komputer umumnya) hanya memanipulasi nombor dalam sistem binary. Satu digit nombor binary kita panggil sebagai
bit
(
BI
nary digi
T
) dan ni laa unit data paling asas dalam CPU. Transistor kat dalam CPU bukan hanya ader sikit, tapi juta2. Transistor2 ni disusun mengikut konfigurasi tertentu (dipanggil get logik) sehingga ia bleh digunakan untuk melakukan operasi2 tertentu ke atas nombor2 binari ni. Tak perlu laa aku citer details pasal struktur fizikal ni.. nanti lain plak jadinya... Setiap CPU telah dibina di dalamnya set arahan yang ia fahami dan tugas2 yang perlu dilakukan untuk melengkapkan arahan ni. Setiap arahan diwakili oleh siri nombor binari yang unik, iaitu
opcode
(
OP
eration
CODE
). Contohnya kalau CPU tengah amik nombor binary 10010010 dari memori sebagai arahan, unit yang bertanggungjawab dalam CPU akan mencari arahan yang mempunyai opcode 10010010 dan memprosesnya jika arahan ni wujud. Ringkasnya cam tu laa.... Semer CPU yang kita guna kat PC tergolong dalam satu keluarga CPU yang kita panggil sebagai
80x86
, atau
x86
. Bila aku sebut satu keluarga kat sini basically maknanya semer CPU dalam keluarga ni menyokong set arahan asas yang sama. Latest CPU dalam satu keluarga, walaupun ditambah dengan arahan2 baru, masih menyokong arahan2 asas CPU sebelumnya. Aku yakin korang tentu lebih tau nama2 CPU yang dikeluarkan oleh
Intel
dan
AMD
. Contohnya 80386, K6, Pentium, Celeron, Duron, Athlon, Sempron dan lain2 laa. PC dulu2 guna CPU 16-bit, cam 8088, 8086. Then PC kita guna plak CPU 32-bit cam 80386, Pentium dan lain2. Sekarang ni plak kita dah bleh guna CPU 64-bit, cam Athlon 64. Orang selalu sebut CPU 64-bit dari AMD sebagai AMD64, dan Intel plak panggil EM64T, aper2 pun kat sini aku rujuk dua2 dengan nama x86-64. 16/32/64 bit kat sini biasanya merujuk kepada saiz satu general purpose register so kalau kita ader CPU 16-bit maknanya dia bleh manipulasi data bersaiz 16 bit sekaligus.
memori
. Memori ni merujuk kepada memori utama dalam PC, yang selalu kita sebut sebagai RAM, atau nama penuhnya Random Access Memory. Program dan data disimpan dalam RAM sebagai storan sementara sehinggalah ia diperlukan oleh CPU. "Random Access" maknanya kat sini bukanlah ia diakses secara rawak oleh CPU, tapi ia diakses mengikut alamat. Kita bleh anggap RAM sebagai terbahagi kepada "bilik"2, yang kita panggil sebagai sel memori di mana data disimpan dan diambil. Setiap sel ni mempunyai saiz yang sama dan bleh menyimpan beberapa bit data. Setiap sel mempunyai alamat yang unik dan dinomborkan mengikut urutan bermula dari 0, so sel pertama mempunyai alamat 0. Oleh kerana setiap setiap sel mempunyai alamat yang unik, maka CPU bleh laa gunakan alamat ni untuk akses mana2 sel yang ia kehendaki secara direct. Actually dalam PC, setiap sel memori ni bersaiz tepat 8 bit. Satu kumpulan 8 bit data kita panggil sebagai
byte
, maknanya 1 byte bleh mewakili 8 digit nombor binari. RAM disebut sebagai "byte-addressable memory" kerana setiap alamat adalah dalam turutan 1 byte. So bila kita cakap byte ke 100 dalam memori, kita merujuk kepada sel memori ke 100. Byte adalah unit asas data dalam memori dan bila2 masa kita read/write data dari/ke memori, kita hanya berurusan dengan data dengan saiz minimum 1 byte, takleh laa suka2 nak akses 1 atau 2 bit jer secara direct. Nanti kita akan belajar plak aper beza physical memory dengan virtual memory, physical address, logical address, virtual address dan lain2 laa..
I/O
. I/O ni, bagi kita adalah menatang cam monitor, keyboard, mouse, printer dan sebagainya yang kita gunakan untuk berinteraksi dengan komputer. I/O ni perantara kita dengan CPU laa kiranya. Bagi CPU plak, I/O ni lebih kurang sama laa cam memori, di mana ia bleh read/write data dari/ke I/O dan setiap alatan input/output ni mempunyai alamat yang unik gak. Aku nak tambah lagi 2 menatang yang penting jugak cam 3 komponen kat atas. First sekali aku nak citer pasal storan tetap (e.g disk) sebagai tempat simpanan untuk data yang tak digunakan oleh CPU pada satu2 masa. Meh kita bayangkan disk ni sebagai kabinet fail kat opis korang dan RAM tu plak meja kerja korang, dan korang plak adalah CPU. Fail yang korang nak guna (proses) maser tu dah tentu lebih mudah diakses kalau letak atas meja dan fail yang tak berkaitan dengan keje korang maser tu bleh laa simpan kat kabinet, untuk tidak menyesakkan meja. For sure memang payah laa nak proses data dalam fail kalau biar jer kat kabinet, mesti kena letak kat meja gak. Camtu laa kiranya kegunaan storan tetap ni. Satu lagi adalah benda bukan fizikal, kita tak nampak tapi memang sangat menakjubkan, iaitu program. Tanpa program, PC kita basically tak best laa.. Program ni laa yang menjadik "penterjemah" kita bila berinteraksi dengan komputer. Terdapat pelbagai jenis program yang ader untuk melakukan pelbagai tugas dan menyelesaikan pelbagai masalah manusia dan yang paling penting sekali antaranya adalah OS (sistem operasi) yang menjadi antaramuka antara kita dan komponen komputer dan juga menyediakan servis2 kepada program2 lain seperti penyunting teks, kalkulator dan sebagainya.
konsep pengaturcaraan
Pengaturcaraan komputer, bagi aku maknanya ringkas jer, iaitu
mengarahkan komputer untuk melakukan sesuatu
. Secara tradisionalnya, kita mengaturcara dengan membina program yang mengandungi arahan2 untuk dilaksanakan oleh CPU. Proses pembinaan program bleh diringkaskan seperti yang ditunjukkan dalam rajah di bawah :
rce0200qv9.png
Kod sumber
biasanya disediakan dalam bentuk fail dalam storan komputer yang ditulis mengikut spesifikasi bahasa pengaturcaraan yang tertentu. Ia bleh dianggap sebagai arahan yang kita hendak CPU laksanakan daripada perspektif bahasa pengaturcaraan tersebut. Kemudian kod sumber ni diberikan sebagai input kepada compiler (penyusun ke aper tah). Compiler adalah program yang menterjemahkan kod sumber ni kepada program yang terdiri daripada bahasa mesin (siri nombor binary), iaitu satu-satunya bahasa yang difahami oleh komputer. Aku gunakan istilah compiler untuk merujuk kepada semer program yang menterjemahkan kod sumber kepada bentuk kod yang akan dilaksanakan. Juga bleh jadik terdapat lebih dari satu program yang digunakan untuk menterjemahkan kod sumber (compiler system). Kod sumber yang ditulis dengan bahasa pengaturcaraan biasanya ader laa iras2 English gabung ngan formula matematik. Contohnya, untuk membina program yang menambah 3 nombor, kita tulis kod sumbernya seperti berikut, dalam satu bahasa pengaturcaraan yang dipanggil C :
  #include <stdio.h>   void main() {     int x, y, z;     printf("Berikan 3 nombor integer : ");     scanf("%i %i %i", &x, &y, &z);     printf("Jumlah %i+%i+%i = %i", x, y, z, x+y+z);   }   
Kod sumber ni kemudiannya diproses oleh compiler yang memahami bahasa C (C compiler laa). Sebagai penerangan ringkas, pernyataan matematik x+y+z dalam kod C di atas mewakili arahan untuk menambah 3 nombor yang disimpan dalam pembolehubah x, y, dan z dalam memori. #include adalah arahan untuk komponen dalam compiler (prapemproses), scanf dan printf membolehkan kita menerima input dan memaparkan output ke paparan komputer. Kalau kod sumber ditulis dengan betul, hasilnya merupakan program binari yang kalau kita lihat isinya di dalam memori adalah siri2 nombor binari, e.g (dalam hex) :
55 8B EC 83 EC 0C 68 40 A0 40 00 E8 5C 00 00 00 83 C4 04 8D 45 F4 50 8D 4D FC 51 8D 55 F8 52 68 5C A0 40 00 E8 2C 00 00 00 83 C4 10 8B 45 F8 03 45 FC 03 45 F4 50 8B 4D F4 51 8B 55 FC 52 8B 45 F8 50 68 68 A0 40 00 E8 20 00 00 00 83 C4 14 33 C0 8B E5 5D C3 8D 44 24 08 50 FF 74 24 08 68 88 A0 40 00 E8 69 02 00 00 83 C4 0C C3 53 56 57 BE A8 A0 40 00 56 E8 78 11 00 00 8B F8 8D 44 24 18 50 FF 74 24 18 56 E8 B9 12 00 00 56 57 8B D8 E8 ...... dan seterusnya

*Note that 2 digit nombor hex bleh mewakili mana2 8 digit nombor binari (8 bit, atau 1 byte). Oleh kerana 1 byte data adalah unit asas dalam memori, kita selalu tulis data menggunakan sistem nombor hex. Setiap dua digit nombor hex bleh mempunyai nilai di antara 0 hingga 255 decimal.*

Sepertimana kita berkomunikasi sesama manusia dengan menggunakan bahasa manusia (e.g Melayu, English, Jepun, Esperanto dan sebagainya), kita "berkomunikasi" dengan komputer menggunakan bahasa pengaturcaraan. Macam bahasa manusia jugak, bahasa pengaturcaraan ada banyak jenis dan dialek. Rasanya ader beribu-ribu gak bahasa pengaturcaraan yang wujud sejak komputer digital mula wujud sampai laa sekarang ni. Kita bleh kategorikan bahasa pengaturcaraan dalam beberapa cara, tapi kat sini, ikut cara aku, aku cuma bahagikan kepada 3 - bahasa mesin, bahasa aras rendah (Low Level Language - LLL) atau lebih dikenali sebagai bahasa himpunan dan bahasa aras tinggi (High Level Language - HLL).

Bahasa C adalah salah satu dari ribuan HLL yang wujud dan HLLs dinamakan sedemikian sebab kita lebih cenderung memahaminya daripada LLL dan bahasa mesin. Ader banyak laa nama2 HLL, contohnya C, Fortran, Cobol, Pascal, Ada, Lisp, Algol, C++, Basic, Perl, C#, Forth, Javascript, Java dan macam2 lagi laa.. Model yang digunakan oleh HLLs ni untuk menyelesaikan masalah kita panggil sebagai paradigma pengaturcaraan. Kita ader procedural paradigm cam C, Pascal dan Fortran; kita ader object-oriented paradigm cam SmallTalk; kita ader functional paradigm cam Lisp ngan Haskell dan lain2 model lagi laa.. Selalunya setiap bahasa pengaturcaraan menyokong satu model tapi ader gak yang support lebih dari 1, contohnya C++ support procedural model ngan object-oriented model.

Bahasa himpunan, atau ringkasnya asm (assembly language), jugak kita panggil sebagai LLL direka untuk memberikan kuasa penuh kepada pengaturcara untuk mengakses setiap arahan mesin dalam set arahan yang difahami oleh CPU dan jugak persekitaran pengaturcaraan yang disediakan oleh CPU. So bleh katakan aper2 menatang yang bleh diprogramkan dalam CPU bleh diakses dengan asm. Oleh kerana CPU berlainan bleh mempunyai set arahan yang berbeza, maka asm pun bleh berbeza-beza antara semer CPU ni. Kita selalu panggil pengaturcaraan asm kat PC sebagai x86 assembly programming, untuk merujuk kepada asm yang khusus kepada CPU dalam keluarga x86. Assembler, atau assembly compiler adalah program yang bertanggungjawab menterjemahkan kod sumber asm kepada bahasa mesin. Arahan mesin, apabila dilihat dari perspektif asm; atau kita bleh cakap setiap arahan asm, mempunyai format berikut :

<mnemonik arahan> <pengoperasi>

<mnemonik arahan> adalah arahan mesin dalam asm, contohnya ADD untuk operasi tambah, JMP untuk JuMP, CMP untuk CoMPare, MOV untuk MOVe dan sebagainya. Kita bleh dapatkan senarai arahan dalam set arahan yang disokong oleh satu2 CPU daripada pengeluar CPU tersebut, dan untuk PC, kita bleh laa mintak kat Intel atau AMD (actually bleh download dari website depa ni laa). Aku tak tau laa exact URL (rasanya URL dia bleh berubah-ubah.. pelik), tapi bleh cari kat
dan dokumen tu tajuk utama dia
"IA-32 Intel® Architecture Software Developer’s Manual"
. Rasanya ader 3 bahagian dan bahagian kedua adalah rujukan set arahan. Kalau korang nak tau basic programming environment untuk x86 ni laa dokumen2 yang patut menjadi rujukan (bahagian 1 dan 2). Bahagian 3 adalah untuk pengaturcara sistem (e.g OS developers). Dari website AMD pun bleh gak download. Tajuk utama dokumen2 ni (ader 4-5 bahagian) adalah "
AMD64 Architecture Programmer’s Manual"
. Setiap arahan bleh menerima 0, 1, 2 atau 3 pengoperasi (parameter), bergantung kepada tugas arahan tersebut. Contohnya, arahan NOP (No OPeration) tak perlukan aper2 parameter, so kita tulis sebagai satu baris kod "nop" sahaja. Bagi arahan yang menerima satu pengoperasi, jenis pengoperasi ni biasanya adalah samada alamat memori atau register (register adalah storan sementara kecik kat dalam CPU, so bleh diakses dengan sangat pantas). Contohnya arahan INC (INCrease) bleh digunakan untuk menambah nilai pada satu alamat memori (misalnya 400000) sebanyak 1, so kita tulis sebagai "inc [400000]". Nanti laa aku citer lagi dengan betul pasal asm programming ni.

Setiap arahan2 mesin biasanya diwakili oleh satu baris arahan dalam asm, iaitu bleh dikatakan kod mesin dan kod asm mempunyai hubungan 1-1. Maknanya lebih mudah menukarkan kod asm kepada kod mesin (dan sebaliknya) daripada menukarkan kod HLL kepada kod mesin (dan sebaliknya). Tu sebab asm ni tersangat laa penting dalam subjek RCE kita. HLL diterjemahkan oleh compiler ke bahasa mesin dan dengan disassembler plak kita terjemahkan semula bahasa mesin ni kepada asm, pendek kata, kita dapatlaa semula kod program tu, tapi dalam LLL, bukannya HLL. Sebab kod HLL adalah kompleks dan pernyataan kod program dalam HLL biasanya diwakili oleh beberapa arahan asm, malah bleh gak sampai beratus-ratus. Tanpa sebarang maklumat yang membolehkan bahasa mesin ditukarkan semula ke HLL, terjemahan ni memang mustahil laa. Kesimpulannya kat sini kita kena kenali asm dengan lebih rapat lagi laa.. yang aku akan citer kat bahagian seterusnya.

bersambung.....

Share this post


Link to post
Share on other sites

wahh kelas dah start...harap tak lmbt cikgu :) tak sabar utk kelas akan dtg....

Share this post


Link to post
Share on other sites

C. Operasi aritmetik binari

Arahan2 dalam kategori ni menggunakan flags untuk memberi petunjuk mengenai hasil operasi di mana semuanya menggunakan SF untuk menyatakan samada hasil pada destinasi adalah nombor negatif (set) atau tidak (clear); ZF digunakan untuk menyatakan samada hasil pada destinasi adalah 0 (set) atau tidak (clear), OF digunakan untuk menyatakan samada hasil pada destinasi terlalu besar untuk nombor positif atau negatif (tak termasuk signed bit) (set) atau tidak (clear), PF plak digunakan untuk menyatakan samada 8 bit terkecil hasil pada destinasi mengandungi bilangan bit 1 yang genap (set) atau tidak (clear).

  1. ADD

    Arahan ni menambah 2 pengoperasi (destinasi=destinasi+sumber) di mana CF akan disetkan jika berlaku overflow (carry) dan clear sebaliknya. Peraturan untuk pengoperasinya sama jer ngan arahan MOV. Contoh :

      ADD ESP, 24
      ADD BYTE [EAX], CL
      
  2. SUB Arahan ni kita guna untuk menolak 2 pengoperasi (destinasi=destinasi-sumber) di mana CF akan disetkan jika berlaku overflow (borrow) dan clear sebaliknya. Peraturan untuk pengoperasinya sama jer ngan arahan MOV. Contoh :
      SUB EAX, EAX
      SUB ECX, 1
      
  3. MUL Arahan ni adalah untuk operasi pendaraban ke atas 2 pengoperasi (nombor tak bertanda). Tapi kita cuma berikan satu pengoperasi jer iaitu sumber, sebab destinasinya dianggap adalah AX, atau gabungan DX:AX atau EDX:EAX. Ia berfungsi camni.. kalau kita berikan satu pengoperasi bersaiz byte, maka ia didarabkan dengan nilai pada register AL dan hasilnya diletakkan pada register AX (AX=AL*sumber). Kalau kita berikan pengoperasi bersaiz word, maka ia didarabkan dengan nilai pada register AX dan hasilnya diletakkan pada register DX dan AX (DX:AX=AX*sumber), dan kalau kita berikan pengoperasi bersaiz dword, maka ia didarabkan dengan nilai pada register EAX dan hasilnya diletakkan pada register EDX dan EAX (EDX:EAX=EAX*sumber). Contoh :
      MUL BX                ;DX:AX=AX*BX
      MUL BYTE [EAX] ;AX=AL*nilai pada lokasi yang ditunjuk oleh EAX
      
  4. DIV Arahan ni adalah untuk operasi bahagi ke atas nombor tak bertanda. Peraturannya lebih kurang jer cam arahan MUL. Satu pengoperasi yang diterima adalah merupakan pembahagi. Kalau kita bagi pembahagi bersaiz byte, maka nombor yang dibahagi diambil dari register AX dan hasil bahagi diletakkan pada register AL, manakala bakinya diletakkan pada register AH (AL=AX/sumber, AH=baki). Kalau pembahagi bersaiz word plak maka AX=DX:AX/sumber, DX=baki. Kalau pembahagi bersaiz dword maka EAX=EDX:EAX/sumber, EDX=baki. Contohnya katakan kita nak lakukan x/100 (dengan saiz data dword), di mana x adalah pembolehubah :
      MOV EAX, DWORD [x] ;EAX=x
      MOV EDX, 0                ;EDX=0
      MOV ECX, 100            ;ECX=100
      DIV ECX                      ;EDX:EAX/ECX, iaitu x/100
     ;Kat sini kita ader EAX mengandungi hasil bahagi
     ;EDX plak mengandungi baki
      
  5. NEG Arahan ni tujuannya simple jer, iaitu menterbalikkan tanda nombor pada pengoperasi. So kalau pengoperasi kita negatif, ia jadikannya positif dan sebaliknya. Contohnya :
      NEG EAX    ;EAX = -EAX
      
Tu cuma 5 operasi matematik asas. Kita jugak ader arahan INC (INCrease), DEC (DECrease), ADC (ADd with Carry), SBB (SuBtract with Borrow), IMUL (signed Integer MULtiply), IDIV (signed Integer DIVide) dan XADD. Kita jugak ader arahan CMP (CoMPare) yang sebijik cam arahan SUB, cuma dia tak ubah nilai pengoperasi, hanya update status flags. D. Pemindahan kawalan Arahan2 dalam kategori ni penting untuk mengubah perjalanan kod. Tanpa arahan2 ni, CPU hanya melaksanakan kod program kita secara linear, takleh lompat ke mana2.
  1. JMP Basically untuk melompat ke lokasi lain, kita kena laa berikan alamat untuk melompat. Ader dua cara untuk berikan alamat ni sebagai pengoperasi, secara langsung (nyatakan alamat sasaran untuk melompat) atau tak langsung (nyatakan lokasi terletaknya alamat sasaran untuk melompat). Tengok contoh di bawah :
      JMP SomePlace
      MOV EAX, SomePlace
      JMP EAX
      MOV [LocationOfSomePlace]
      JMP [LocationOfSomePlace]
      
    Kod JMP SomePlace adalah contoh lompatan secara langsung, di mana sasarannya adalah alamat berlabel SomePlace. Dua lagi JMP kat bawah tu contoh secara tak langsung. Label SomePlace (sasaran) diletakkan pada register EAX, kemudian JMP EAX menggunakan nilai pada EAX sebagai alamat untuk melompat.
  2. Jxx Jxx ni bukan arahan sebenar. Jxx ni sebenarnya aku tulis untuk mewakili beberapa arahan yang berkaitan dengan lompatan bersyarat. Sebelum lompatan dilakukan, status flags tertentu diperiksa terlebih dahulu samada ia memenuhi syarat atau tidak. Jika tidak, lompatan tidak akan berlaku dan aliran kod akan bersambung pada arahan selepas Jxx. Jadual kat bawah tunjukkan semer arahan Jxx. xx dalam Jxx digantikan dengan simbol2 pada kolum mnemonic dan kolum kedua plak tunjukkan status flags yang diperiksa.
    
       Mnemonic        Condition tested
       ========        ================
       o               OF = 1
    
       no              OF = 0
    
       c
       b               CF = 1
       nae
    
       nc
       ae              CF = 0
       nb
    
       e               ZF = 1
       z
    
       ne              ZF = 0
       nz
    
       be              CF or ZF = 1
       na
    
       a               CF or ZF = 0
       nbe
    
       s               SF = 1
    
       ns              SF = 0
    
       p               PF = 1
       pe
    
       np              PF = 0
       po
    
       l               SF xor OF = 1
       nge
    
       ge              SF xor OF = 0
       nl
    
       le              (SF xor OF) or ZF = 1
       ng
    
       g               (SF xor OF) or ZF = 0
       nle
      
    Sebagai contoh :
        CMP EAX, 0
        JZ  SomePlace
        CMP EAX, 1
        JE  SomePlace
    
    Arahan CMP set ZF jika EAX-0 = 0 (ingat arahan CMP adalah arahan SUB yang hanya update status flags, tapi tidak destinasi). Arahan JZ SomePlace memeriksa flag ZF. Jika ZF set, maka lompatan ke label SomePlace akan berlaku. Jika tidak, perlaksanaan akan diteruskan pada arahan CMP EAX, 1. Arahan JE hanyalah nama lain bagi JZ dan kedua-duanya mempunyai fungsi yang sama. Secara umumnya, contoh di atas bleh laa diterangkan seperti berikut :
    JIKA EAX = 0 LOMPAT KE SomePlace JIKA EAX = 1 LOMPAT KE SomePlace
  3. CALL Arahan CALL jugak berfungsi lebih kurang sama seperti arahan JMP, iaitu memindahkan perlaksanaan kod ke lokasi lain. Tapi arahan CALL juga menyimpan lokasi arahan berikutnya (arahan selepas CALL) pada stack. So, basically contoh kod
    CALL     SomePlace
    Next:
    MOV     EAX, 1
    
    bleh diwakili oleh arahan berikut
    PUSH    Next
    JMP        SomePlace
    Next:
    MOV        EAX, 1
    
  4. RET Arahan ni biasanya digunakan sebagai pelengkap arahan CALL. Arahan RET (RETurn) menggunakan nilai pada stack sebagai lokasi untuk melompat. So, digabung dengan CALL, arahan RET akan kembali semula kepada aliran kod yang 'memanggil' label tersebut. Contohnya :
    CALL     SomePlace
    Next:
    MOV        EAX, 1
    ;dan kod2 seterusnya
      .
      .
      .
      .
    
    SomePlace:
        RET
    
    Bila arahan CALL SomePlace dilaksanakan, alamat Next disimpan pada stack (top of stack) kemudian perlaksanaan kod berpindah pada label SomePlace. Pada label ni, bila arahan RET dilaksanakan, ia akan menggunakan nilai pada top of stack (tos) yang kini mengandungi alamat Next sebagai alamat untuk melompat, so basically perlaksanaan kod kembali ke label Next. Oleh kerana arahan CALL dan RET menggunakan stack, kena berhati-hati laa kalau ubah ESP (stack pointer).
Aku lupa plak nak bagitau yang kita ader satu register yang bernama EIP (Instruction Pointer). Ni basically kita nyer program counter laa dan CPU amik kod untuk dilaksanakan daripada lokasi yang terkandung dalam register EIP ni. Kita takleh memanipulasi EIP secara langsung. Malah kita jugak takleh merujuk register EIP dalam kod. Takde arahan seperti MOV EAX, EIP dalam asm. Hanya arahan2 dalam kategori pemindahan kawalan yang bleh mengubah register EIP secara tak langsung. Actually tujuan asal aku bukanlah nak citer secara details pasal setiap arahan ni. Oleh sebab tu aku akan stop kat sini walaupun pada hakikatnya ader banyak lagi arahan2 lain dalam kategori2 lain yang aku belum sentuh. Aku bleh katakan yang sebenarnya agak mudah untuk memahami tugas arahan2 asas dan meneka bilangan pengoperasi yang diterima dan jenisnya hanya dengan melihat mnemonik arahan tersebut. Satu idea yang baik adalah dengan mengetahui mnemonik2 yang bleh digunakan dan menyimpan nota atau manual dari Intel/AMD itu sendiri (volume 2 mendokumenkan set arahan x86). dan merujuknya pada bila2 masa semasa menulis kod asm. Dalam SoftIce pun kita bleh gak tengok panduang arahan2 asm dengan command opcode. Satu perkara yang paling penting adalah walaupun terdapat banyak arahan2 yang bleh digunakan, tak semestinya kita kena tau dan guna semuanya. Tapi tu dalam pengaturcaraan laa. Semasa menganalisis program kita akan melihat bermacam jenis arahan dan dengan mempelajari semer arahan yang disokong oleh CPU akan memudahkan kita dalam proses analisis. Aku akan citer mengenai arahan2 lain jugak lepas ni semasa kita perlu menggunakannya. Untuk itu meh kita belajar plak camne kita bleh gunakan arahan2 ni untuk membina program. Semasa menulis kod program dengan asm, kita bebas mengatur kod dan data dalam program. Kuasanya kat tangan kita. Samada program tersebut mempunyai kesilapan semasa dilaksanakan tak kesahlaa.. selagi assembler bleh menterjemahkan kod sumber asm kepada program binari, ia pasti akan dilakukan. Ini memaksa kita, sebagai pengaturcara asm, memastikan yang kita menulis kod program dengan betul, baris demi baris. Dalam procedural language cam C, program dibahagikan kepada unit2 tugas yang kita panggil sebagai fungsi. HLLs lain plak ader yang memanggilnya sebagai prosedur, rutin, atau subrutin, tapi basically semer menatang ni sama jer. Setiap kod program yang hendak dilaksanakan oleh CPU perlu diletakkan dalam fungsi. Kiranya fungsi ni bleh laa kita katakan sebagai 'container' untuk kod laa. Takde kod program yang bleh diletakkan kat luar aper2 fungsi. Kalau dalam asm, setiap baris kod asm kita bleh kata sebagai unit tugas, tapi dalam procedural language, semer kod kena duduk dalam fungsi. Setiap fungsi plak bleh menerima 0 atau lebih parameter yang mempengaruhi tugasnya (analoginya sama laa dengan arahan asm yang terima 0 atau lebih pengoperasi). Parameter ni biasanya kita panggil sebagai argument. Fungsi jugak bleh mengembalikan nilai (biasanya satu sahaja). Sebagai contoh, jika kita perlu menulis program untuk memanipulasi data dalam disk, kita bleh bahagikan program kita kepada unit2 tugas yang menerima input (e.g nama fail untuk dimanipulasi), membuka fail tersebut, menulis ke dalam fail, membaca data di dalam fail, dan juga fungsi yang memaparkan data ke skrin komputer. Setiap fungsi ni bleh dipanggil dari satu fungsi utama di mana program kita bermula. Katakan kita nak manipulasi data pelajar dalam kelas. Sebagai permulaan, kita bleh wakili program tersebut dengan pseudocode berikut :
FUNGSI MULA
  PILIHAN = PANGGIL FUNGSI MENU
  JIKA PILIHAN == 1
   PANGGIL FUNGSI DATA_MASUK
  JIKA PILIHAN == 2
   PANGGIL FUNGSI DATA_KELUAR
  JIKA PILIHAN == 3
   PANGGIL FUNGSI PAPARKAN_DATA
  JIKA PILIHAN == 4
   PANGGIL FUNGSI KELUAR_PROGRAM
  TAMAT JIKA
TAMAT FUNGSI
Fungsi MULA mewakili "badan" utama program kita di mana fungsi2 lain dipanggil. Fungsi MENU mempunyai tugasnya tersendiri iaitu untuk memaparkan pilihan yang bleh dilakukan oleh pengguna program komputer ni dan juga menerima pilihan yang dibuat oleh pengguna. Kemudian nilai yang dipulangkan oleh fungsi MENU diletakkan dalam pembolehubah PILIHAN dan pembolehubah ni diperiksa pada kod2 seterusnya. Kita bleh tulis plak fungsi MENU seperti berikut :
FUNGSI MENU
 PAPARKAN TEKS "1. Masukkan Data Pelajar."
 PAPARKAN TEKS "2. Lihat Data Pelajar."
 PAPARKAN TEKS "3. Lihat Semua Data Pelajar."
 PAPARKAN TEKS "4. Tamat Program."
 PANGGIL FUNGSI TERIMA_KEKUNCI
 PULANGKAN KEKUNCI
TAMAT FUNGSI
Note that contoh kod di atas ditulis dengan pseudocode. Kiranya kod tipu2 laa ni. Kita tak compile kod camni dan tujuannya cuma untuk memberikan kita idea atau formula mengenai satu2 algoritma. Ia berubah-ubah mengikut sesiapa yang menulisnya, asalkan dia bleh paham cukuplaa.. Tapi biasanya mudah jugak memahami kod pseudocode yang ditulis orang lain. Kalau kita tulis dalam bahasa aturcara sebenar, kena laa ikut sintaksis bahasa tersebut. Contohnya dalam C, fungsi MENU akan ditulis seperti berikut :
char MENU() {
   printf("1. Masukkan Data Pelajar.\n");
   printf("2. Lihat Data Pelajar.\n");
   printf("3. Lihat Semua Data Pelajar.\n");
   printf("4. Tamat Program.\n");
   printf("Pilihan anda : ");
   return getchar();
}
Tu sintaksis untuk menulis fungsi dalam bahasa C. Ringkasnya setiap fungsi dalam C mempunyai format berikut :
<jenisPulangan> <namaFungsi>(<parameter>)
di mana <jenisPulangan> adalah jenis data seperti yang disokong dalam C, dalam contoh di atas, kita gunakan jenis data char; <namaFungsi> adalah nama fungsi tersebut, e.g MENU; <parameter> plak adalah argument yang diperlukan oleh fungsi tersebut. Ianya terdiri daripada dua bahagian iaitu jenis data dan nama rujukan argument tersebut. Semasa membina program dengan asm kita bleh abaikan penggunaan fungsi sebab kod asm tu sendiri adalah unit tugas. Tapi pada kebanyakan masa, kod program kita jugak perlu berinteraksi dengan kod program yang ditulis oleh orang lain. Sebagai contoh, kita perlu menggunakan fungsi yang disediakan oleh OS untuk memanipulasi fail atau memaparkan data ke skrin. Dengan itu kita perlu tau bagaimana kita bleh menstrukturkan kod program asm dengan menggunakan fungsi. Pertama sekali kita perlu tau yang setiap data yang dihantar sebagai parameter kepada suatu fungsi dan juga data yang dipulangkan oleh suatu fungsi memerlukan storan. Kedua-dua fungsi yang berinteraksi (yang memanggil dan yang dipanggil) perlu bersetuju menggunakan lokasi storan yang sama untuk menyimpan dan mengambil data. Kita sebenarnya bleh menggunakan bermacam-macam kaedah untuk menghantar parameter dan memulangkan nilai dari suatu fungsi. Kaedah yang digunakan untuk menghantar parameter kepada fungsi dan mengembalikan nilai dari suatu fungsi kita panggil sebagai konvensyen panggilan (calling convention). Satu cara untuk memastikan kita bleh memanggil fungsi yang disediakan oleh OS dengan betul adalah dengan memahami konvensyen panggilan yang dipatuhi oleh fungsi tersebut. Sebelum kita mengenali beberapa konvensyen panggilan yang piawai, meh kita cuba melihat konsep fungsi dari perspektif asm. Basically, fungsi hanyalah satu lokasi memori yang mengandungi kod fungsi tersebut. Bila kita panggil suatu fungsi, perlaksanaan kod berpindah kepada lokasi tersebut. Dalam FASM, setiap label kod adalah lokasi memori, jadik kita bleh gunakan label kod sebagai permulaan fungsi. Kita jugak ader beberapa cara untuk memindahkan perlaksanaan kod, seperti yang aku citer kat atas tadi. Tapi yang paling sesuai digunakan untuk memanggil suatu fungsi adalah arahan CALL, sebab ia bukan sahaja memindahkan perlaksanaan kod seperti JMP, tapi jugak meletakkan alamat selepas arahan CALL ke atas stack. Fungsi yang dipanggil bleh mendapatkan alamat ni dari stack untuk digunakan sebagai alamat untuk "kembali" kepada fungsi yang memanggilnya. Meh kita define satu fungsi Add yang menerima 2 parameter iaitu nilai yang perlu ditambah dan memulangkan hasil tambah 2 parameter ni.
Add :
  mov ecx, ?
  mov eax, ?
  add eax, ecx
  mov ?, eax
  ret
Label Add mewakili nama fungsi Add jadik kod pada lokasi lain bleh menggunakan arahan call Add untuk memanggil fungsi ni. Kod di bawahnya adalah "isi" fungsi tersebut dan kita akhiri fungsi Add ni dengan arahan asm ret. Masalahnya sekarang kita tak tau kat maner kedua-dua parameter dihantar dan kat mana kita nak letakkan hasil tambah (nilai pulangan), seperti yang ditanda dengan simbol ? pada kod di atas. Masalah ni diselesaikan bila kita bersetuju menggunakan satu calling convention yang sama antara fungsi2 yang berinteraksi. Sebagai contoh, fungsi Add bleh menerima parameter pertama pada register ECX dan parameter kedua pada register EDX dan memulangkan nilai pada register EAX, jadi fungsi Add menjadi seperti berikut :
Add :
 mov eax, edx
 add eax, ecx
 ret
Semasa fungsi Add dipanggil, atau lebih tepat lagi semasa perlaksanaan kod berpindah pada label Add, register ECX dan register EDX mengandungi 2 parameter tersebut. Jadi arahan mov eax, edx menyalin parameter kedua kepada register EAX dan menambahkan nilai parameter pertama kepadanya dengan arahan mov eax, ecx. Oleh kerana register EAX digunakan untuk menyimpan nilai pulangan, maka kita bleh laa kembali kepada pemanggil dengan arahan ret. Kod yang memanggil fungsi Add akan kelihatan seperti berikut (tambah 1 dan 2) :
mov  ecx, 1
mov  edx, 2
call Add
Menggunakan register untuk menghantar parameter mempunyai kelebihan, iaitu ia lebih pantas berbanding menggunakan memori. Tapi seperti yang kita tau, kita cuma mempunyai sedikit sahaja GPRs. Menyimpan nilai pulangan ke register ok laa kot sebab fungsi biasanya hanya perlu pulangkan satu nilai. Tapi camne kalau kita nak hantar banyak parameter kepada satu2 fungsi? Salah satu jawapannya adalah dengan menggunakan stack. Aku dah citer sedikit sebanyak mengenai stack dan bagaimana ia berfungsi. Kat sini kita citer camne stack digunakan sebagai storan untuk menghantar parameter ke fungsi. Sebelum tu kita kena ingat yang arahan CALL dan RET jugak menggunakan stack secara automatik. Maknanya kita perlu pastikan stack berada dalam keadaan yang seimbang. Arahan PUSH bleh digunakan untuk menghantar parameter melalui stack. Meh kita tengok fungsi Add tadi. Jika kita nak hantar data ke fungsi ni melalui stack, kita akan lakukannya seperti berikut :
push 1
push 2
call Add
Rajah berikut menunjukkan keadaan stack selepas setiap arahan dilaksanakan (ESP adalah stack pointer, dan assume ia menunjuk ke lokasi 100)
    [b]<sebelum push 1>[/b]

    ------- n
       .
       .
    ------- 108
       ?
    ------- 104
       ?
    ------- 100 <-ESP
       ?
    ------- 96
       ?
    ------- 92
       .
       .
    ------- 0
     [b]<selepas push 1>[/b]

    ------- n
       .
       .
    ------- 108
       ?
    ------- 104
       ?
    ------- 100
       1
    ------- 96 <-ESP
       ?
    ------- 92
       .
       .
    ------- 0
     [b]<selepas push 2>[/b]

    ------- n
       .
       .
    ------- 108
       ?
    ------- 104
       ?
    ------- 100
       1
    ------- 96
       2
    ------- 92 <-ESP
       .
       .
    ------- 0
Dan apabila arahan call Add dilaksanakan, perlaksanaan kod berpindah ke fungsi Add dan struktur stack pada masa itu akan menjadi:
     [b]dalam fungsi Add[/b]

    ------- n
       .
       .
    ------- 108
       ?
    ------- 104
       ?
    ------- 100
       1
    ------- 96
       2
    ------- 92
     alamat
     kembali
    ------- 88 <-ESP
       .
       .
    ------- 0
Seperti yang kita dapat lihat, dalam fungsi Add kita bleh menggunakan register ESP untuk mendapatkan parameter yang dihantar dan jugak alamat untuk kembali kepada kod yang memanggil kita. Kita bleh merujuk kepada parameter pertama dengan [ESP+8] dan parameter kedua dengan [ESP+4]. Oleh kerana sekarang parameter telah dihantar dengan stack, maka kita bleh ubah fungsi Add menjadi :
Add :
 mov eax, [esp+8];dapatkan parameter pertama
 mov ecx, [esp+4];dapatkan parameter kedua
 add eax, ecx
 ret
Semasa arahan RET dilaksanakan, nilai kat atas stack (iaitu alamat kembali) akan di"pop" . Jadi, selepas kembali dari fungsi Add kepada arahan selepas call Add (tak ditunjuk), struktur stack akan jadik seperti berikut :
     [b]selepas arahan RET[/b]

    ------- n
       .
       .
    ------- 108
       ?
    ------- 104
       ?
    ------- 100
       1
    ------- 96
       2
    ------- 92 <-ESP

    ------- 88
       .
       .
    ------- 0
Note that untuk memastikan interaksi antara fungsi berlaku dengan betul, kita perlu pastikan stack berada dalam keadaan yang seimbang, iaitu nilai ESP sebelum satu fungsi dipanggil adalah sama dengan selepas fungsi tersebut kembali. Dalam satu2 fungsi kita juga mungkin memanggil fungsi2 lain, dan ini sudah semestinya menggunakan stack. Selagi kita bleh pastikan stack berada dalam keadaan seimbang, fungsi akan dipanggil dan kembali dengan betul. Perhatikan jugak jika kita gunakan ESP untuk akses parameter dalam stack, kedudukannya bleh berubah jika kita menggunakan arahan2 yang mengubah ESP secara automatik (e.g PUSH, POP, CALL dan sebagainya). Sebagai contoh jika kita "push" suatu data ke dalam stack dalam fungsi Add seperti berikut :
Add :
 mov eax, [esp+8]
 push 0
 mov ecx, [esp+4]
 add eax, ecx
 ret
Arahan mov ecx, [esp+4] tidak lagi merujuk kepada parameter kedua. Oleh sebab tu kita biasanya gunakan satu lagi register sebagai titik rujukan tetap dalam stack yang merupakan nilai ESP semasa berada di awal suatu fungsi. Maknanya register ni menunjuk kepada alamat kembali kepada kod yang memanggil fungsi tersebut. Titik rujukan ni kita panggil sebagai stack-frame base pointer dan secara piawainya, register EBP digunakan untuk menyimpan titik rujukan ni. Untuk menggunakan stack-frame base pointer ni, kita salin dulu nilai pada register ESP kepada register EBP sebelum menggunakan arahan2 yang memanipulasi stack. Then bila kita nak kembali dari fungsi, kita akan restore kembali nilai ESP dengan menggunakan nilai asalnya yang kita telah simpan ke dalam register EBP. Fungsi Add bleh ditulis semula seperti berikut :
Add :
 mov ebp, esp
 mov eax, [ebp+8]
 mov ecx, [ebp+4]
 add eax, ecx
 mov esp, ebp
 ret
Dengan menggunakan stack-frame base pointer, kita sentiasa bleh rujuk parameter dengan menggunakan cara yang sama. Terdapat beberapa calling convention yang biasa digunakan dalam HLLs dan jugak OS seperti Windows dan Linux. Aku akan terangkan lagi mengenai calling convention ni bila kita melakukan analisis ke atas program. Tapi kalau korang nak bacer lebih details mengenainya, bleh laa baca dokumen yang ditulis oleh Agner Fog bertajuk Calling conventions for different C++ compilers and operating systems. Bleh cari kat www.agner.org. Yang paling penting untuk diketahui adalah stdcall yang digunakan oleh Windows API, cdecl yang digunakan oleh C compiler dan juga sesetengah Windows API dan fastcall yang biasa diguna dalam object-oriented program. Abis pasal parameter. Aku nak citer pasal local variable (pembolehubah setempat) dan global variable (pembolehubah global) plak. Local variable adalah variable yang hanya bleh diakses oleh satu fungsi di mana variable tersebut diisytiharkan, manakala global variable adalah variable yang bleh diakses oleh mana2 fungsi. Sebenarnya dua2 jenis variable ni takde beza. Dua2nya duk kat dalam memori. Kita isytiharkan global variable dalam kod asm dengan menggunakan arahan2 pengisytiharan data FASM iaitu db, rb dan sebagainya. Jadual di bawah menunjukkan arahan2 ni :
    Arahan takrifan data      Arahan tempahan data     Saiz (byte)
    ====================      ====================     ==========
             db                       rb                   1

             du                       rw                   2
             dw

             dd                       rd                   4

             dp                       rp                   6
             df                       rf

             dq                       rq                   8

             dt                       rt                   10
Arahan2 tempahan (simpanan) data kita gunakan untuk "tempah" storan memori yang kita tak beri nilai awal (uninitialized data). Penggunaan arahan2 ni biasanya didahului dengan label supaya ia bleh dirujuk dalam kod asm. Setiap arahan2 d* bleh diikuti dengan nilai awal ataupun simbol ? yang menandakan nilai awalnya tidak penting. Manakala arahan2 r* plak perlu diberikan saiz storan memori yang ditempah. Contohnya :
hasilTambah dd ?

 mula:
 push 1
 push 2
 call Add
 mov [hasilTambah], eax
 ret
Label hasilTambah digunakan untuk merujuk kepada pembolehubah bersaiz 4 byte. Ia jugak bleh ditulis seperti berikut :
hasilTambah rd 1
atau
hasilTambah dd 0
yang memberikan nilai awal pembolehubahubah hasilTambah sebagai 0. Global variable, secara ringkasnya blehlaa kita katakan sebagai variable yang bleh dirujuk oleh mana2 kod dan ia bleh terletak di mana sahaja dalam memori. Bagaimana plak kita isytiharkan local variable? Jawapannya adalah dengan menggunakan stack jugak. Penggunaan stack memang sesuai dengan konsep local variable sebab sebaik sahaja kita keluar dari fungsi ini, ia takleh dirujuk oleh fungsi lain. Kita bleh allocate local variable dengan menolak nilai dari register ESP kepada saiz yang diperlukan untuk local variables. Untuk memahami konsep ni, meh kita tengok contoh screenshot dari IDA kat post pertama dulu, iaitu salah satu fungsi dalam game Minesweeper :
.text:01003D1D sub_1003D1D     proc near              ; CODE XREF: sub_1001BC9+32Cp
.text:01003D1D
.text:01003D1D Buffer          = word ptr -200h
.text:01003D1D szOtherStuff    = word ptr -100h
.text:01003D1D
.text:01003D1D                 push    ebp
.text:01003D1E                 mov     ebp, esp
.text:01003D20                 sub     esp, 512
.text:01003D26                 push    esi
.text:01003D27                 mov     esi, 128
.text:01003D2C                 push    esi            ; nBufferMax
.text:01003D2D                 lea     eax, [ebp+Buffer]
.text:01003D33                 push    eax            ; lpBuffer
.text:01003D34                 push    12             ; __int16
.text:01003D36                 call    sub_10039E7
.text:01003D3B                 push    esi            ; nBufferMax
.text:01003D3C                 lea     eax, [ebp+szOtherStuff]
.text:01003D42                 push    eax            ; lpBuffer
.text:01003D43                 push    13             ; __int16
.text:01003D45                 call    sub_10039E7
.text:01003D4A                 push    100            ; lpIconName
.text:01003D4C                 push    hInstance      ; hInstance
.text:01003D52                 call    ds:LoadIconW
.text:01003D58                 push    eax            ; hIcon
.text:01003D59                 lea     eax, [ebp+szOtherStuff]
.text:01003D5F                 push    eax            ; szOtherStuff
.text:01003D60                 lea     eax, [ebp+Buffer]
.text:01003D66                 push    eax            ; szApp
.text:01003D67                 push    hWnd           ; hWnd
.text:01003D6D                 call    ds:ShellAboutW ; Display a Shell About dialog box
.text:01003D73                 pop     esi
.text:01003D74                 leave
.text:01003D75                 retn
.text:01003D75 sub_1003D1D     endp
Arahan push ebp menyimpan nilai asal register EBP dan kemudian menggunakan register EBP sebagai stack-frame base pointer dengan arahan mov ebp, esp. Kemudian kita allocate 512 bytes local variables dengan arahan sub esp, 512. Selepas arahan sub esp, 512 ni, stack akan kelihatan seperti berikut :
  -------------------- +ve
         ??
  -------------------- +8
    <alamat kembali>
  -------------------- +4
       <EBP asal>
  -------------------- <-- EBP

       512 bytes
     local variable

  -------------------- <-- ESP
          ??
  -------------------- -ve
Oleh itu, suatu fungsi yang set up ESP dan EBP camni blehlaa akses parameter dengan offset positif dari EBP, bermula dari offset +8, dan mengakses local variable dengan offset negatif dari EBP. Kat akhir fungsi sub_1003D1D kita ader arahan LEAVE. Basically tugas arahan ni blehlaa disamakan dengan turutan arahan berikut :
mov esp, ebp
pop ebp

yang mengembalikan keseimbangan stack seperti sediakala.

Aku harap korang faham laa penggunaan stack sebagai tempat simpanan sementara untuk parameter dan jugak local variable sebab semer HLLs gunakannya. Begitu jugak Windows.

Bahagian 1.2 : Pengaturcaraan Windows

intro

Windows, seperti yang kita semer sedia maklum adalah sistem operasi (OS) yang dibangunkan oleh Microsoft untuk PC (khususnya). Actually Windows bukanlah OS pertama dari Microsoft. Sebelum tu diaorang ader DOS (Disk Operating System), yang dijual dengan nama MS-DOS. Maser IBM nak cari OS untuk first IBM PC dulu sebenarnya IBM nakkan CP/M (Control Program for Microcomputers) yang dibangunkan oleh Digital Research (DR). Tauke DR maser tu Gary KilDall. Tapi encik Gary ni takut plak IBM akan amik alih CP/M ni.. lagipun DR maser tu bleh kira company yang stabil, takde masalah. So dia pun reject laa offer dari IBM. Tak dapat laa IBM nak guna CP/M kat PC. Then nak dijadikan sejarah, muncul laa plak Bill Gates dengan company dia Microsoft (maser tu company ni kecik je laa). Memandangkan IBM masih tengah tercari-cari OS, encik Gates pun offer IBM dengan OS yang lebih kurang sama dengan CP/M, tapi ditambah lagi dengan ciri2 yang IBM nak. So, mulalah perbincangan bisnes antara Microsoft dan IBM yang telah melakar sejarah penting dalam industri PC. Antara persetujuan yang telah dicapai adalah IBM bleh pasarkan DOS (dengan nama PC-DOS) bundled sekali dengan IBM PC, dan pada masa yang sama Microsoft pun bleh pasarkan DOS (dengan nama MS-DOS). So, dengan tu saper2 bleh buat komputer cam IBM PC dan gunakan MS-DOS sebagai OS. Oleh kerana MS-DOS lebih kurang sama jer ngan PC-DOS (compatible laaa), komputer yang merupakan klon IBM PC bleh run program yang sama yang dibina untuk IBM PC dan PC-DOS.

PC dulu2 guna Intel 8088 sebagai CPU. Ni CPU 16-bit dan ader address bus bersaiz 20-bit, yang bermakna ia bleh alamatkan lokasi memori bersaiz 2^20 (0 hingga 2^20-1), atau 1 MiB. Dalam program, alamat memori diakses dengan menggunakan dua bahagian, iaitu dalam bentuk segment pointer dan offset dalam segmen tersebut, biasanya ditulis sebagai segment:offset. Segment pointer dan offset adalah bersaiz 16 bit kedua-duanya. Sudah tentu secara fizikalnya address adalah linear, jadi segment pointer dan offset ni diterjemahkan kepada linear address dengan formula segment*16+offset. Contohnya alamat 0x07C0:0x0000 akan ditukarkan kepada linear address 0x07C0*16+0x0000 = 0x7C00. Walaupun CPU bleh alamatkan 1 MiB lokasi memori, PC dulu2 takde plak ader physical memori banyak camtu. First PC dulu cuma ader 64 KiB memori. Maser IBM design PC dulu, diaorang reserved 384 KiB alamat memori untuk kegunaan diaorang (e.g untuk hardware), so program cuma ader 640 KiB alamat memori yang bleh digunakan. Tapi lama kelamaan program jadik semakin canggih dan perlukan memori yang lebih banyak. PC pun ditambah memori yang lebih banyak... sampai laaa lebih daripada 640 KiB. Oleh kerana DOS cuma bleh alamatkan 640 KiB lokasi memori, yang selebihnya tu dia takleh nak akses. Begitu jugak dengan program2 lain. Dan dengan sebab tu muncul laa spesifikasi untuk menyelesaikan masalah nak akses physical memory yang berlebihan ni. Yang pertama adalah EMS (Extended Memory Specification) dan yang kedua adalah XMS (Expanded Memory Specification). Tapi ni semer citer dulu2 jadik aku taknak laa citer lebih banyak pasal spesifikasi ni.

DOS seperti yang kita tau mempunyai antaramuka pengguna berasaskan teks atau dipanggil sebagai antaramuka baris arahan (command line interface). Bila Mac yang mempunyai antaramuka pengguna berasaskan grafik (Graphical User Interface, GUI) jadik popular, Microsoft pun taknak mengalah gak. So diaorang pun develop OS yang mempunyai GUI, yang kita kenali sekarang sebagai Windows. First version keluar dulu maser aku baru nak masuk sekolah rendah. Basically Windows maser tu adalah DOS yang dimekap. Rasanya Windows tak terkenal sehinggalah versi 3.x keluar. Semer orang nak guna Windows yang ni. Aku pun suka gak. Tapi aku cuma suka main game :). Yang bestnya dengan Windows kita bleh run lebih dari 1 program pada satu2 masa, keupayaan yang kita panggil sebagai "multitasking". Tapi multitasking Windows dulu2 tak sama dengan yang sekarang. Windows sebelum 95/NT dulu gunakan konsep "coorperative multitasking". Dengan "coorperative multitasking" program yang tengah run kena give-up kawalan CPU kepada program lain secara sukarela. Kalau program tu tak serahkan, program lain kena tunggu laa sampai dia terminate dan ni dah tentu bleh menyebabkan hang (sebab OS pun takleh nak buat aper2).

Windows versi sebelum 95/NT adalah Windows 16 bit. Windows 95/98/ME/NT/2000/XP dan maner2 Windows yang memerlukan at least CPU 32 bit adalah Windows 32 bit. Actually Windows 95/98/ME bukanlah Windows 32 bit dalam ertikata sebenar-benarnya. Oleh kerana ia adalah kesinambungan dari pembangunan DOS dan Windows 16 bit, masih terdapat komponen-komponen 16 bit dalam kod OS Windows 95/98/ME. Hanya Windows yang berasaskan kernel NT adalah Windows 32 bit yang sebenar. NT asalnya dibangunkan untuk digunakan dalam workstation, network server atau komputer yang memerlukan OS yang power laa. Pendek kata, pengguna PC memang tak guna laa NT ni. Tidak sehingga Windows XP dihasilkan. XP, dengan menggunakan kernel NT direka untuk desktop PC dan jugak komputer yang berfungsi sebagai server. Kat sini aku rujuk Windows 95/98/ME dengan nama Win9x dan Windows berasaskan NT sebagai WinNT. Win9x dan WinNT secara umumnya aku ringkaskan sebagai Win32.

bersambung ...

Share this post


Link to post
Share on other sites

C. Operasi aritmetik binari

Arahan2 dalam kategori ni menggunakan flags untuk memberi petunjuk mengenai hasil operasi di mana semuanya menggunakan SF untuk menyatakan samada hasil pada destinasi adalah nombor negatif (set) atau tidak (clear); ZF digunakan untuk menyatakan samada hasil pada destinasi adalah 0 (set) atau tidak (clear), OF digunakan untuk menyatakan samada hasil pada destinasi terlalu besar untuk nombor positif atau negatif (tak termasuk signed bit) (set) atau tidak (clear), PF plak digunakan untuk menyatakan samada 8 bit terkecil hasil pada destinasi mengandungi bilangan bit 1 yang genap (set) atau tidak (clear).

[*]ADD

Arahan ni menambah 2 pengoperasi (destinasi=destinasi+sumber) di mana CF akan disetkan jika berlaku overflow (carry) dan clear sebaliknya. Peraturan untuk pengoperasinya sama jer ngan arahan MOV. Contoh :

  ADD ESP, 24
  ADD BYTE [EAX], CL
  
[*]SUB Arahan ni kita guna untuk menolak 2 pengoperasi (destinasi=destinasi-sumber) di mana CF akan disetkan jika berlaku overflow (borrow) dan clear sebaliknya. Peraturan untuk pengoperasinya sama jer ngan arahan MOV. Contoh :
  SUB EAX, EAX
  SUB ECX, 1
  
[*]MUL Arahan ni adalah untuk operasi pendaraban ke atas 2 pengoperasi (nombor tak bertanda). Tapi kita cuma berikan satu pengoperasi jer iaitu sumber, sebab destinasinya dianggap adalah AX, atau gabungan DX:AX atau EDX:EAX. Ia berfungsi camni.. kalau kita berikan satu pengoperasi bersaiz byte, maka ia didarabkan dengan nilai pada register AL dan hasilnya diletakkan pada register AX (AX=AL*sumber). Kalau kita berikan pengoperasi bersaiz word, maka ia didarabkan dengan nilai pada register AX dan hasilnya diletakkan pada register DX dan AX (DX:AX=AX*sumber), dan kalau kita berikan pengoperasi bersaiz dword, maka ia didarabkan dengan nilai pada register EAX dan hasilnya diletakkan pada register EDX dan EAX (EDX:EAX=EAX*sumber). Contoh :
  MUL BX            ;DX:AX=AX*BX
  MUL BYTE [EAX];AX=AL*nilai pada lokasi yang ditunjuk oleh EAX
  

[*]DIV

Arahan ni adalah untuk operasi bahagi ke atas nombor tak bertanda. Peraturan

dalam banyak-banyak ni, dalam binary punya topic, tak nampak pun mention pasal LSB ngan MSB, buleh terangkan sekali tak ?

mengapa "os lain takda umph" ? bleh declare tak kat mana yg takda "umphh" tu ? takda umph sebab takda tools macam resource penggodam ? atau kelabu mata nak tengok output dari gdb ?

soalan ni hanya untuk melegakan hati saya yg gak keliru. :)

Share this post


Link to post
Share on other sites

pasal os umpph ke tak tu terpulang la kepada sesiapa yg nak menafsirkan sendiri. tunggu sahaja jawapan dari penulis.

jika perasa *nix umpph kepada anda, 'unggulekey nalladey' :).

bagi aku plak yg tak berapa reti os design ni, aku rasa windows platform ada ummpph nya jugak :D. dari segi kernel - memory, multitasking, process manager, filesystem; mungkin *nix lagi berkuasa. tapi kelebihan windows ni kat gui system dia yg embedded kat the whole os tu sendiri. mac plak bergantung kat hardware dia sendiri, dan hardware apple ni luxury item utk sekadar kegunaan peribadi bagi aku. no comment.

p/s: unggulekey nalladey = good for u

Share this post


Link to post
Share on other sites

aduss tlepas kelas aritu kene rewind balik la nehh....mana cikgu kita tak masuk lagi?

Share this post


Link to post
Share on other sites

umpphh atau tidak actually adalah personal opinion.. why use gdb kalau kita ader very powerful visual-based debugger?? yang nyatanya bukan sebab ader resource h@cker sebab menatang ni bleh buat sendiri dengan mudah :)..

Share this post


Link to post
Share on other sites

[nota]
. sebelum aku teruskan dengan pengaturcaraan, aku terangkan lebih lanjut lagi mengenai LSB/MSB. LSB/MSB kat sini merujuk kepada
least significant byte
(bait bermakna terkecil) dan
most significant byte
(byte bermakna terbesar), masing2. Bila kita tulis nombor matematik, kita letakkan digit yang terkecil (sa) kat sebelah kanan sekali, diikuti oleh puluh, ratus, ribu dan seterusnya. Sebagai contoh, dalam nombor
1234567890
, angka 1 adalah digit bermakna terbesar, manakala angka 0 adalah digit bermakna terkecil. Bila kita mewakili nombor dalam binari, bit kat kanan sekali kita panggil sebagai bit bermakna terkecil (least sigificant bit) manakala yang kat kiri sekali kita panggil sebagai bit bermakna terbesar. Oleh kerana dalam komputer kita mempunyai beberapa jenis data (saiz) yang berbeza, setiap jenis data mempunyai bit/byte bermakna terbesar pada lokasi yang berlainan. Sebagai contoh, satu nombor bersaiz 1 byte, 10101000b mempunyai bit bermakna terkecil = 0 dan bit bermakna terbesar = 1. Lokasi bit bermakna terbesar adalah pada bit 7 :

index>    7   6   5   4   3   2   1   0         ---------------------------------         | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |         ---------------------------------
kita takde MSB/LSB dalam data berjenis byte. Untuk nombor bersaiz 1 word, e.g 0xFFF0, atau 1111111111110000B, kita ader bit bermakna terbesar pada bit ke 15, iaitu 1. LSB untuk nombor ni adalah 0xF0 dan MSB plak adalah 0xFF. Tapi seperti yang aku dah bagitau sebelum ni, oleh kerana PC menggunakan format
little-endian
untuk simpan data dalam memori, maka jika nombor ni dilihat dalam memori, LSB nombor tersebut akan terletak pada lokasi memori yang lebih rendah, manakala MSB nombor tersebut akan terletak pada lokasi memori yang lebih tinggi, i.e dalam turutan 0xF0, 0xFF. Untuk nombor bersaiz 1 dword, 0x12345678, bit bermakna terbesar terletak pada bit 31. LSB nombor ni adalah 0x78 manakala MSB plak adalah 0x12. Dalam memori PC, ia akan kelihatan dalam turutan 0x78, 0x56, 0x34, 0x12. Senibina komputer yang lain plak ader yang menggunakan format
big-endian
untuk menyimpan nombor dalam memori, di mana LSB terletak pada lokasi memori yang lebih tinggi dan MSB terletak pada lokasi memori yang lebih rendah. So, bila dilihat dalam memori dengan sel bersaiz 1 byte, turutannya adalah sama seperti mana kita menulisnya, e.g nombor 0x12345678 akan dilihat sebagai 0x12, 0x34, 0x56, dan 0x78.
Processes dan Threads Windows, seperti yang kita semer sedia maklum, adalah sistem operasi multi-tugas (multitasking OS) di mana lebih dari satu tugas bleh dijalankan serentak. Realitinya, ni bukanlah multi-tugas dalam erti kata sebenar-benarnya. Untuk multi-tugas sebenar, kita perlukan komputer dengan lebih dari satu unit perlaksanaan kod, seperti komputer dengan multi-pemproses atau pemproses multi-teras (cam Intel nyer dual core), yang mampu melaksanakan lebih dari satu tugas serentak. Dalam komputer dengan sebijik pemproses (unipemproses), kita cuma bleh melaksanakan satu tugas pada satu2 masa. Windows mencapai keupayaan multi-tugas dengan membahagikan "masa CPU" (kuantum) untuk setiap tugas yang wujud pada satu2 masa. Penjadual tugas yang merupakan sebahagian dari teras sistem operasi bertanggungjawab menjadualkan unit2 tugas ni untuk dilaksanakan oleh CPU. Unit tugas ni laa yang kita panggil sebagai thread, so kita jugak sebut Windows sebagai multithreading OS. Penjadualan thread ni laa yang membolehkan Windows mewujudkan keadaan multi-tugas dalam komputer unipemproses dan ia kelihatan seolah-olah lebih dari satu thread bleh berjalan dengan serentak dalam sistem tersebut. Sebenarnya setiap thread cuma mempunyai giliran tempoh masa yang singkat (dalam unit milisaat) untuk dilaksanakan. Algoritma yang digunakan oleh penjadual untuk menjadualkan threads untuk perlaksanaan adalah Round-Robin. Biasanya walaupun wujud banyak threads dalam sistem pada satu2 masa, kebanyakannya thread ni berada dalam keadaan "tergantung" (suspended) iaitu tidak mendapat giliran untuk dijadualkan. Thread yang tengah berjalan plak, samada menyerahkan masa CPU walaupun masih dalam gilirannya atau disampuk perlaksanaannya oleh penjadual kerana gilirannya telah tamat, akhirnya akan digantung jugak dan threads lain yang menunggu giliran akan dijadualkan untuk perlaksanaan. Ni laa sebabnya Win32 dipanggil sebagai preemptive multitasking (multithreading) OS sebab threads yang tengah berjalan bleh digantung pada bila2 masa dan thread lain plak bleh dijadualkan. Ni berbeza dengan Windows dulu2, yang merupakan coorperative multitasking OS dan DOS yang merupakan single-tasking OS. Process plak, secara ringkasnya adalah container (bekas) untuk threads. Thread SENTIASA wujud dalam konteks satu process. Dalam sistem bleh wujud lebih dari satu process pada satu2 masa dan dalam process bleh wujud lebih dari satu threads pada satu2 masa. Note that process bukanlah entiti yang dijadualkan untuk perlaksanaan, tapi thread. Satu elemen yang ditakrifkan oleh process adalah ruang memori maya (virtual memori) linear sebanyak 4 GiB di mana threads dalam process tersebut dilaksanakan. Ruang memori ni dikongsi oleh semer threads dalam process tu, so basically setiap threads dalam satu process bleh berkongsi pembolehubah global yang sama. Setiap process dalam sistem mempunyai ruang memori mayanya yang tersendiri. Sebenarnya dengan mekanisme paging ruang memori maya ni bukanlah semernya unik - ader ruang yang yang dikongsi oleh semer process dan ader gak yang unik kepada setiap process. Contohnya, kod kernel dan pemacu perkakasan yang dimuatkan ke ruang memori 2 GiB ke atas dikongsi oleh semer process. Sebahagian dari memori pada ruang memori 2 GiB ke atas ni plak unik kepada setiap process (contohnya untuk maintain page tables untuk setiap process). Bila kita melaksanakan satu program, contohnya notepad.exe, kernel akan mencipta satu process baru untuk program ni dan memetakan modul (fail program) notepad ni ke ruang memori maya yang diperuntukkan untuk proses yang baru dicipta untuk notepad. Basically process ni kepunyaan program notepad laaa. Kalau program ni menggunakan modul lain (notepad mengimpot fungsi dari beberapa DLLs seperti kernel32.dll, user32.dll, shell32.dll, advapi32.dll, comctl32.dll dan lain2), setiap modul ni jugak dipetakan ke ruang memori dalam process yang sama dengan notepad tadi. Jika DLLs ni pun seterusnya mengimpot fungsi dari DLLs yang belum dimuatkan ke memori, semer DLLs tersebut jugak akan dimuatkan ke memori dalam process notepad tadi, sehinggalah smeernya dah dimuatkan ke memori (oleh kerana kod DLLs sistem biasa digunakan oleh semer program, sistem bleh menggunakan page tables yang sama untuk memetakan DLLs ni). Pada masa ni process tersebut takde thread lagi. Kemudian, satu thread yang kita panggil sebagai thread utama (main thread) akan dicipta dalam konteks process notepad ni di mana perlaksanaannya bermula pada entrypoint program kita (actually thread ni bukanlah mula kat sini, ia cuma dipanggil oleh thread utama yang bermula dalam kernel32.. tapi tak salah gak kalau sebut thread utama bermula pada entrypoint program kita). Kalau thread utama ni tak cipta thread baru (secara langsung atau tidak), maka ia adlaah satu-satunya thread yang wujud dalam process notepad tersebut. Jika ia kembali dengan arahan ret atau menamatkan perlaksanaannya menggunakan fungsi ExitThread, maka takde lagi laa thread yang wujud dalam process notepad ni. Process tanpa thread tak mendatangkan aper2 faedah (sebab takde kod yang dilaksanakan dalam process tersebut), so process ni akhirnya dimusnahkan oleh sistem dan memori yang digunakan untuk menyediakan ruang memori maya process tersebut akan diambil semula dan digunakan untuk tujuan yang lain plak. Secara umumnya, Windows membahagikan ruang memori maya linear bersaiz 4 GiB setiap process kepada 2 bahagian, iaitu untuk program biasa (user mode address space) sebanyak 2 GiB dalam julat 0x00000000 hingga 0x7FFFFFFF, dan jugak untuk kernel (kernel mode address space), jugak sebanyak 2 GiB dalam julat 0x80000000 hinggalah 0xFFFFFFFF. Secara kasarnya, ruang memori untuk program biasa dibahagikan kepada beberapa bahagian seperti berikut :
  • 0x00000000 - 0x0000FFFF - ruang alamat memori yang takleh dirujuk oleh thread dalam process. Tujuannya adalah untuk membolehkan penunjuk memori (pointer) bernilai 0 digunakan sebagai penanda bahawa penunjuk tersebut takleh digunakan. Ini biasa digunakan dalam pengaturcaraan. Contohnya, suatu fungsi yang bertugas untuk memperuntukkan ruang memori bleh memulangkan penunjuk kepada permulaan ruang memori yang baru disediakan ni. Jika penunjuk yang dipulangkan bernilai 0, kita tau bahawa fungsi tersebut tak dapat memperuntukkan ruang memori yang kita minta.
  • 0x00010000 - 0x7FFEFFFF - alamat 0x10000 adalah alamat asas yang digunakan secara default oleh sistem untuk memuatkan fail program yang dilaksanakan. Alamat asas ni disebut sebagai image base program tersebut dalam memori. Kita bleh nyatakan image base yang berbeza dalam pengepala PE untuk memberikan petunjuk kepada sistem untuk memuatkan program kita pada ruang memori pada alamat yang berbeza. Ia terpulang kepada sistem untuk mematuhi petunjuk ni atau tidak, jika tidak, alamat 0x10000 akan digunakan secara automatik. Tapi biasanya petunjuk ni akan dipatuhi kecuali alamat memori tersebut telahpun digunakan untuk memuatkan modul lain atau alamat yang diberikan sebagai petunjuk tidak sah. Kat sini jugak (dalam kawasan 0x70000000 - 0x78000000, lebih kurang laa) modul DLLs sistem yang biasa digunakan dimuatkan.
  • 0x7FFF0000 - 0x7FFFFFFF - ruang alamat memori ni jugak takleh diakses oleh program (sama laa cam ruangan memori 0 - 0xFFFF tadi).
Ruangan memori 0x80000000 ke atas adalah untuk kernel.. takleh sentuh dari program biasa, jadik kita bincangkan mengenainya dalam post yang kemudian. Note that program biasa takleh menyentuh ruang memori kernel ni. Ini membolehkan kod dan data sistem takleh diganggu oleh program biasa. Ruang memori yang unik untuk setiap process jugak membolehkan setiapnya terlindung daripada kerosakan yang dilakukan oleh satu sama lain. So kalau thread dalam satu proses mempunyai kesilapan, hanya process yang menjadi konteks thread ni akan terjejas, bukannya processes lain dalam sistem. Akses oleh satu process ke ruang memori process yang lain hanya bleh dilakukan dengan menggunakan Windows API yang disediakan, jika dibenarkan oleh sistem. Meh kita tengok screenshot kat bawah yang merupakan output dari Process Explorer dalam sistem aku : rce0600uw3.th.png Daripada output kat atas kita bleh nampak processes yang wujud dalam sistem kita dan pelbagai maklumat yang berkaitan. Dalam subwindow Process Explorer kat bahagia atas kita bleh dapatkan maklumat asas mengenai setiap process. Contohnya process procexp (process untuk Process Explorer ni) mempunyai PID = 19244. PID adalah Process Identifier, iaitu nombor pengenalan yang digunakan sebagai identiti process tersebut dan ia adalah unik. Setiap thread pun ader gak nombor pengenalan unik ni yang kita panggil sebagai TID (Thread Identifier). KIta bleh merujuk process atau thread dengan menggunakan PID atau TID ni. Note that Process Explorer jugak paparkan dua "pseudo-process" yang dinamakan dengan Interrupts dan DPCs (Deferred Procedure Calls. Actually ni bukanlah process. Nanti aku citer pasal ni bila kita sentuh pasal kernel Windows. Kat kolum Threads kita bleh nampak bilangan threads yang wujud dalam setiap proses tersebut. Kolum Path plak menunjukkan nama modul yang memiliki process tersebut. So, dari sini kita tau process smss.exe (Session Manager) dicipta hasil perlaksanaan program kat C:\WINDOWS\SYSTEM32\SMSS.EXE dan seterusnya. Perhatikan daripada cara item dalam kolum Process disusun menandakan hubungkait process ni antara satu sama lain. Process pertama yang dicipta dalam sistem adalah System Idle Process, yang kemudiannya mencipta process System. Kedua-duanya dicipta oleh kernel di awal permulaan sistem dan takde fail program yang terlibat dalam penciptaannya. Process System plak mencipta process smss.exe yang seterusnya plak mencipta process csrss.exe dan winlogon.exe. Process explorer.exe adalah "shell" untuk Windows, iaitu komponen yang bertanggungjawab menjadi antaramuka di antara pengguna dan OS. Kalau kita double click (atau right click dan pilih menu Properties...) mana2 process ni, satu dialog box yang memaparkan lebih banyak maklumat mengenai process tersebut akan dipaparkan. Perhatikan jugak kolum Page Faults. Ni sebenarnya sebahagian dari mekanisme paging dan ia sesuatu yang wajib berlaku dalam OS yang menggunakan paging yang disokong oleh x86. Bila2 masa kod program merujuk kepada alamat memori yang tak wujud dalam memori fizikal, page fault exception akan berlaku. Kod yang bertindak sebagai pengendali exception ni akan menentukan dari mana ia perlu muatkan page tersebut ke dalam memori fizikal, contohnya dari fail dalam cakera keras, atau dari lokasi memori fizikal yang lain. Lebih sikit page fault bermakna kebanyakannya ruang memori process tersebut sedang berada dalam memori fizikal atau CPU nyer cache. Subwindow kat bawah plak menunjukkan setiap modul yang dimuatkan ke dalam ruang memori maya process tersebut. Dalam output di atas, subwindow kat bawah tunjukkan modul-modul untuk process windbg.exe. Kolum Image Base adalah image base modul tersebut seperti yang dinyatakan dalam pengepala PE modul tersebut. Kolum Base plak tunjukkan image base sebenar di mana ia dimuatkan ke dalam memori. Note that 3 modul (yang diwarnakan kuning), srcsvr.dll, kdexts.dll dan ext.dll telah dimuatkan ke alamat yang lain daripada yang dinyatakan dalam pengepala PE. Keadaan ni dinamakan penempatan semula (relocation). Penempatan semula berlaku jika modul yang hendak dimuatkan ke memori tidak bleh dimuatkan kepada alamat yang dinyatakan sebagai image base modul tersebut dalam pengepala PE modul tersebut. Apabila penempatan semula berlaku, semer rujukan alamat memori yang menggunakan alamat mutlak tidak lagi sah kerana ia menggunakan alamat asas yang dah tak betul, dengan itu alamat mutlak yang dirujuk oleh kod program ni perlu di"tampal" oleh sistem. Maklumat yang menyenaraikan semer alamat mutlak yang dirujuk oleh kod program disimpan dalam modul tersebut dan jika penempatan semula perlu dilakukan, sistem akan cari dan proses maklumat ni untuk membetulkan kod program tersebut. Jika maklumat ni tak disediakan, Windows (jika flag Characteristics dalam pengepala PE tidak menyatakan maklumat penempatan semula dibuang) akan cuba memuatkan program tersebut pada image base yang baru dengan kod program yang tidak dibetulkan dan akan menyebabkan kesilapan jika kod menggunakan alamat memori mutlak dilaksanakan. Bleh jadik jugak (jika flag Characteristics dalam pengepala PE menyatakan maklumat penempatan semula dibuang) Windows tak akan memuatkan modul tersebut ke dalam memori dan program kita pun takleh laa jalan. Cuba ubahsuai kod program hello putera.com kita sebelum ni dengan mengubah arahan format pe gui kepada format pe gui at 0 yang menetapkan image base modul program kita kepada alamat 0 (yang tak sah) dan cuba compile dan run dan tengok aper yang jadik. Aku akan citer lebih lanjut mengenai penempatan semula bila kita bincang mengenai format PE dalam post akan datang. Daripada program Process Explorer kat atas kita bleh dapat banyak maklumat mengenai processes atau threads dalam sistem kita. Ini kerana Windows menyimpan pelbagai maklumat mengenai setiap process dan threads dalam struktur data yang kita panggil sebagai Process Environment Block (PEB) untuk process dan Thread Environment Block (TEB) untuk thread. Kita bleh memeriksa struktur ni untuk mendapatkan maklumat mengenai satu2 process atau thread tersebut. Semasa satu thread tengah dilaksanakan, sistem menggunakan register FS untuk menyimpan alamat linear TEB untuk thread tersebut. Dalam struktur TEB ni kita bleh dapatkan alamat linear ni jugak pada offset 0x18. Contohnya, arahan mov esi, [fs:0x18] akan menyalin alamat linear TEB thread tersebut ke register esi. Struktur TEB dan PEB ni tidak didokumenkan oleh Windows kerana ia bleh berubah dari satu versi Windows ke versi yang lain (namun demikian terdapat beberapa bahagian dalam struktur ni yang tetap untuk setiap versi, dan dalam kes ni ia akan didokumenkan jika ia berguna kepada pengaturcara, atau pembuat compiler). Kebanyakan maklumat dari TEB atau PEB bleh diminta melalui penggunaan Windows API. Hanya sebagai contoh, API GetModuleHandle (A/W) dengan parameter 0 akan memulangkan image base program kita dalam ruang alamat proses program kita (sila rujuk PSDK). Kod fungsi ni akan kelihatan seperti berikut :
GetModuleHandle:
  push  ebp
  mov   ebp, esp
  mov   eax, [ebp+4]
  test  eax, eax
  jnz   @f
;dapatkan image base untuk daripada PEB
  mov   eax, [fs:0x18]   ;dapatkan penunjuk TEB
  mov   eax, [eax+0x30]  ;dapatkan penunjuk PEB
  mov   eax, [eax+8]     ;dapatkan image base dari PEB
  jmp   .ret
;dapatkan image base untuk
@@:
  ..
  ..
.ret:
  pop   ebp
  ret   4

Ni kerana image base program dalam process kita disimpan dalam struktur PEB pada offset 8. Alamat linear struktur PEB plak bleh didapati dari struktur TEB pada offset 0x30. Aku akan citer lebih banyak mengenai struktur TEB dan PEB di lain waktu. Ni penting untuk mengetahui karakteristik sebenar thread dan process dalam Windows. So, aku tangguh laa dulu citer pasal thread priority, thread affinity, thread kernel object dan sebagainya sehinggalah lepas kita discuss pasal system level debugger di mana kita bleh memeriksa struktur2 ni dengan lebih details lagi...

Akhir sekali, untuk menjadualkan setiap threads dalam sistem, Windows perlu simpan senarai threads yang tengah wujud dalam sistem pada setiap masa dalam semer proses. Untuk menyimpan senarai ni ruang memori diperlukan untuk menyimpan data yang berkaitan dengan setiap thread, contohnya keadaan CPU (e.g nilai2 GPRs dan register lain, nilai EIP dan lain2) semasa thread tersebut digantung dan pelbagai maklumat lain. Begitu jugak dengan proses2 yang wujud perlu disimpan senarainya oleh sistem. Jika terlalu banyak threads yang perlu dikendalikan oleh penjadual, sistem akan menjadi lembab dan memori yang banyak jugak perlu digunakan untuk menyimpan stuktur data yang berkaitan. Dalam kes2 tertentu ini bleh membawa kepada skrin biru. Jadik semasa mereka dan membina program adalah penting untuk kita menggunakan lebih dari satu thread hanya jika diperlukan. Tapi dalam kebanyakan kes kita biasanya tak perlu mencipta thread baru dalam program.

bersambung ...

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...