Analisis Self Modifying Code Menggunakan Dynamic Binary Instrumentation
(2)
(3)
(4)
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 Komputer, Jurusan S1 Teknik Informatika
(5)
Diajukan untuk Menempuh Ujian Akhir Sarjana
TEGUH PRIMAALKO 10109383
PROGRAM STUDI TEKNIK INFORMATIKA
FAKULTAS TEKNIK DAN ILMU KOMPUTER
UNIVERSITAS KOMPUTER INDONESIA
2016
(6)
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
(7)
iv
Bandung, 2 Maret 2016
(8)
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
(9)
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
(10)
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
(11)
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
Predicates,” in Computational Intelligence and Security (CIS), Kunming, 2014.
(12)
[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 Optimization, 2015.
(13)
[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
(14)
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 integritas biner sehingga instruksi program tetap utuh atau tidak menganggu
(15)
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++ sebagaimana API yang disediakan oleh DynamoRIO
(16)
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 sebuah cache code, dimana instruksi dapat bebas dimodifikasi. DynamoRIO
(17)
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 kemudahan akses ke kode stream.
(18)
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
(19)
(20)
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 hampir untuk semua compiler.
(21)
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
(22)
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 table dengan fungsi instrumentasi kemudian memanggil fungsi asli dari hook.
(23)
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 menggambarkan bagaimana seksi tersebut harus disimpan dalam memori.
(24)
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 dapat merubah fungsi dengan sendirinya ketika eksekusi. Teknik tersebut
(25)
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
(26)
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
imul rax, rax or 0x5, rax pushfq
add (rsp), rbx
jmp *rdx ;jump ke 1 dari 4 blok
2. Self-Decrypting
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
(27)
dienkripsi decode:
mov al, byte [rsi] ; Muat karakter dari kunci ke al
xor byte [rsi+38], al ; xor kunci dengan kode yang dienkripsi
inc rsi ; increment alamat dekode loop jmp rsi ; jump ke kode yang didekripsi
3. Self-Extracting
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 assembly:
inject_loop:
cmpb $0x20, (%rax, %rsi, 1) je inject_finished
movb (%rax, %rsi, 1), %r10b xor $0x3, %r10b
movb %r10b, (%rcx, %rsi, 1) inc %rsi
jmp inject_loop
inject_finished: inc %rsi
movb $0xc3, (%rcx, %rsi, 1) push %rdi
push %rcx ret
(28)
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
mov 8(si), ax ; Memulai angka blok
mov 10(si), dx
movb dl, device(bp) ; dl = device yang akan dibaca
movb ah, #0x42
int 0x13
pop si ; Mengeluarkan si ke poin alamat array
!jmp rdeval rdeval:
jc error ; Jump ke disk yang error dibaca
movb al, cl addb bh, al addb bh, al
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
(29)
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:
MOV R1, 00000000 ; R1 = 0 MOV R2, 00000000 ; R2 = 0 MOV R6, 00000000 ; R6 = 0
MOV R7, signature ; deklarasi signature MOV R8, 11111111 ; 4-bit increment dengan 1 loop: UMUL R4,R3,R2,R1 ; multiplikasi
ADD R5,R4,R3 ; tambah words ADD R6,R6,R5
ADC R6,R6,0
ADD R2,R2,R8 ; increment R2 CMP R2, 11111110
BNE loop
MOV R2, 00000000 ; R2 = 0 ADD R1,R1,R8 ; increment R1 CMP R1, 11111110
BNE loop
CMP R6,R7 ; cek signature BNE test_fail_routine JMP test_pass_routine
II.7 Anti Debugging
Anti-debugging adalah salah satu upaya untuk menghambat reverse engineering sehingga analis tidak dapat menggunakan debugger untuk menganalisis program. Teknik ini umum digunakan untuk mencegah pembajakan
(30)
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. PIN yang merupakan perangkat lunak DBI dari Intel kurang unggul dalam hal
(31)
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 menyebabkan performansi aplikasi menjadi lamban. Keluaran yang dihasilkan
(32)
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 meliputi hex editing hingga membuat flow- graph. Beberapa alat analisis biner
(33)
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 menginvokasinya. Koneksi tersebut dapat diikat secara statis maupun dinamis
(34)
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 Translation dapat ditemukan pada mesin virtualisasi seperti Qemu atau VMware.
(35)
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:
if (x + 2 > 5) y = 2;
else y = 3; x++;
t = x + 2
if t > 5 goto l1 y = 3
goto l2 l1: y = 2 l2: x = x + 1
II.15 Reverse Engineer
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 optimasi.
(36)
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 kembali di stack
(37)
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, Self-Decrypting dan Self-Extracting.
(38)
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)
{
checksum[0] += nonce;
checksum[1] ^= DP;
checksum[2] += *DP;
checksum[4] ^= EIP;
mix(checksum);
nonce += (nonce*nonce) | 5;
DP = codeStart + (nonce %
codeSize);
iteration++;
} }
Nonce mempunyai nilai acak(integer) yang tidak pernah sama setiap kali eksekusi. Bagian codeStart, codeEnd dan codeSize didefinisikan pada seksi header program yang diperoleh ketika kompilasi.
(39)
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,... MOV SP,0682h JUMP:
XOR WORD PTR [SI],SI XOR WORD PTR [SI],SP INC SI
DEC SP JNZ JUMP
Berdasarkan kode diatas kunci dekripsi akan berganti dengan multiple execution dikarenakan stack pointer diinilisiasi sebelum looping. Berdasarkan pengamatan dekripsi routine tersebut seharusnya kode enkripsi menggunakan
(40)
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 6. Terakhir jump ke OEP untuk memulai eksekusi executable sebenarnya
(41)
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 menemukan sebuah branch langsung dilakukan pemeriksaan terlebih
(42)
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 ke hash yang sesuai. Alamat kembali cache mungkin dapat terjadi kesalahan.
(43)
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 thread. Hal ini juga berisi node akhir yang tidak memiliki node
(44)
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 ini:
(45)
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 harus diperhatikan untuk nama file adalah:
(46)
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 INDIRECT_BRANCH Sebuah indirect untuk unconditional branch
(47)
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 CFG
(48)
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 kunci IMAGES dalam proses data objek. Adapun klasifikasinya sebagai berikut: UNKNOWN Mewakilkan semua jenis Edge yang tidak diketahui
(49)
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. Adapun klasifikasinya sebagai berikut:
(50)
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 dilihat pada tabel berikut:
(51)
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 routines dan kontrol aliran non-standar lainnya.
(52)
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
(53)
Tabel III.9 Head Loop
Heading Nilai
LOOP_HEAD_NODE_ID Sebuah integer dari blok dasar pada head di loop
LOOP_BACK_EDGE_SOURCE_NODE_IDS Sebuah id integer blok dasar dari nodes yang mengandung branches kembali pada head di loop
LOOP_NODE_IDS Array dari id blok dasar untuk semua nodes dalam loop
PARENT_LOOP_HEAD_NODE_ID Sebuah id integer blok dasar dari head di node yang mengandung loop dalam routine
13.Edges
Semua informasi edge untuk proses tertentu disimpan dalam tabel yang muncul setelah tag EDGE dalam objek proses. Edge ditempatkan di luar data images karena edge sering keluar diantara images yang berbeda. Adapun spesifikasinya dapat dilihat pada tabel berikut:
Tabel III.10 Edges
Heading Nilai
EDGE_ID Sebuahid yang bernilai integer
SOURCE_NODE_ID Sebuah node id khusus atau id blok dasar dari control flow TARGET_NODE_ID Sebuah node ide khusus atau id blok dasar ke control flow EDGE_TYPE_ID Sebuah ide integer yang merupakan jenis edge
COUNT_PER_THREAD Array yang berisi integer dimana setiap integer berisi hitungan eksekusi untuk edge per-thread
(54)
III.1.6 Spesifikasi Intermediate Representation
Representasi menggunakan standar universal sebuah SSA (Static Single Assignment) dari LLVM karena ekspresif dalam human readable assembly language. Adapun spesifikasinya dapat diklasifikasikan sebagai berikut:
1. Identifiers
Identifier dibagi atas dua tipe dasar yaitu global dan local. Identifier global (functions, variabel global) dimulai dengan karakter „@‟. Identifier local (register names, types) dimulai dengan dengan karakter „%‟. Terdapat tiga format untuk identifier tergantung tujuan masing -masing:
1. Nilai yang mempunyai nama direpresentasikan sebagai string dengan prefix-nya. Contoh %foo dan @DivisionByZero. Identifier yang memerlukan karakter lain dalam penamaanya dikurung dengan tanda kutip dua. Karakter khusus di-escape menggunakan “\xx“ dimana xx adalah kode ASCII untuk karakter dalam hexademical. Prefix “\01“ dapat digunakan dalam variabel global untuk penekanan mangling.
2. Nilai yang tidak mempunyai nama direpresentasikan sebagai unsigned numeric dengan prefix-nya. Contoh %12 dan @2.
3. Konstan dibagi atas dua jenis yaitu simple dan dan complex. Konstan simple direpresentasikan dengan Boolean, Integer, Floating Point, Null Pointer dan Token sedangkan complex berupa Struktur, Array, Vector, Zero Initialization dan simpul metadata.
Prefix digunakan karena beberapa kata kunci seperti add, bitcast, ret untuk tipe data primitf seperti void dan i32 tidak boleh konflik dengan variabel nama.
Komentar dipisah dengan penandaan sebuah titik koma „;„ terus sampai akhir
baris.
2. Linkage Types
Semua variabel global dan fungsi mempunyai setidaknya satu dari tipe linkage. Hal ini dapat dilihat seperti pada tabel berikut:
(55)
Tabel III.11 Linkage Types
No Linkage Type Keterangan
1 private Nilai global dengan linkage“private“ hanya dapat diakses langsung oleh objek – objek dalam modulnya
2 internal Sama dengan “private“ akan tetapi nilai dimunculkan sebagai simbol lokal (STB_LOCAL pada ELF) dalam file objek
3 available_externally Global dengan tanda “available_externally” mengizinkan inlining dan optimasi lainny sebagai pengetahuan definisi global diluar modul tersebut.
4 linkonce Global dengan linkage “linkonce“ menandakan penggabungan dengan global lainnya yang mempunyai nama sama ketika linkage terjadi
5 weak Secara semantik sama dengan linkage linkonce kecuali referensinya bisa jadi tidak dihapus
6 common Sebagian besar mirip dengan “weak” tetapi linkage “common” digunakan untuk definisi sementara pada C seperti “int X;” pada skala global
7 appending Global “appending” hanya diterapkan pada variabel pointer ke tipe array
8 extern_weak Semantik linkage ini mengikuti model file objek pada ELF yang mana akan selalu null jika tidak linked
9 linkonce_odr Linkage ini untuk mengindikasikan bahwa global akan selalu digabungkan bersama global yang setara lainnya
10 external Linkage “external“ digunakan jika tidak ada satupun identifier yang dipakai, artinya dapat digunakan dalam menyelesaikan simbol eksternal
(56)
3. Visibility Styles
Seluruh variabel global dan fungsi pada ELF setidaknya mempunyai visibility styles. Hal tersebut dapat dilihat dalam tabel berikut:
Tabel III.12 Visibility Styles No Visibility
Style
Keterangan
1 default Deklarasi tampak untuk modul lainnya dalam shared libraries 2 hidden Mengindikasikan bahwa simbol tidak akan ditempatkan dalam tabel
simbol dinamis
3 protected Menyatakan bahwa simbol akan ditempatkan dalam tabel simbol dinamis tetapi tidak dapat di-override oleh modul lain
Sebuah simbol dengan linkage internal atau private harus mempunyai
“default” visibility. Hal ini dikarenakan setiap pustaka saling berkaitan satu sama lain
4. Comdats
Comdat adalah sebuah objek yang mengandung paket fungsi dan data. Pada Intermediate Representation berisi akses untuk COFF dan file objek ELF. Comdat memiliki seleksi jenis untuk menyediakan input dalam bagaimana linker harus memilih antara kunci dalam dua file objek berbeda.
Syntax:
$<Name> = comdat JenisSeleksi
(57)
Tabel III.13 COMDAT
No Jenis Seleksi Keterangan
1 any Linker memilih kunci COMDAT yang mana saja secara acak. 2 exactmatch Linker memilihkunci COMDAT yang mana saja tetapi seksi harus
mengandung data yang sama
3 largest Linker memilih seksi yang mengandung kunci COMDAT paling besar
4 noduplicates Linker memilih kunci COMDAT yang paling unik pada seksi 5 samesize Linker memilih kunci COMDAT yang mana saja tetapi seksi harus
mengandung banyaknya data yang sama
5. Atribut Parameter
Setiap parameter sebuah tipe fungsi memiliki sebuah atribut parameter yang terkait satu sama lain. Atribut parameter digunakan untuk komunikasi informasi tambahan tentang hasil atau parameter sebuah fungsi. Atribut parameter dianggap sebagai bagian dari fungsi, bukan tipe fungsi, dengan kata lain fungsi – fungsi dengan atribut parameter berbeda dapat memiliki tipe fungsi yang sama. Atribut parameter didefinisikan sebagai berikut:
Tabel III.14 Atribut Parameter
No Parameter Keterangan
1 zeroext Mengindikasikan ke kode generator bahwa parameter atau nilai kembali harus zero-extended untuk jangkauannya dimana diperlukan oleh caller untuk parameter dan callee untuk nilai kembali
2 signext Mengindikasikan ke kode generator bahwa parameter atau nilai kembali harus sign-extended untuk jangkauannya dimana diperlukan oleh caller untuk parameter dan callee untuk nilai kembali
(58)
3 inreg Mengindikasikan bahwa parameter atau nilai kembali harus dianggap spesifik dalam targetnya dengan menempatkannya dalam register sebagai penentang ke memori
4 byval Mengindikasikan bahwa penunjuk parameter harus melewati nilai untuk menuju ke fungsi
5 inalloca Atribut inalloca membolehkan caller untuk mengambil alamat pernyataan stack yang sedang berjalan
6 sret Mengindikasikan parameter pointer menspesifikasikan alamat sebuah struktur yang mana nilai kembali merupakan fungsi dalam sumber program
7 align Mengindikasikan bahwa nilai pointer diasumsikan oleh optimizer untuk mempunyai spesifikasi alignment
8 noalias Mengindikasikan bahwa objek diakses dengan nilai – nilai pointer berdasarkan pernyataan atau nilai kembali
9 nocapture Mengindikasikan bahwa callee tidak membuat salinan pointer yang dipakai lebih lama dari callee itu sendiri
10 nest Mengindikasikan bahwa parameter pointer dapat dipotong menggunakan trampoline instrincs
11 returned Mengindikasikan bahwa fungsi selalu mengembalikan pernyataan sebagai nilai kembali
12 nonnull Mengindikasikan bahwa parameter atau pointer kembali tidak null
13 dereferenceable Mengindikasikan bahwa parameter atau pointer kembali dereferenceable
14 Dereferenceable_or_null Mengindikasikan bahwa parameter atau nilai kembali bukan non-null atau non-dereferenceable pada saat yang sama
6. Atribut Fungsi
Atribut fungsi adalah set komunikasi informasi tambahan tentang sebuah fungsi yang berupa kata kunci sederhana mengikuti spesifikasi tipe. Atribut dapat
(1)
TEST(DYNSMC, getcwd) { char path[PATH_MAX + 1];
char* res = getcwd(path, sizeof(path)); ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]); }
7.
Shared Memory
Pengujian
shared memory
dari pemanggilan proses
TEST(DYNSMC, shmat) {
void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_NE(MAP_FAILED, p);
((char *)p)[10] = *GetPoisoned<U1>(); ((char *)p)[4095] = *GetPoisoned<U1>(); int res = munmap(p, 4096);
ASSERT_EQ(0, res);
int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
ASSERT_GT(id, -1);
void *q = shmat(id, p, 0); ASSERT_EQ(p, q);
EXPECT_NOT_POISONED(((char *)q)[0]); EXPECT_NOT_POISONED(((char *)q)[10]); EXPECT_NOT_POISONED(((char *)q)[4095]); res = shmdt(q);
ASSERT_EQ(0, res);
res = shmctl(id, IPC_RMID, 0); ASSERT_GT(res, -1);
(2)
8.
Pembacaan Direktori
Pengujian baca direktori dilakukan untuk memeriksa apakah
program dapat membaca direktori atau tidak
TEST(DYNSMC, readdir) { DIR *dir = opendir(".");
struct dirent *d = readdir(dir); ASSERT_TRUE(d != NULL);
EXPECT_NOT_POISONED(d->d_name[0]); closedir(dir);
}
9.
Canonicalized Path
Pengujian absolut
pathname
merupakan pengecekan apakah target
program adalah
symbolic links
atau tidak
TEST(DYNSMC, realpath) { const char* relpath = "."; char path[PATH_MAX + 1];
char* res = realpath(relpath, path); ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]); }
10.
Environment Variable
Pengujian untuk mengganti dan mengubah nilai
environ
pada
shell
TEST(DYNSMC, putenv) {
char s[] = "AAA=BBB"; putenv(s);
for (char **envp = environ; *envp; ++envp) {
EXPECT_NOT_POISONED(*envp); EXPECT_NOT_POISONED(*envp[0]); }
(3)
11.
Penyalinan Memori
Pengujian fungsi salin memori pada dari
source
ke
destination
TEST(DYNSMC, memcpy) {
char* x = new char[2]; char* y = new char[2]; x[0] = 1;
x[1] = *GetPoisoned<char>(); memcpy(y, x, 2);
EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); }
12.
Penyalinan String
Pengujian fungsi salin
string
dari
source
ke
destination
TEST(DYNSMC, strcpy) {
char* x = new char[3]; char* y = new char[3]; x[0] = 'a';
x[1] = *GetPoisoned<char>(1, 1); x[2] = 0;
strcpy(y, x); // NOLINT EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); EXPECT_NOT_POISONED(y[2]); }
13.
Cetak Keluaran
(4)
TEST(MemorySanitizer, dr_printf) { char buff[10];
break_optimization(buff); EXPECT_POISONED(buff[0]);
int res = dr_printf(buff, "%d", 1234567); ASSERT_EQ(res, 7);
ASSERT_EQ(buff[0], '1'); ASSERT_EQ(buff[1], '2'); ASSERT_EQ(buff[2], '3'); ASSERT_EQ(buff[6], '7'); ASSERT_EQ(buff[7], 0); EXPECT_POISONED(buff[8]); }
14.
Timestamp
Pengujian
timestamp
dilakukan untuk memperoleh
interval
waktu
eksekusi
TEST(DYNSMC, time) { time_t t;
EXPECT_POISONED(t); time_t t2 = time(&t); ASSERT_NE(t2, (time_t)-1); EXPECT_NOT_POISONED(t); }
15.
Penggunan Resource
Pengujian penggunaan kesuluruhan
resource
program
TEST(DYNSMC, getrusage) { struct rusage usage;
__dyn_poison(&usage, sizeof(usage));
int result = getrusage(RUSAGE_SELF, &usage);
ASSERT_EQ(result, 0);
(5)
EXPECT_NOT_POISONED(usage.ru_utime.tv_usec); EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
EXPECT_NOT_POISONED(usage.ru_stime.tv_usec); EXPECT_NOT_POISONED(usage.ru_maxrss); EXPECT_NOT_POISONED(usage.ru_minflt); EXPECT_NOT_POISONED(usage.ru_majflt); EXPECT_NOT_POISONED(usage.ru_inblock); EXPECT_NOT_POISONED(usage.ru_oublock); EXPECT_NOT_POISONED(usage.ru_nvcsw); EXPECT_NOT_POISONED(usage.ru_nivcsw); }
16.
Operasi Bit
Pengecekan
circular shift
TEST(DYNSMC, LLVMOp) {
if (!TrackingOrigins()) return; BinaryOpOriginTest<S8>(XOR<S8>); BinaryOpOriginTest<U8>(ADD<U8>); BinaryOpOriginTest<S4>(SUB<S4>); BinaryOpOriginTest<S4>(MUL<S4>); BinaryOpOriginTest<U4>(OR<U4>); BinaryOpOriginTest<U4>(AND<U4>); BinaryOpOriginTest<double>(ADD<U4>); BinaryOpOriginTest<float>(ADD<S4>); BinaryOpOriginTest<double>(ADD<double>); BinaryOpOriginTest<float>(ADD<double>); }
IV.2.1.3 Hasil Unit Testing
Berdasarkan pembangunan
unit testing
selanjutnya diserahkan pada
runner
atau kompilasi terhadap program
testing.
Dari pengamatan diatas diperoleh
keluaran sebagai berikut:
(6)
Running main() from gtest_main.cc
[==========] Running 16 tests from 1 test cases. [———-] Global test environment set-up.
[———-] 16 tests from DYNSMC
[ RUN ] DYNSMC.gagalBukaFile
[ OK ] DYNSMC.gagalBukaFile (0 ms) [ RUN ] DYNSMC.Malloc
[ OK ] DYNSMC.Malloc (0 ms) [ RUN ] DYNSMC.StackTest
[ OK ] DYNSMC.StackTest (0 ms) [ RUN ] DYNSMC.StackTest
[ OK ] DYNSMC.StackTest (0 ms)
---dipotong---
[———-] 16 tests from DYNSMC (0 ms total) [———-] Global test environment tear-down
[==========] 16 tests from 1 test cases ran. (0 ms total) [ PASSED ] 16 tests.