Nama Lengkap : Teguh Prima Alko
Jenis Kelamin : Pria
Tempat, Tanggal
lahir : Pangkal Pinang, 2 Maret 1992
Kewarganegaraan : Indonesia
Status Hubungan : Belum Menikah
Tinggi , Berat : 175 cm , 73 kg
Agama : Islam
Alamat Lengkap : JL. R.H Fisabilillah No. 7 Tanjungpinang
Handphone : 081224746230
E-mail : teguh@cloudmail.de
RIWAYAT PENDIDIKAN
1998 – 2003 : SD Negeri 23 Tanjungpinang
2003 – 2006 : SMP Negeri 4 Tanjungpinang
2006 – 2009 : SMA Negeri 2 Tanjungpinang
2009 – 2016 : Universitas Komputer Indonesia, Fakultas Teknik dan Ilmu
Diajukan untuk Menempuh Ujian Akhir Sarjana
TEGUH PRIMAALKO 10109383
PROGRAM STUDI TEKNIK INFORMATIKA
FAKULTAS TEKNIK DAN ILMU KOMPUTER
iii
Sudah semestinya penulis berterimakasih kepada Allah Subhanahu wa
ta’ala yang telah memberikan energi untuk dapat menyelesaikan skripsi yang
berjudul “ANALISIS SELF-MODIFYING CODE MENGGUNAKAN
DYNAMIC BINARY INSTRUMENTATION”.
Maha kuasa Allah Subha nahu wa ta’ala telah mengirim anugerah dengan
orang-orang yang dapat menemani, membimbing dan mendukung
penyelesaian skripsi ini dengan cara yang sangat luar biasa. Untuk itu,
penulis ingin menyampaikan rasa terimakasih sebesar-besarnya kepada:
1. Ibunda penulis yang telah memberikan doa dan pengertian serta Suci A.
Ayu sebagai adik dari Penulis yang telah memberikan dukungan.
2. Bpk. Adam Mukharil Bachtiar, S.Kom., M.T., sebagai pembimbing
yang memotivasi dan memberikan pemahaman yang jernih kepada
penulis.
3. Adrian Negreanu dan Derek Bruening sebagai pengembang
DynamoRIO yang bersahabat dalam memberikan petunjuk
4. Aluh yang bersih keras agar Penulis tetap berjuang sampai lulus, Ipey
dengan nasihat dan konsep kedewasaanya, Domse yang selalu percaya
diri dengan absurdity-nya, Olih yang selalu menebar tawa ketika down,
Tetski dengan kelucuan emosionalnya dan Didiw sebagai sahabat
travelling dan refreshing ketika jenuh
5. Rekan-rekan seperjuangan skripsi yang ikhlas memberikan informasi
kepada Penulis yakni Rizkika Adam dan Arif serta Ali yang
memberikan cheer up dengan penuh determinasi
6. Yellow Truck, Bobber Cafe, Goethe-Institut, Double Eight Coffee dan
Caffetto atas ruang yang cozy dan kopi nikmatnya
iv
Bandung, 2 Maret 2016
v
ABSTRACT ... ii
KATA PENGANTAR ... iii
DAFTAR ISI ... v
DAFTAR GAMBAR ... viii
DAFTAR TABEL ... ix
DAFTAR LAMPIRAN ... xi
BAB I PENDAHULUAN ... 1
I.1 Latar Belakang Masalah ... 1
I.2 Perumusan Masalah ... 2
I.3 Maksud dan Tujuan Penelitian ... 2
I.4 Batasan Masalah ... 2
I.5 Metodologi Penelitian ... 3
I.6 Sistematika Penulisan ... 5
BAB II TINJAUAN PUSTAKA ... 7
II.1 Debugging ... 7
II.2 Macam-Macam Format Debugging ... 7
II.3 Instrumentation ... 8
II.4 Metode Binary Instrumentation ... 10
II.5 ELF ... 10
II.6 Self-Modifying Code ... 11
vi
II.11 Binary Analysis ... 19
II.12 Program Lifecycle Phase ... 20
II.12.1 Edit Time ... 20
II.12.2 Compile Time... 20
II.12.3 Link Time ... 20
II.12.4 Load Time ... 21
II.12.5 Run Time ... 21
II.13 Binary Translation ... 21
II.14 Intermediate Representation ... 21
BAB III ANALISIS SELF-MODIFYING CODE DAN PERANCANGAN DYNAMIC BINARY INSTRUMENTATION ... 23
III.1 Analisis Sistem ... 23
III.1.1 Analisis Masalah ... 23
III.1.2 Analisis Biner Program ... 23
III.1.3 Analisis Self-Modifying ... 24
III.1.4 Analisis Binary Translation ... 28
III.1.5 Analisis Sintaksis ... 30
III.1.6 Spesifikasi Intermediate Representation ... 41
III.1.7 Analisis Kebutuhan Non Fungsional ... 50
III.1.7.1. Analisis Perangkat Lunak ... 51
III.1.7.2. Analisis Perangkat Keras ... 51
vii
IV.1.1. Lingkungan Implementasi Sistem ... 63
IV.1.2. Implementasi Pembangunan Dynamic Binary Instrumentation ... 63
IV.1.3. Implementasi Pembuatan Random Test Case Generation ... 65
IV.2 Pengujian Sistem ... 65
BAB V KESIMPULAN DAN SARAN ... 75
77
Instrumentation,” in VEE '12 Proceedings of the 8th ACM SIGPLAN/SIGOPS conference on Virtual Execution Environments, New York, 2012.
[2] M. Probst, “Dynamic Binary Translation,” CD Laboratory for Compilation Techniques, 2003.
[3] N. Mavrogiannopoulos, N. Kisserli and B. Preneel, “A taxonomy of self -modifying code for obfuscation,” Computers and Security, vol. 30, no. 8, pp. 679-691, 2011.
[4] N. Nethercote, “Dynamic Binary Analysis and Instrumentation,” University of Cambridge Computer Laboratory, 2004.
[5] “The DynamoRIO API,” Google, 8 October 2015. [Online]. Available: http://dynamorio.org/docs/.
[6] K. Anand, M. Smithson, K. Elwazeer, A. Kotha, J. Gruen, N. Giles and R.
Barua, “A Compiler-level Intermediate Representation based Binary Analysis
and Rewriting System,” in EuroSys '13 Proceedings of the 8th ACM European Conference on Computer Systems, New York, 2013.
[7] “ELF,” OS Development, 7 August 2015. [Online]. Available: http://wiki.osdev.org/ELF.
[8] X. Xie, F. Liu, B. Lu and F. Xiang, “Mixed Obfuscation of Overlapping Instruction and Self-Modify Code Based on Hyper-Chaotic Opaque
[9] S. Blazy, V. Laporte and D. Pichardie, “Verified Abstract Interpretation Techniques for Disassembling Low-level Self-modifying Code,” in Interactive Theorem Proving, Springer International Publishing, 2014, pp.
128-143.
[10] B. Anckaert, M. Madou and K. D. Bosschere, “A Model for Self-Modifying
Code,” in Information Hiding, Springer Berlin Heidelberg, 2007, pp. 232-248.
[11] T. Touili, B. Cook and P. Jackson, “Computer Aided Verification,” in 22nd International Conference, CAV 2010, Edinburgh.
[12] N. M. Hai, M. Ogawa and Q. T. Tho, Obfuscation code localization based on
CFG generation of malware, Clermont-Ferrand: Springer, 2015.
[13] R. Mankadan, P. A. Kumar and R. Govindaraju, “CODE SECURITY BY
CONFUSING LOGIC FLOW USING SELF MODIFYING CODE,”
International Journal of Innovative Trends and Emerging Technologies, vol.
I, no. 2, 2015.
[14] J. Pogulis, “Generation of dynamic control-dependence graphs for binary
programs,” Linköping University, Department of Computer and Information
Science, Database and information techniques, 2014.
[15] M. Payer, A. Barresi and R. T. Gross, “Lockdown: Dynamic Control-Flow
Integrity,” ETH, Zürich, 2014.
[16] W. Arthur, B. Mehne, R. Das and T. Austin, “Getting in control of your control flow with control-data isolation,” in CGO '15 Proceedings of the 13th Annual IEEE/ACM International Symposium on Code Generation and
[17] V. Pappas, M. Polychronakis and A. D. Keromytis, “Dynamic Reconstruction of Relocation Information for Stripped Binaries,” in Research in Attacks, Intrusions and Defenses, Springer International Publishing, 2014, pp. 68-87.
[18] T. Vilkeliskis, “Automated unpacking of executables using Dynamic Binary
Instrumentation,” Department of Computer Science, Stevens Institute of
Technology, 2009.
[19] . A. Roy, S. Hand and T. Harris, “Hybrid binary rewriting for memory access
instrumentation,” in VEE '11 Proceedings of the 7th ACM SIGPLAN/SIGOPS international conference on Virtual execution environments, New York,
2011.
[20] J. Ming, D. Xu, L. Wang and D. Wu, “LOOP: Logic-Oriented Opaque
Predicate Detection in Obfuscated Binary Code,” in CCS '15 Proceedings of the 22nd ACM SIGSAC Conference on Computer and Communications
Security, 2015.
[21] H. Guo, J. Pang, Y. Zhang, F. Yue and R. Zhao, “HERO: A novel malware
detection framework based on binary translation,” in Intelligent Computing and Intelligent Systems (ICIS), Xiamen, 2010.
[22] H. Guan, E. Zhu, H. Wang, R. Ma, Y. Yang and B. Wang, “SINOF: A dynamic-static combined framework for dynamic binary translation,” Journal of Systems Architecture, vol. 58, no. 8, pp. 305-317, 2012.
[23] M. Braun, M. Buchwald and A. Zwinkau, “FIRM: A Graph-Based
1
BAB I
PENDAHULUAN
I.1 Latar Belakang Masalah
Self-Modifying Code berperan penting dalam pengembangan perangkat
lunak komersil terutama pada kasus proteksi lisensi dari pembajakan dan
malicious software dalam menyembunyikan eksistensinya. SMC juga sering
dikombinasikan dengan teknik anti-debugging lainnya seperti obfuscation. Hal
tersebut menjadi tantangan pada dunia reverse engineering karena sulit dianalis
secara statis. Aplikasi debugger umumnya hanya mengontrol data tetap pada
program dan memori saja. Salah satu menyiasatinya adalah dengan mendampingi
debugger dengan metode instrumentasi. Instrumentasi pada pemograman
digunakan untuk beberapa tujuan seperti hasil penggunaan memori, statistik
performansi maupun pengecekan bug dari segi kegunaan dan keamananan.
Instrumentasi beroperasi dengan menanamkan kode monitoring ke dalam
spesifik komponen program pada level sumber kode maupun biner. Pada kasus
program Self-Modifying Code terdapat pola subtitusi fungsi yang membuat proses
monitoring lepas dari pemindaian. Hal tersebut merupakan kelemahan dari
instrumentasi statis yang bekerja sebelum program dijalankan atau hanya
memindai binernya saja. Dengan kata lain subtitusi fungsi tidak dapat diketahui
karena terjadi pada saat eksekusi program. Kesulitan lain yang akan dihadapi oleh
reverse engineer adalah waktu yang diperlukan untuk memecahkan subtitusi
tersebut dan akan selalu berganti setiap kali ditemukan polanya, maka dari itu
perubahan harus dapat ditebak akan seperti apa selanjutnya.
Berdasarkan kendala tersebut diperlukan suatu analisis secara dinamis pada
saat program ditahap runtime. Dengan menggunakan metode Dynamic Binary
Instrumentation diharapkan dapat menganalisis Self-Modifying Code saat program
sedang memodifikasi dirinya. Instrumentasi dinamis pada biner juga menjaga
proses subtitusi fungsi dari Self-modifying Code itu sendiri. Proses DBI dilakukan
hampir tanpa interaksi reverse engineer atau menganalisis secara otomatis,
dengan begitu kasus dapat cepat diselesaikan.
I.2 Perumusan Masalah
Berdasarkan permasalahan yang telah dikemukakan pada latar belakang
dapat dirumuskan, kesulitan melakukan reverse engineering terhadap program
Self-Modifying Code sebagai usaha anti debugging.
I.3 Maksud dan Tujuan Penelitian
Maksud dari penelitian ini adalah menganalisis teknik Self-Modifying Code
menggunakan metode DBI(Dynamic Binary Instrumentation).
Adapun tujuan yang akan dicapai dalam penelitian ini adalah memperoleh
hasil analisis Self-Modifying Code yang mudah dimengerti dengan keluaran
intermediate representation untuk mempermudah reverse engineer dalam menilai
tindak lanjut pada proses debugging.
I.4 Batasan Masalah
Batasan masalah yang digunakan untuk Dynamic Binary Instrumentation
adalah sebagai berikut:
1. Dynamic Binary Instrumentation menggunakan Open Source Framework
DynamoRIO.
2. DynamoRIO digunakan dengan integrasi API (Application Programming
Interface) LLVM untuk memperoleh keluaran intermediate
representation
3. DynamoRIO plugin yang dibangun bertujuan memberikan nasihat atas
pola Self-Modifying Code
4. DynamoRIO plugin yang dibangun bukan sebagai patcher atau mengubah
program Self-Modifying Code menjadi non-Self-Modifying Code
5. DynamoRIO plugin dibangun menggunakan bahasa pemograman C++
Sedangkan batasan masalah pada kasus Self-Modifying Code terdiri dari:
1. Program Self-Modifying Code berformat ELF (Executable and Linkable
Format)
2. Program Self-Modifying Code mempunyai instruksi arsitektur x86_64 atau
AMD64(little endian)
3. Program Self-Modifying Code dianalisis dengan metode Dynamic Binary
Instrumentation
4. Program Self-Modifying Code dianalisis dengan tujuan menemukan set
instruksi pengganti dengan mudah
5. Program Self-Modifying Code bukan kompilasi JIT(Just-in-Time)
I.5 Metodologi Penelitian
Metodologi yang digunakan dalam penelitian ini adalah metode
eksperimental karena dilakukan pengujian berulang – ulang dan kasus dapat diuji
dengan metode lainnya. Adapun untuk analisis permasalahan digunakan metode
DBI(Dynamic Binary Instrumentation).
1. Metode Pengumpulan Data
a. Metode Studi Pustaka
Mencari literatur yang terkait dengan Self-Modifying Code dan Dynamic
Binary Instrumentation.
b. Metode Wawancara
Berupa tanya jawab dengan reverse engineer melalui e-mail dan forum
online. Metode ini digunakan untuk mendapat data – data pada sistem.
2. Metode Analisis Dynamic Binary Instrumentation
Metode yang digunakan dalam penelitian ini adalah DBI(Dynamic Binary
Instrumentation) dengan menggunakan framework dari DynamoRIO. DynamoRIO
beroperasi dengan menggeser eksekusi sebuah aplikasi dari petunjuk aslinya ke
menempati ruang alamat aplikasi tersebut dan memiliki kendali penuh atas
eksekusi, mengambil alih setiap kali kontrol meninggalkan cache code atau ketika
sistem operasi langsung mentransfer kontrol ke aplikasi (kernel-mediated control
transfers).
Gambar I.1 Proses DynamoRIO
DynamoRIO menyalin kode aplikasi satu blok dasar dinamis setiap waktu
ke dalam kode cache blok dasarnya. Sebuah blok yang langsung menargetkan
blok lain sudah ditempati dalam cache yang terkait blok tersebut untuk
menghindari kembali ke dispatcher. Urutan eksekusi dari blok dasar yang sering
muncul digabungkan menjadi traces yang ditempatkan secara terpisah.
DynamoRIO membuat traces tersebut tersedia melalui antarmuka untuk
I.6 Sistematika Penulisan
Sistematika penulisan ini disusun untuk memberikan gambaran umum
tentang penelitian yang dijalankan. Sistematika penulisan penelitian ini adalah
sebagai berikut:
BAB I PENDAHULUAN
Menguraikan tentang latar belakang permasalahan, mencoba merumuskan
inti permasalahan yang dihadapi, menentukan tujuan dan kegunaan
penelitian, yang kemudian diikuti dengan pembatasan masalah, asumsi, serta
sistematika penulisan.
BAB II. TINJAUAN PUSTAKA
Membahas berbagai konsep dasar dan teori-teori yang berkaitan dengan
topik penelitian yang dilakukan dan hal-hal yang berguna dalam proses
analisis permasalahan serta tinjauan terhadap penelitian-penelitian serupa yang
telah pernah dilakukan sebelumnya termasuk sintesisnya.
BAB III. ANALISIS SELF-MODIFYING CODE DAN PERANCANGAN
DYNAMIC BINARY INSTRUMENTATION
Bab ini berisi tentang analisis masalah, analisis biner program, analisis
non-fungsionalitas serta analisis perancangan metode yang digunakan. Selain itu
pada bab ini memaparkan perancangan sistem yang akan dianalisis.
BAB IV. IMPLEMENTASI DAN PENGUJIAN SISTEM
Bab ini menerangkan tentang pengujian sistem berdasarkan pada metode yang
digunakan dengan menggunakan unit testing dan menjelaskan apakah sudah
benar-benar sesuai dengan analisis dan perancangan yang telah dilakukan.
BAB V. KESIMPULAN DAN SARAN
7
BAB II
TINJAUAN PUSTAKA
II.1 Debugging
Bug pada perangkat lunak merupakan sebuah kesalahan dalam program atau
sistem yang menyebabkan setidaknya satu fungsional atau non-fungsional
menjadi terganggu. Debugging adalah sebuah proses sistematis memerika
program dari bug. Debugging sendiri diambil dari kata bug yang fokus utamanya
memang untuk melepas bug. Namun, tujuan akhirnya tidak selalu untuk
memperbaiki program, beberapa reverse engineer melakukannya agar dapat
mengambil keuntungan tertentu seperti eksploitasi.
Pada umumnya debugging adalah bagaimana menciptakan suatu masalah
seperti input diluar ekspektasi atau dengan membuat test case sembarangan (black
box testing) sampai menimbulkan crash. Setelah program mencapai keadaan
crash kemudian debugger mengeksaminasi status program dimana terjadi urutan
letak masalah atau dikenal sebagai call stack. Beberapa call stack memiliki
informasi yang kurang jelas atau implisit tergantung dari tingkatan kompleksnya
sebuah program.
II.2 Macam-Macam Format Debugging
Format Debugging merupakan desain data yang tersimpan dalam program
untuk mempermudah debugger dalam menganalisis. Macam – macam format
debugging diantaranya:
1. STAB (symbol table) menyimpan informasi debug ke bagian simbolis file
objek yang umumnya digunakan oleh executable pada sistem operasi
UNIX terdahulu dan digunakan hingga sekarang untuk alasan
kompabilitas.
2. DWARF (debug with arbitrary record format) menggunakan file objek
untuk menyimpan informasi debug dengan struktur pohon di mana setiap
simpul mewakili tipe data, variabel atau fungsi. DWARF menjadi standar
II.3 Instrumentation
Instrumentasi dalam istilah pemograman adalah tindakan menanamkan kode
monitoring ke dalam sistem perangkat lunak. Instrumentasi dapat dilakukan
dengan cara transformasi biner program, manipulasi link-time, hooks khusus
dalam virtual machine(bahasa pemograman tingkat tinggi/interpreter) atau dengan
transformasi pada sumber kode. Keluaran yang dihasilkan berupa peristiwa yang
terjadi pada program dalam konteks spesifik, tidak meluas atau hanya bergantung
pada komponen dan fungsi yang ditinjau.
Kelemahan instrumentasi terletak pada jangkauannya yang mengurucut ke
fungsi target sehingga memungkinkan kode yang di-instrument lepas dari
eksamen atau tidak sampai mencapai poin eksekusi ketika fungsi tersebut
memanggil fungsi lainnya. Instrumentor juga berperan menggapai memori yang
diakuisisi program dan membuat kinerja program menjadi lamban atau bahkan
crash. Hal tersebut sangat bergantung pada kondisi environment atau resource
yang dimiliki.
Dalam menentukan instrumentasi apa yang cocok untuk digunakan perlu
dilihat ketersediaan informasi program. Adapun kategori tersebut dikategorikan
berdasarkan language agnostic yakni:
1. DLL(Dynamic Link Library) Rewriting
Instrumentasi dijalankan saat setelah siklus kompilasi/linking dimana
penggunaan hasil cache merupakan DLL yang telah dimodifikasi
2. In Place Instrumentation
Sama dengan DLL rewriting akan tetapi DLL tidak dimodifikasi begitu juga
dengan target program. Fungsi – fungsi di-hook tepat untuk tugas yang
diperlukan ketika DLL tersebut dimuat atau di-load pertama kali saat startup
atau setelah panggilan LoadLibrary
Mirip dengan in place instrumentation tetapi hanya menginstrumentasi
sebuah fungsi saat pertama kali fungsi tersebut dieksekusi
4. Intermediate Language Instrumentation
Instrumentasi pada bahasa tingkat menengah adalah memonitor aktivitas
eksekusi sebelum bahasa tingkat menengah dikompilasi ke dalam instruksi
executable oleh virtual machine atatu interpreter
5. Intermediate Language Instrumentation via Reflection
Java dan .Net keduanya memberikan API refleksi yang memungkinkan
penemuan metadata tentang metode. Dengan menggunakan data tersebut dapat
dibuat metode baru dengan on-the-fly instrumentation yang ada seperti dengan
instrumentasi bahasa tingkat menengah disebutkan sebelumnya.
6. Compile Time Instrumentation
Teknik ini digunakan pada waktu kompilasi untuk menyisipkan instruksi
yang tepat ke dalam aplikasi selama kompilasi. Kelemahannya membutuhkan
usaha pembangunan linking yang besar.
7. Source Code Instrumentation
Teknik ini digunakan untuk memodifikasi kode sumber dengan menyisipkan
kode instrumentasi yang sesuai dengan dekorator sebelum masing-masing fungsi.
8. Link Time Instrumentation
Teknik ini sangat berguna ketika dibutuhkannya penggantian memory
allocators seperti fungsi realloc dengan tracing allocators. Hal tersebut berkaitan
dengan pencarian bug pada memori seperti buffer overflow atau memory leak
9. IAT Hooking Instrumentation
Instrumentasi ini melibatkan modifikasi import address table untuk fungsi
terkait dalam DLL atau Unix shared object. Hanya dengan patch lokasi import
II.4 Metode Binary Instrumentation
Binary Instrumentation merupakan proses memodifikasi instruksi sebuah
program ketika eksekusi. Modifikasi tersebut dapat diaplikasikan pada file
executable, file objek maupun file kelas pada semua fase seperti waktu kompilasi,
linking pustaka, load time atau run-time. Dynamic Instrumentation beroperasi
dengan menanamkan kode dinamis ke dalam program tanpa harus rekompilasi.
Dynamic Binary Instrumentation dapat menganalisis eksekusi program secara
step-by-step pada konteks memori dan register dan hanya menganalisis kode yang
dieksekusi.
Dynamic Binary Instrumentation adalah sebuah metode analisis tingkah
laku aplikasi secara runtime pada saat eksekusi melalui penanaman kode
instrumentasi. Kode intrumentasi tersebut mengeksekusi sebagai bagian dari
instruksi asli. DBI dibagi atas dua berdasarkan cara kerjanya yaitu light-weight
dan heavy-weight. Light-weight DBI beroperasi pada instruksi stream secara
spesifik berdasarkan arsitektur dan status perlakuan analisis sedangkan
heavy-weight beroperasi secara abstrak pada stream dan status instruksinya [2].
Berbeda dengan Static Binary Instrumentation yang memodifikasi file
executable maupun pustakanya dengan pendekatan sebelum eksekusi program.
Instrumentasi biner dinamis memanipulasi saat program di tahap sudah dimuat
dalam memori. Instrumentasi biner secara statis mempunyai keunggulan dalam
hal performansi karena DBI melakukan penyisipan sebelum eksekusiyang
berakibat akses informasi seperti nama variabel menjadi sulit.
II.5 ELF
ELF (Executable and Linking Format) ialah format file executable standar
UNIX System V seperti Linux yang dibagi beberapa seksi seperti .text untuk
kode, .data untuk variabel global, .rodata yang umumnya menyimpan strings
konstan, .bss(Block Started by Symbol) data segment yang mengandung variabel
statis representasi oleh zero-valued(pengosongan memori) ketika eksekusi dimulai
dan .stab untuk simbol debugging. File ELF juga berisi header yang
Gambar II.1 ELF Diagram
ELF dahulunya disebut Extensible Linking Format karena dapat direlokasi
dengan mudah mengandalkan linking dan loading DSO (dynamically linked
shared objects). Namun, ELF juga mampu mendukung position independent code
yang menghindari pengalamatan secara absolut atau tidak membutuhkan relokasi
sama sekali. Hal tersebut berbeda dengan pustaka statis walaupun ELF juga
mendukung sistem portable.
II.6 Self-Modifying Code
Self-Modifying Code adalah sebuah teknik pemograman dimana program
merupakan cetusan dari Rice’s theorem dimana untuk setiap properti non-trivial
dari fungsi parsial, tidak ada metode umum dan efektif yang dapat memutuskan
apakah suatu algoritma mengkalkulasi fungsi parsial properti tersebut. Logika
Self-Modifying Code pada dasarnya menggunakan ekspresi lambda kalkulus
dalam subtitusi fungsi.
Self-Modifying Code kerap kali diidentikkan dengan salah satu teknik
obfuscation namun, program tidak serta merta menjadi kompleks dalam hal
analisis melainkan performa program yang membaik dan baris kode yang lebih
efisien. Rata – rata program obfuscated adalah memberikan junk yang tidak
berarti untuk mengelabui analis sedangkan Self-Modifying Code umumnya
mengambil jalan potong untuk instruksi yang lebih sederhana.
Berdasarkan fungsinya Self-Modifying Code dibagi atas beberapa tujuan.
Adapun contoh diantaranya yang sering digunakan adalah sebagai berikut:
1. Self-Checksumming
Program melakukan pengecekan integritas terhadap variasi segmen kode saat
eksekusi untuk memastikan bahwa biner program tidak diubah. Verifikasi berada
pada segmen memori dengan status segmentation fault atau program dihentikan
dengan signal handler interupsi tertentu jika terdeteksi ketidaksesuaian. Hal ini
bukan mengecek apakah hash checksum dari keseluruhan biner berbeda
melainkan keutuhan dari instruksi program. Adapun contoh dari Self-Checksum
dapat dilihat pada pseudocode assembly berikut:
add (rbx), r15 ;membaca memori
sub 1, ecx ;looping counter secara decrement
add rdi, rax
xor r14, rdi
add rcx, rdx
add rbx, rdi
xor rax, rdx ;modifikasi register jump_target yaitu rdx dan rdi
xor r15, rdi
add rdi, r14 ;modifikasi checksum dengan rdx dan rdi
xor rdx, -8(rsp) ;modifikasi checksum dalam stack
xor r15, r13
add r14, r12
rol r15
xor rdi, rbx ;membuat pseudorandom akses memori
and mask1, ebx
or mask2, rbx
xor rdx, rsp
and mask3, esp
or mask4, rsp
and 0x180, edx ;Modifikasi penunjuk stack dan alamat target_jump
and 0x1, rdi
add rdi, rdx
add rdi, rdi
add rdi, rdx
or mask, rdx ;membuat alamat target_jump
xor rdx, r15 ;Menambahkan alamat target_jump ke dalam checksum
mov rax, rdi
Enkripsi dapat diimplementasikan pada biner executable dan didekripsi pada
saat program dijalankan. Biasanya menggunakan instruksi aritmetik
XOR(exclusive-or) maupun polymorphic dengan menambahkan operasi bit
instruksi ADD(addition) dan SUB(subtraction). Contoh Self-Decrypt dapat
dilihat pada pseudocode assembly berikut:
main:
pop rsi ; pop alamat data
dienkripsi
Biner executable dapat diperkecil ukuran datanya dengan teknik kompresi
yang kemudian diekstrak ke memori untuk mendapatkan fungsi program
sebenarnya. Algoritma kompresi yang digunakan sama dengan metode untuk
kompresi file seperti Huffman/Lempel-Ziv, Welch,
Lempel-Ziv-Markov dan PAQ akan tetapi header atau magic program tetap sebagaimana
executable semestinya. Berikut contoh self-extract dalam bahasa pemograman
4. Self-Repairing
Self-Error-Correcting atau Self-Healing code merupakan upaya untuk
memperbaiki perangkat lunak dari error dengan sendirinya agar tidak pernah
crash. Hal ini merupakan topik lanjutan dari SMC karena menggunakan
kecerdasan buatan dalam implementasinya. Konsep dari Self-Repairing adalah
menyalin instruksi clean untuk memperbaiki jika ada satu atau lebih instruksinya
rusak. Adapun contohnya dapat dilihat pada pseudocode assembly berikut yang
merupakan safepoint pada hardisk atau S.M.A.R.T. (Self-Monitoring, Analysis
and Reporting Technology)
disk:
movb cl, (si) ; Jumlah sektor yang akan dibaca
push si ; Simpan si
mov si, #LOADOFF+ext_rw ;
movb 2(si), cl ; Mengisi blok yang akan ditransfer
mov 4(si), bx ; alamat buffer
pop si ; Mengeluarkan si ke poin alamat array
!jmp rdeval
add 1(si), ax ; Pembaharuan alamat oleh sector baca
adcb 3(si), ah
subb (si), al ; Decrement jumlah sektor dengan sector
baca
jnz load ;
add si, #4 ; memperbaiki alamat selanjutnya
yang dibaca
jnz load ; Baca instruksi selanjutnya
5. Self-Testing
Self-Testing Code bertujuan me-refactoring kode agar dapat menguji testcase
dengan sendirinya. Pendekatan ini mirip dengan built-in test akan tetapi eksekusi
bersifat jika peristiwa tertentu terjadi seperti kegagalan fungsi progam (bug)
dalam menjalankan tugasnya. Adapun contohnya dapat dilihat pada pseudocode
berikut:
loop: UMUL R4,R3,R2,R1 ; multiplikasi
ADD R5,R4,R3 ; tambah words
Anti-debugging adalah salah satu upaya untuk menghambat reverse
engineering sehingga analis tidak dapat menggunakan debugger untuk
perangkat lunak dan infeksi dari program lain seperti malware (malicious
software). Pada dasarnya semua sistem proteksi software primitif dibagi atas dua
ide yaitu checks dan landmines. Checks menghasilkan nilai ubahan atau jalan
eksekusi kode berbasis status item yang dicek sedangkan landmines seperti crash,
hang, scramble yang menginterupsi alat analisis atau debugger itu sendiri.
Beberapa bahasa pemograman telah menyediakan fungsi built-in berupa
API (Application Programming Interface) untuk pendeteksian debugger dan
virtual machine. Selanjutnya programmer dapat memutuskan apakah debugger
diizinkan untuk menganalisis atau tidak. Anti-debugging juga dapat diciptakan
oleh compiler yang fungsinya menghapus readable strings (metadata) termasuk
informasi debug atau dengan memberikan obfuscation agar instruksi program
menjadi kompleks.
II.8 DynamoRIO
DynamoRIO adalah salah satu framework atau alat Dynamic Binary
Instrumentation yang tersedia multiplatform dan sumber terbuka. Alat tersebut
merupakan kombinasi dari Dynamo, sebuah mesin optimasi dinamis yang
dikembangkan oleh peniliti dari HP dan RIO yaitu runtime instropection and
optimization engine yang dikembangkan oleh MIT. DynamoRIO mendukung
analisis aplikasi pada sistem operasi seperti Windows, Linux dan OSX yang
mempunyai arsitektur x86, AMD64 dan ARM.
Salah satu kelebihan DynamoRIO adalah analisis sudut pandangnya yang
menanamkan kode instrumentasi ketika binary fragment sedang dimasukkan ke
dalam fragment cache. Hal tersebut sangat berguna untuk mencegat akses memori
di dalam aplikasi. Ketika fragmen sedang dibuat, pustaka analisis DynamoRIO
berperan masuk ke instruksi dalam fragmen yang dihasilkan. Menggunakan
pengetahuan tersebut memungkinkan analis merancang pustaka analisis yang
dapat mencegat memori dalam membaca dan menulis ketika aplikasi dieksekusi.
Performansi merupakan kendala besar dalam instrumentasi biner dinamis.
performansi karena menggunakan rekompilasi JIT(Just-in-Time) terhadap seksi
kode yang memerlukan kerja ekstra. Namun untuk mengatasi logika kompleks
DynamoRIO dirasa tidak mumpuni karena ketersediaan pada kode cache terbatas.
Berikut ini dapat dilihat benchmark dalam analisis perangkat lunak chromium
yang menggunakan beberapa pustaka seperti kriptografi hingga multimedia
Gambar II.2 DynamoRIO Benchmark
PIN berulang kali melakukan iterasi untuk memastikan instruksi yang
kompleks benar-benar valid. Sedangkan Inference DynamoRIO yang merupakan
modifikasi khusus untuk target program hanya memerlukan informasi sederhana
dari arus instruksi berjalannya sebuah program karena informasi lainnya sudah
terdapat pada pustaka analisis yang dibuat.
II.9 Profiling
Profiling dalam informasi teknologi adalah aktivitas mengumpulkan
informasi penggunaan resources dan waktu yang diperlukan untuk menjalankan
suatu aplikasi. Profiling umumnya bertujuan untuk menemukan apa yang
dapat berupa penggunaan instruksi, panggilan fungsi diikuti waktu eksekusi
hingga aplikasi berhenti dalam bentuk teks maupun visualisasi grafik. Profiling
dapat dilakukan dengan kode instrumentasi yang ditanam pada biner program atau
pada level kode sumber.
Peristiwa yang terjadi pada program dapat diukur dengan statistik atau
benchmarks. Dengan memberikan kerja berat pada aplikasi, benchmarking lebih
memberikan informasi maksimal. Variasi kondisi membuat benchmarking dan
profiling menjadi dua hal yang berbeda. Aktivitas profiling pada dasarnya tidak
dibebani tugas yang berat melainkan tingkah laku pada status normal.
II.10 Tracing
Tracing dalam istilah pemograman merupakan salah satu teknik debugging
yang digunakan untuk memahami proses berjalannya sebuah program. Tracing
sering kali dikomparasikan dengan logging karena berupa catatan seperti file apa
saja yang dibuka, pustaka apa saja yang dipanggil dan sebagainya. Terdapat
beberapa level dalam mekanisme trace yaitu Verbose, Debug, Info, Warning,
Error, Fatal dan Silent. Buffer yang ditampilkan juga melingkupi bagian Main,
System, Radio, Events bahkan Crash.
Keluaran trace paling popular adalah backtrace atau stacktrace dimana
beberapa stack frame yang menjadi masalah pada program dikembalikan sampai
ke pangkal fungsi utama aplikasi. Stacktrace pada bahasa pemograman tingkat
tinggi di-handle oleh interpreter dan berisi poin baris kode yang
menginterpretasikan referensi masalah sedangkan, bahasa tingkat rendah
memerlukan simbol debug atau jika tidak ada, keluaran berupa bahasa mesin atau
assembly.
II.11 Binary Analysis
Analisis biner adalah sebuah pendekatan membongkar program dengan
disassembly atau dekompilasi untuk tujuan reverse engineering. Pekerjaan ini
dilakukan ketika analis tidak memiliki sumber kode. Aktivitas analisis biner
mendukung terjemahan yang sederhana ke dalam byte code atau emulasi sebagai
binary translation. Hal tersebut berkenaan bahasa mesin atau assembly sulit
dimengerti terutama pada aplikasi berskala besar yang mempunyai jutaan
instruksi.
Biner program juga dapat direpresentasikan dalam bahasa tingkat
menengah namun, bahasa tersebut sangat independen tergantung compiler yang
mengkompilasinya. Alat analisis biner berperan langsung dalam dekompilasi ke
bahasa independen tersebut. Analisis biner juga dapat dilakukan secara dinamis
dengan mengeksekusi program pada real dan virtual processor. Terminologi
analisis biner sangat dekat dengan runtime analysis karena keterbatasan analisis
statis yang tidak mumpuni untuk perangkat lunak berproteksi.
II.12 Program Lifecycle Phase
Fase umum dari hidupnya sebuah perangkat lunak dari sumber kode hingga
menjadi biner yang dijalankan meliputi:
II.12.1 Edit Time
Edit time adalah fase dimana ketika kode program sedang diubah artinya
status program bisa jadi belum ditahap konsisten. Perubahan biasanya dilakukan
oleh programmer namun, dapat pula dilakukan oleh generator, alat desain atau
dengan sistem meta-programming. Contohnya seperti pengecekan syntax atau
analisis sumber kode maupun merubah bahasa pemograman satu ke yang lainnya.
II.12.2 Compile Time
Compile time adalah fase setelah sumber kode diterjemahkan kedalam
bahasa mesin oleh compiler. Pada tahap kompilasi terjadi pengecekan atas
konsistensi kode yang diubah dan menghasilkan sebuah file executable. Untuk
bahasa pemograman tingkat tinggi yang menggunakan interpreter, kompilasi
berupa merubah sumber kode menjadi bytecode.
II.12.3 Link Time
Link time adalah fase menghubungkan pustaka dengan program yang
atau bahkan ketika eksekusi. Linking kerap kali dikaitkan dengan kompilasi
walaupun sebenarnya tahap ini terpisah. Linking juga merupakan penggabungan
beberapa file objek menjadi satu buah executable.
II.12.4 Load Time
Load time adalah fase ketika file executable dipanggil dan ditempatkan
dalam memori yang aktif sebagai bagian dari mulainya eksekusi. Sederhanya
adalah tahap dimana program pertama kali dijalankan yang mana sudah tidak lagi
berupa file melainkan menjadi kesatuan atau pengalamatan interface pada kernel.
II.12.5 Run Time
Run time adalah fase dimana program sedang berjalan normal maupun
tidak normal seperti hang. Di tahap ini program berada di status sudah
mengakuisisi memori dan dapat mulai bekerja secara multi threading atau
menciptakan proses child.
II.13 Binary Translation
Binary Translation adalah proses menerjemahkan kode mesin (biner) dari
satu set instruksi ke instruksi lainnya. Sistem yang menggunakan hal tersebut
direferensikan sebagai emulator. Kebanyakan Binary Translation mempunyai
fungsi alat migrasi untuk transisi arsitektur lama ke yang baru. Penerjamahan
biner dapat dilakukan secara statis (seluruh biner ke target platform) maupun
dinamis dengan menerjemahkan kode saat eksekusi secara parsial berdasarkan
fungsi yang diinginkan [3].
Beberapa Dynamic Binary Translation menggunakan “fast return” atau
indirect branch/call prediction dalam pendekatan mengindari overhead. Pada
processors terbaru prediksi menggunakan dua level adaptif predictor. Instruksi
tersebut berkontribusi lebih dari satu bit ke history buffer. Prosesor tanpa
mekanisme tersebut secara sederhana memprediksi sebuah indirect jump ke lokasi
yang sama terakhir kalinya. Contoh sederhana implementasi dari Binary
II.14 Intermediate Representation
IR atau sering disebut bahasa tingkat menengah merupakan representasi
program diantara sumber kode dan biner (assembly). Hal tersebut sangat
independen tergantung pada compiler maupun interpreter-nya. Representasi dapat
digambarkan melalui graph seperti AST (Abstract Syntax Tree) maupun biner
dalam bytecode. Bytecode mempunyai tujuan retargetable untuk merekonstruksi
kembali kedalam biner. Pada dasarnya IR memiliki contoh padanan menampilkan
algortitma sebagai berikut:
Reverse engineer dalam dunia komputer adalah orang yang mempunyai
tugas merekayasa hasil objek baik perangkat keras maupun lunak untuk
mengubah atau mengembalikkan informasi sumbernya. Pada biner aktivitasnya
meliputi membaca kode mesin assembly untuk program executable dan membaca
hexademical untuk objek lainnya seperti gambar atau video yang kemudian
direplikasi atau patching menjadi sesuai keinginan reverse engineer.
Terdapat bermacam-macam teknik reverse engineering untuk perangkat
lunak diantaranya melakukan analisis secara statis(disassembly) langsung pada
biner program hingga memasukkanya dalam ruang lingkup debugger. Beberapa
reverse engineer melakukan instrumentasi atau menyisipkan program bantuan
untuk melakukan analisis secara otomatis dan bermain di area memori. Untuk
reverse engineer yang tidak biasa dengan hal tersebut biasanya menggunakan
intermediate representation sebagai acuan dalam mengolah data yang menjadi
23
BAB III
ANALISIS SELF-MODIFYING CODE DAN PERANCANGAN
DYNAMIC BINARY INSTRUMENTATION
III.1 Analisis Sistem
Subbab analisis ini membahas mengenai analisis masalah, analisis biner
program, analisis kebutuhan nun fungsional, analisis teknik Self-Modifying Code
dan perancangan Dynamic Binary Instrumentation.
III.1.1 Analisis Masalah
Masalah yang menjadi latar belakang pada penelitian ini adalah bagaimana
menganalisis Self-Modifying Code setelah dikompilasi ke dalam biner program
untuk memahami cara kerjanya menggunakan metode DBI(Dynamic Binary
Instrumentation). Adapun spesifikasi masalah adalah pengaruh Self-Modifying
Code sebagai usaha anti analisis dalam membuat proses debugging menjadi sulit,
kendala Dynamic Binary Instrumentation dalam menganalisis program serta
konfigurasi environment yang berbeda-beda.
III.1.2 Analisis Biner Program
Analisis Biner adalah proses menganalisis dan menggambarkan
bagaimana program dalam bekerja menjalankan tugasnya. Teknik analisis biner
memiliki ruang lingkup yang luas. Selain meliputi biner yang melibatkan sistem
operasi, analisis biner juga memodelkan aspek–aspek yang terkait dengan
instruksi independen arsitektur. Instruksi yang perlu diketahui untuk menganalisis
program Self-Modifying Code adalah transfer kontrol tidak kondisional seperti:
Tabel III.1 Transfer Kontrol
Instruksi Keterangan
JMP JMP(Jump) adalah transfer kontrol satu arah dan tidak menyimpan alamat
CALL CALL(Call Procedure) mendorong alamat kembali ke stack dan transfer
kontrol ke prosedur
RET RET(Return From Procedure) memunculkan alamat kembali dari stack dan
mengembalikan kontrol ke lokasi tersebut
Tidak ada urutan standar dalam analisis biner karena setiap proses debugging
adalah seni. Adapun langkah-langkah yang diambil untuk analisis biner
Self-Modifying Code dengan Dynamic Binary Instrumentation adalah sebagai berikut:
1. Memeriksa fungsi de-obfuscation routine dengan disassembly secara statis.
Hal ini dapat dilakukan dengan alat seperti objdump maupun debugger seperti
GDB.
2. Setelah mengetahui fungsi dimana terjadi Self-Modifying Code, dilakukan
pembangunan instrumentasi untuk memonitoring fungsi tersebut.
3. Selanjutnya program Self-Modifying Code dijalankan dengan invokasi
instrumentor dalam hal ini DynamoRIO
4. Setelah hasil analisis berupa keluaran intermediate reprsesentation
dilanjutkan dengan membuat script sederhana atau patcher untuk
memecahkan Self-Modifying Code tersebut
5. Membuat laporan cara kerja dengan teliti apa yang sebenarnya dilakukan oleh
kesuluruhan program
III.1.3 Analisis Teknik Self-Modifying
Self-Modifying Code yang dianalisis merupakan perspektif telah menjadi
program executable artinya tidak ada akses untuk sumber kode. Informasi yang
tersedia hanya kode assembly pada biner dimana setiap routine harus
diidentifikasi terlebih dahulu untuk mendapatkan fungsi yang mengolah
modifikasi. Terdapat tiga kasus yang akan diuji diantara lain Self-Checksumming,
1. Self-Checksumming
Program Self-Modifying yang memverifikasi keaslian kode selama eksekusi
terdapat sisipan produser kode perhitungan checksum. Sebuah algoritma
checksum menghitung hash melewati berbagai kode kritis yang tidak boleh
diubah. Verifikasi tersebut membandingkan hasil perhitungan checksum terhadap
nilai yang tertera secara hard-coded dalam fungsi program. Kegagalan verifikasi
menunjukkan dugaan modifikasi dari program dimana integritas tidak lagi
terjamin.
Dimisalkan sebuah program yang dapat dijalankan hanya dengan adanya
lisensi yang valid. Program harus dapat melindungi modifikasi kode yang
melakukan cek lisensi. Reverse engineer mungkin menghapus fungsi pengecekan
lisensi tersebut dengan cukup memasukkan instruksi jump pada kode dimana cek
lisensi berada. Artinya pengecekan dilewati atau tidak dieksekusi sama sekali.
Adapun contoh self-checking checksum dapat dilihat pada pseudocode berikut:
Selfcheck(checksum, nonce, codeStart, codeEnd,
codeSize) {
while (iteration < 2500000)
{
eksekusi. Bagian codeStart, codeEnd dan codeSize didefinisikan pada seksi
2. Self-Decrypting
Idealnya perangkat lunak yang mendekripsi bagian dirinya hanya berisi
decryptor stub (informasi yang digunakan untuk mendekripsi) dan kode yang
terenkripsi. Ada banyak varian dari metode enkripsi, beberapa diantaranya
cendrung statis (dengan kunci dekripsi) dan yang lainnya dengan polymorphic
atau mengubah kunci dekripsi. Hal ini dilakukan dalam rangka untuk membuat
ruang lingkup debugger atau emulasi pada antivirus berhenti. Adapun klasifikasi
enkripsi biner dibedakan berdasarkan bagaimana kode tersebut didekripsi yaitu:
1. Dengan kunci statis (dekripsi routine sangat mudah dimengerti)
2. Kunci yang berubah-ubah sewaktu-waktu(looping dengan increment +1,
mudah dimengerti namun sedikit kerja ekstra untuk reverse engineer)
3. Tanpa kunci atau hanya operasi bit (contoh instruksi circular shift atau
penggeseran seperti not, rol, ror, x-bit swap)
4. Kunci dengan eksternal dependensi(Berganti terus menerus dan tidak
mempunyai pola spesifik seperti pada pengalamatan modul poin entri atau
alamat virtual di memori untuk executable)
5. Tanpa kunci sama sekali(kode dekripsi didapatkan dengan brute force)
Cryptanalysis dapat dilakukan dengan menggunakan metode Stream Cipher
Attack atau memanfaatkan informasi yang muncul berkali-kali. Adapun kasus
polymorphic self-decryption dapat dilihat pada pseudocode assembly berikut:
LEA SI,...
Berdasarkan kode diatas kunci dekripsi akan berganti dengan multiple
execution dikarenakan stack pointer diinilisiasi sebelum looping. Berdasarkan
byte,word dan dword sebagai kunci atau kode metadata seperti alamat relative
dan absolute pada memori sebagai kuncinya untuk enkripsi yang lebih baik.
3. Self-Extracting
Sederhananya Self-Extracting melakukan unpacking satu atau lebih segmen
yang mengandung data konstan ke dalam blok yang dialokasikan pada memori
executable dan kemudian memulai proses langsung melompat pada kode
sebenarnya. Dengan kata lain sama seperti self-decrypting dimana terdapat
decompressor dan program loaders. Self-Extracting dibangun menggunakan
packers yaitu UPX(Ultimate Packer for eXecutable).
Ketika packing executable menggunakan UPX, semua seksi seperti .text dan
.data dikompresi dengan penamaan UPX0, UPX1 dan seterusnya. Kemudian UPX
menambahkan seksi kode diakhir yang mengandung keseluruhan dekompresi saat
eksekusi. Berikut ini langkah-langkah yang dilakukan oleh UPX:
1. Eksekusi dimulai dengan OEP(Original Entry Point) baru
2. Menyimpan status register menggunakan instruksi PUSHAD
3. Semua packed atau pemadatan di-unpack dalam memori
4. Memuat kembali alamat import table orisinil dari file executable
5. Memuat kembali status register asli menggunakan instruksi POPAD
III.1.4 Analisis Binary Translation
Program yang emodifikasi bagian dirinya menimbulkan masalah ketika
kode yang telah diterjemahkan berganti menjadi program asing. Jika binary
translators tidak menyadari akan hal tersebut, binary translator akan
mengeksekusi kode asal saat sebelum diterjemahkan. Analisis Binary Translation
dilakukan berkenaan dengan desain keluaran yang akan dihasilkan berupa
representasi bahasa pemograman tingkat menengah.
Performansi pada proses translasi biner juga patut diperhatikan. Adapun
konsep yang dapat mempengaruhi proses translasi biner menjadi cepat atau
bahkan lamban adalah sebagai berikut:
1. Looping Translation
Proses penerjemahan berjalan pada unit dasar blok. Sebuah blok dasar
adalah aliran langsung instruksi dengan instruksi cabang (JMP, call, dll) di
tail namun bukan di dalam fungsi. Sebuah blok dasar diterjemahkan dapat
langsung dijalankan pada CPU. Ketika instruksi branch terakhir
dijalankan, kemudian ditentukan apakah target branch sudah
diterjemahkan. Jika iya, Translator hanya bisa melompat disana. Jika
tidak, Translator harus menerjemahkan blok dasar pertama. Panggilan
untuk mengirimkan trampolin ditambahkan ke setiap blok dasar yang
diterjemahkan.
for (;;) {
if (!(translated_pc = find_translation(pc)) translated_pc = translate_basic_block(pc); execute(translated_pc);
}
2. Direct Branch
Branch langsung adalah jika target dapat ditentukan pada saat
penerjemahan. Misalnya, memanggil fungsi tetap merupakan branch
langsung. Jika hanya ada satu target yang deterministik untuk branch
maka penerjemahan akan sangat mudah untuk dioptimalkan. Ketika
dahulu apakah sudah dijalankan. Jika iya, binary translator dapat dengan
mudah meng-encode target branch. Jika tidak, bangun trampolin seperti:
push $patch_addr push $target_pc
jmp dbt_find_direct_internal
Dimana patch_addr adalah pointer ke target branch langsung dalam
instruksi branch asli. dbt_find_direct_internal adalah fungsi perakitan
untuk menyimpan dan memulihkan konteks program. Ketika fungsi
tersebut dipanggil selanjutnya adalah menerjemahkan blok dasar yang
hilang dengan menerjemahkan translated_pc ke patch_addr. Oleh karena
itu ketika instruksi branch asli ditemui kedua kalinya, langsung melompat
ke target yang benar tanpa overhead.
3. Indirect Branch
Karena Branch tidak langsung tidak dapat ditentukan pada saat
penerjemahan maka, diselesaikan pada saat runtime. Efektivitasnya
langsung mempengaruhi kinerja sistem DBT.
4. Return Handling
Instruksi ret adalah bentuk khusus dari percabangan tidak langsung yang
sangat mudah diprediksi. Beberapa sistem DBT menggunakan pendekatan
"fast return" untuk meminimalkan terjadinya overhead. Ketika call
dijalankan, binary translator mendorong alamat pengirim yang
diterjemahkan, bukan alamat pengirim asli untuk stack. Masalah utama
dari pendekatan ini adalah tidak transparan untuk aplikasi pokok, dan fitur
tertentu seperti exception handling akan gagal jika alamat kembali diubah.
DynamoRIO menerapkan teknik yang disebut "return cache". Kembalinya
cache bermaksud tabel hash terdiri dari pemetaan dari alamat kembali. Setiap
hash bucket memiliki hanya satu entri. Ketika instruksi panggilan dijalankan, pc
yang diterjemahkan dari alamat pengirim ditulis ke hash table bucket. Ketika
instruksi kembali dijalankan, alamat pengirim di stack diiris dan melompat masuk
Untuk menangani kasus ini, sebuah stub sederhana ditambahkan setelah instruksi
panggilan.
1. Call return pair optimization
CPU modern memiliki mekanisme prediksi branch yang maju untuk
meningkatkan efisiensi eksekusi. Salah satu optimasi tersebut disebut "return
stack buffer". Hal tersebut merupakan ring buffer yang mirip dengan alamat
kembali cache. Ketika instruksi call dijalankan, alamat kembali dimasukkan ke
buffer. Ketika instrruksi ret dijalankan, tumpukan atas muncul dan digunakan
sebagai prediksi alamat target. Untuk mengambil keuntungan dari ini, instruksi
call dan ret harus dalam pasangan. Dalam sistem penerjemahan biner tradisional
dinamis dua instruksi tersebut biasanya diimplementasikan menggunakan
instruksi jmp ke berbagai trampolin yang benar-benar hilang optimasinya dari
return stack buffer.
2. CPUID Emulation
Karena setiap instruksi harus secara eksplisit diharapkan agar bekerja
seluruhnya. Informasi CPUID tidak dapat ditinggalkan dari host langsung ke
target aplikasi. Pertimbangan dukungan instruksi khusus seperti AVX langsung
menggunakan CPUID asli yang membuat aplikasi berpikir dapat menggunakan
instruksi AVX. Oleh karena itu binary translator harus mencegat instruksi
CPUID dan menutupi keluar fitur tersebut.
III.1.5 Analisis Sintaksis
Parsing atau Syntatic Analysis menggunakan DCFG(Dynamic
Control-Flow Graph) yang mana menambahkan data dari sebuah spesifik eksekusi
program. Biasanya CFG didefinisikan secara statis dan tidak mengandung
informasi tentang jalur eksekusi dari setiap beban kerja tertentu. Adapun
kelebihan DCFG antara lain:
1. Sebuah DCFG berisi node awal yang tidak memiliki node pendahulu
dan pengganti node-nya berisi instruksi pertama yang dieksekusi per
penerus dan pendahulunya berisi instruksi terakhir yang dieksekusi
per thread.
2. Setiap edge DCFG ditambah dengan jumlah yang dinamis untuk
menunjukkan berapa kali dilalui per thread oleh eksekusi program
yang diberikan. Kecuali untuk awal dan akhir node, hitungan dinamis
setiap node adalah sama dengan jumlah dari semua edge yang masuk,
yang juga sama dengan jumlah dari semua edge keluar nya.
3. Sebuah DCFG tidak perlu mengandung node atau edge yang tidak
dieksekusi. Sebuah DCFG diperbolehkan mengandung node dan edge
yang tidak dieksekusi atau hanya akan memiliki jumlah nol.
4. Sebuah DCFG berisi edge yang mewakili semua jalur kode eksekusi
sebenarnya, bahkan untuk non-control-flow. Sebagai contoh, sebuah
instruksi floating-point yang menyebabkan pengecualia selama
eksekusi dapat menciptakan keunggulan untuk kode
exception-handling.
Blok di DCFG dapat dikombinasikan menjadi tingkat yang lebih tinggi untuk
konstruksi seperti perulangan, rutinitas dan biner images. Data dinamis seperti
jumlah iterasi loop dapat disimpulkan dari jumlah edge dasar. Format DCFG
memungkinkan penyimpanan informasi pada proses, termasuk images konstituen,
simbol, data debug, dan kontrol.
Jenis dari elemen dideskripsikan menggunakan format JSON yang
mempunyai list untuk setiap strukturnya. Hal tersebut nantinya disimpan
sementara dalam memori untuk mempermudah penerjemahan biner dalam hal
parsing. Adapun spesifikasinya sebagai berikut:
1. Top-level structure
Nilai dari Top-level adalah sebuah objek atau urutan pasangan nilai kunci.
Bagian utama dari aliran DCFG ditandai dalam objek tingkat atas yang
terdaftar secara singkat dibawah dan diperluas dalam sisa dokumen berikut
1. Versi format
2. Daftar pengidentifikasi (id) digunakan untuk referensi string kemudian
di-stream seperti nama file, jenis edge dan node khusus.
3. Data proses berisi id, jumlah instruksi per-thread, serta daftar images
dari biner seperti alamat dan ukuran Load, daftar simbol, sumber
berkas, garis nomor debug data, daftar node blok dasar, daftar rutinitas
dan loop konstituen.
2. Versi
Versi mayor dan minor dari format file terdaftar sebagai dua tag terpisah
di objek tingkat atas. Maksudnya adalah bahwa format DCFG akan kemabali
dan maju secara kompatibel sebanyak mungkin. Kompatibilitas berarti bahwa
versi ke depan tidak harus mengubah tag yang telah ditentukan atau
menghapus data non-opsional. Kompatibilitas ke depan berarti bahwa
penambahan harus dilakukan parser untuk format yang sudah ada harus
mampu membaca format ke depan jika mengabaikan tag yang diketahui.
Jika kompatibilitas rusak, atau jika fitur baru utama ditambahkan, nomor
versi utama harus bertambah dan nomor versi minor ulang ke nol. Jika tidak,
perubahan format lain dibuat nomor versi minor yang bertambah. Ketika
dikonversi ke teks, versi mayor dan versi minor dipisahkan oleh sebuah titik
(".") dan versi minor harus ditampilkan sebagai dua digit yang memungkinkan
hingga versi 99 tanpa kebingungan karena nilai tempat desimal, misalnya 2.03
mendahului 2.12.
3. Nama File
Daftar nama file yang digunakan untuk menghemat ruang adalah dengan
mengizinkan nama file direferensikan nanti oleh pengidentifikasi bilangan bulat,
bukan string panjang yang mungkin perlu diulang berkali-kali. Adapun yang
1. Seperti layaknya semua string, karakter khusus harus lolos memenuhi
format string JSON.
2. Parsers tidak boleh berasumsi bahwa id mulai dengan satu atau berurutan
dalam pemesanan tertentu.
3. Semua nama file yang digunakan dalam aliran DCFG disimpan dalam
tabel yang sama, termasuk untuk images dan file sumber.
4. Jenis Edge
Daftar jenis edge digunakan untuk menghemat ruang dengan mengizinkan
jenis edge untuk kemudian direferensikan dengan pengenal bilangan bulat, bukan
string yang seharusnya perlu diulang berkali-kali. Adapun jenis string edge yang
telah ditentukan dapat dilihat pada tabel berikut:
Tabel III.2 Nilai String Jenis Edge
Nilai String Jenis Edge Keterangan
ENTRY Edge pertama dilalui dalam DCFG yang menjadi
tanda dari mulainya node ke blok dasar pertama
eksekusi
EXIT Edge terkahir dilalui dalam DCFG yang menjadi
tanda dari berakhirnya node ke blok dasar akhir
eksekusi
BRANCH Mewakilkan semua branch yang tidak diketahui
CONDITIONAL_BRANCH Mewakilkan semua jenis conditional branch baik
direct maupun indirect
UNCONDITIONAL_BRANCH Mewakilkan semua jenis unconditional branch baik
direct maupun indirect
DIRECT_BRANCH Sebuah direct untuk conditional branch
DIRECT_CONDITIONAL_BRANCH Sebuah direct untuk conditional branch
INDIRECT_CONDITIONAL_BRANCH Sebuah indirect untuk conditional branch
DIRECT_UNCONDITIONAL_BRANCH Sebuah direct untuk unconditional branch
INDIRECT_UNCODITIONAL_BRANCH Sebuah indirect untuk unconditional branch
REP Sebuah Edge yang mengindikasikan sebuah
instruksi dengan prefix “REP” atau repeated.
FALL_THROUGH Sebuah Edge yang mengindikasikan instruksi pada
alamat selanjutnya telah dieksekusi.
CALL Mewakilkan semua jenis call yang tidak diketahui
DIRECT_CALL Sebuah direct call yang mempunyai satu alamat
statis
INDIRECT_CALL Sebuah indirect call yang mempunyai satu alamat
dinamis
RETURN Sebuah return biasanya dipanggil dari routine
CALL_BYPASS Mengindikasikan control flow dalam sebuah routine
tanpa diikuti call
SYSTEM_CALL Sebuah call khusus ke sistem routine
SYSTEM_RETURN Sebuah return dari sistem routine
SYSTEM_CALL_BYPASS Sama seperti CALL_BYPASS akan tetapi untuk
sistem routine
CONTEXT_CHANGE Sebuah Edge yang dibuat dari semua instruksi
non-control-flow
CONTEXT_CHANGE_RETURN Sebuah return dari handler context-change
CONTEXT_CHANGE_BYPASS Sama seperti CALL_BYPASS akan tetapi untuk
handler context-change
EXCLUDED_CODE_BYPASS Sebuah Edge yang digunakan untuk memlihara
control flow yang tidak termasuk wilayah kode dari
5. Node Khusus
Daftar node khusus digunakan untuk menghemat ruang dengan mengizinkan
node yang akan kemudian direferensikan oleh pengidentifikasi bilangan. Berikut
yang harus diperhatikan adalah:
1. Parser tidak boleh berasumsi bahwa id dimulai dengan satu atau berurutan
dalam urutan tertentu.
2. Parser tidak boleh berasumsi bahwa id tetap atau sama antara DCFG.
Misalnya node “START” mungkin memiliki id=1 dalam satu DCFG dan
id=3 di lain.
6. Data Proses
Semua data untuk proses disimpan dalam objek yang muncul di kolom
PROCESS_DATA dari tabel PROSES. Kunci dalam objek dapat dilihat pada
table sebagai berikut:
Tabel III.3 Proses Objek
Proses Objek Nilai
INSTR_COUNT Integer: jumlah instruksi untuk proses yang melewati
seluruh thread
INSTR_COUNT_PER_THREAD Array: Setiap integer dari setiap jumlah insruksi untuk
proses per-thread
IMAGES Tabel image
EDGES Tabel edge
7. Images
Semua images untuk suatu proses yang disimpan dalam tabel muncul setelah
Tabel III.4 Images
Heading Nilai
IMAGE_ID Integer dapat dimulai dengan nol
LOAD_ADDR Sebuah integer yang mengandung alamat base yang dimuat oleh sistem
operasi
SIZE Sebuah integer yang mengandung ukuran image
IMAGE_DATA Sebuah objek JSON yang mengandung data image
8. Simbol
Semua simbol untuk images yang diberikan, disimpan dalam tabel yang
muncul setelah kunci SYMBOLS dalam data objek images. Adapun
klasifikasinya sebagai berikut:
Tabel III.5 Simbol Images
Heading Nilai
NAME String yang mengandung nama simbol
ADDR_OFFSET Integer yang mengandung alamat base dari relativitas simbol ke alamat load
yang mengandung image
SIZE Sebuah integer yang mengandung ukuran simbol dalam bytes
9. Informasi Sumber
Semua informasi sumber debug images yang diberikan, disimpan dalam tabel
yang muncul setelah kunci SOURCE_DATA dalam data objek images simbol.
Tabel III.6 Informasi Sumber
Heading Nilai
FILE_NAME_ID Integer id dari nama file tabel yang mempresentasikan file sumber kode
dari data debug
LINE_NUM Sebuah integer yang mempresentasikan garis nomor file referensi sumber
kode
ADDR_OFFSET Sebuah integer yang mengandung alamat base dari relativitas data debug
yang mengandung image
SIZE Sebuah integer yang mengandung ukuran data dalam bytes
NUM_INSTR Sebuah integer yang mengandung angka dari instruksi oleh data debug
10.Blok Dasar
Semua blok dasar untuk images yang diberikan, disimpan dalam tabel yang
muncul setelah kunci BASIC_BLOCKS dalam images objek data informasi
sumber. Sebuah blok dasar hanya memiliki satu poin entri dan satu titik keluar.
Dasar blok didefinisikan secara dinamis, sehingga dapat bervariasi dari run-to-run
pada beban kerja yang sama, hal ini bergantung pada edge dalam CFG yang
dilalui. Variasi tersebut dapat mencakup tidak hanya blok dasar yang disertakan
tetapi juga awal dan akhir alamat masing-masing. Adapun klasifikasinya dapat
Tabel III.7 Blok Dasar
Heading Nilai
NODE_ID Sebuah integer id dan harus unik menyeluruh pada proses, tidak
hanya image
ADDR_OFFSET Sebuah integer yang mengandung instruksi pertama dalam relativitas
blok dasar ke alamat load dari image
SIZE Sebuah integer yang mengandung ukuran blok dala bytes
NUM_INSTRS Sebuah integer yang mengandung angka instruksi dalam blok
LAST_INSTR_OFFSET Sebuah integer yang mengandung alamat instruksi akhir dalam
relativitas blok dasar ke alamat pertama instruksi
COUNT Sebuah integer yang mengandung jumlah angka dari waktu blok
yang telah dieksekusi menyeluruh pada thread
11.Routines
Semua informasi rutin untuk images yang diberikan, disimpan dalam tabel
yang muncul setelah kunci ROUTINES dalam data objek images blok dasar.
Rutinitas harus mengikuti aturan berikut:
1. Sebuah routine dapat memiliki hanya satu entri (routine dapat memiliki
beberapa poin exit)
2. Setiap node dalam routines harus dicapai dari entri node. Hal ini berarti
bahwa setiap node harus menjadi penerus langsung (target edge) dari entri
node atau node lain dalam routines. Edge antar routine (call, returns,
context changes, dll) tidak diperbolehkan dalam traversal tersebut.
Namun, setiap node yang dicapai dari entri node tidak diperlukan untuk
berada di routines yang sama. Hal tersebut memungkinkan untuk
pembagian routines ketika ada beberapa node masuk, melompat antara
3. Setiap node dalam routines harus dalam images yang dikandung.
4. Setiap simpul dari suatu images (kecuali awal dan akhir) akan muncul di
tepat satu routine.
Dengan demikian alamat dan ukuran routines tidak akan selalu sesuai dengan
yang ada di tabel simbol. Routines juga dapat dimasukkan dengan edge selain
calls dan dapat keluar selain returns. Adapun spesifikasinya dapat dilihat pada
tabel berikut:
Tabel III.8 Routines
Heading Nilai
ENTRY_NODE_ID Sebuah integer id dari blok dasar
EXIT_NODE_IDS Array dari id blok dasar yang mengindikasikan satu atau lebih edges
yang meninggalkan routine
NODES Tabel node
12.Loops
Semua informasi loop untuk routine disimpan dalam tabel yang muncul di
bawah kolom LOOPS dalam tabel routine. Loop didefinisikan dengan algoritma
standar graph-traversal. Kendala tersebut dapat diberlakukan sebagai berikut:
1. Sebuah loop hanya dapat memiliki satu head node
2. Sebuah loop dapat memiliki beberapa back-edge