Assalamualaikum. Saya akan sedikit membahas basic dalam melakukan reverse engineering elf binnary, reverse engineering sendiri sangat penting apalagi dalam challenge CTF yang biasa nya mempunyai poin yang besar.

The Code

root@kali:~# cat rev.c
#include 
int main(){
	int a,b,c,d;
	a = 306;
	b = 737;
	c = 100 * a + b;
	printf("Enter your passcode : ");
	scanf("%d", &d);
	if(d == c){
		puts("Correct");
	else{
		puts("Incorrect");			
	return 0;
			```
Proof Of Concept
====================================
``` c %}
root@kali:~# gcc rev.c -o rev
root@kali:~# gdb -q rev
(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x0000555555554760 <+0>:    push   rbp
0x0000555555554761 <+1>:    mov    rbp,rsp
0x0000555555554764 <+4>:    sub    rsp,0x10
0x0000555555554768 <+8>:    mov    DWORD PTR [rbp-0x4],0x132
0x000055555555476f <+15>:    mov    DWORD PTR [rbp-0x8],0x2e1
0x0000555555554776 <+22>:    mov    eax,DWORD PTR [rbp-0x4]
0x0000555555554779 <+25>:    imul   edx,eax,0x64
0x000055555555477c <+28>:    mov    eax,DWORD PTR [rbp-0x8]
0x000055555555477f <+31>:    add    eax,edx
0x0000555555554781 <+33>:    mov    DWORD PTR [rbp-0xc],eax
0x0000555555554784 <+36>:    lea    rdi,[rip+0xd9]        # 0x555555554864
0x000055555555478b <+43>:    mov    eax,0x0
0x0000555555554790 <+48>:    call   0x555555554600 <printf@plt>
0x0000555555554795 <+53>:    lea    rax,[rbp-0x10]
0x0000555555554799 <+57>:    mov    rsi,rax
0x000055555555479c <+60>:    lea    rdi,[rip+0xd7]        # 0x55555555487a
0x00005555555547a3 <+67>:    mov    eax,0x0
0x00005555555547a8 <+72>:    call   0x555555554610 <__isoc99_scanf@plt>
0x00005555555547ad <+77>:    mov    eax,DWORD PTR [rbp-0x10]
0x00005555555547b0 <+80>:    cmp    eax,DWORD PTR [rbp-0xc]
0x00005555555547b3 <+83>:    jne    0x5555555547c3 <main+99>
0x00005555555547b5 <+85>:    lea    rdi,[rip+0xc1]        # 0x55555555487d
0x00005555555547bc <+92>:    call   0x5555555545f0 <puts@plt>
0x00005555555547c1 <+97>:    jmp    0x5555555547cf <main+111>
0x00005555555547c3 <+99>:    lea    rdi,[rip+0xbb]        # 0x555555554885
0x00005555555547ca <+106>:    call   0x5555555545f0 <puts@plt>
0x00005555555547cf <+111>:    mov    eax,0x0
0x00005555555547d4 <+116>:    leave  
0x00005555555547d5 <+117>:    ret    
End of assembler dump.

Command set disassembly-flavor intel digunakan agar hasil disassembly menggunakan syntax intel, karena terdapat 2 syntax pada gdb yaitu att dan intel. Sedangkan disass main merupakan command untuk melakukan disassembly pada fungsi main, apabila ingin melakukan disassembly pada fungsi lain bisa menggunakan disass nama_fungsi.

Dari hasil disassembly diatas, terdapat instruksi yang akan memindahkan nilai hex 0x132 ke rbp-0x4 dan 0x2e1 rbp-0x8. Yang apabila 0x132 dan 0x2e1 dikonversi ke decimal akan menghasilkan 306 dan 737 sama seperti nilai dari variable a,b.

0x0000555555554768 <+8>:    mov    DWORD PTR [rbp-0x4],0x132
0x000055555555476f <+15>:    mov    DWORD PTR [rbp-0x8],0x2e1

Selanjutnya nilai 0x132 yang tersimpan pada rbp-0x4 akan dipindahkan ke register eax

0x0000555555554776 <+22>:    mov    eax,DWORD PTR [rbp-0x4]

Lalu terdapat intruksi imul, imul digunakan untuk melakukan operasi perkalian pada intruksi ini terdapat 0x64 ( konversi ke decimal = 100, sama seperti yang di source code), yang akan dikalikan dengan register eax ( nilai 0x132 ), 0x64 * 0x132 = 0x7788, dan hasil kali tersebut akan disimpan di register edx.

0x0000555555554779 <+25>:    imul   edx,eax,0x64

Selanjutnya nilai 0x2e1 yang tersimpan pada rbp-0x8 akan dipindahkan ke register eax

0x000055555555477c <+28>:    mov    eax,DWORD PTR [rbp-0x8]

Sehingga masuk pada intruksi add yang melakukan operasi pertambahan antara 0x2e1 + 0x7788 = 0x7a69 (31337), lalu akan memindahkan nilai 0x7a69 pada eax ke rbp-0xc, setelah itu baru memindahkan user input (scanf) yang tersimpan sementara di rbp-0x10 ke register eax.

0x000055555555477f <+31>:    add    eax,edx
0x0000555555554781 <+33>:    mov    DWORD PTR [rbp-0xc],eax
        --- snip ---
0x00005555555547ad <+77>:    mov    eax,DWORD PTR [rbp-0x10]

Setelah itu intruksi cmp akan melakukan compare antara nilai 0x7a69 yang berada di rbp-0xc dan inputan passcode kita yang berada di eax.

0x00005555555547b0 <+80>:    cmp    eax,DWORD PTR [rbp-0xc]

Apabila hasil compare tidak sama (jne = jump if not equal), maka akan menuju offset 0x5555555547c3 dan mengeluarkan pesan “Incorrect”.

0x00005555555547b3 <+83>:    jne    0x5555555547c3 <main+99>
        --- snip ---
0x00005555555547ca <+106>:    call   0x5555555545f0 <puts@plt>

Sedangkan apabila sama, akan melewati intruksi jne dan dan mengeluarkan pesan “Correct”.

0x00005555555547bc <+92>:    call   0x5555555545f0 <puts@plt>

Dari pembahasan diatas, diketahui bahwa passcode yang valid adalah 31337 Apabila kita sudah mengerti uraian diatas, sebenar nya kita bisa mencari passcode yang tersimpan dalam register secara otomatis tanpa menghitung manual seperti diatas jika kita sudah sedikit mengerti intruksi assembly.

Proof Of Concept #2

Saya memasang breakpoint pada offset 0x00005555555547b0 #<+80>, untuk melihat nilai yang akan di compare dengan inputan kita yang telah tersimpan di rbp-0xc

(gdb) b *0x00005555555547b0
Breakpoint 1 at 0x5555555547b0
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: ~/rev 
Enter your passcode : 123456
Breakpoint 1, 0x00005555555547b0 in main ()
(gdb) x $rbp-0xc
0x7fffffffe244:    0x00007a69
(gdb) print 0x00007a69
$1 = 31337

Karena passcode yang valid sudah diketahui, bisa langsung membuktikan dengan menjalankan program nya.

root@kali:~# ./rev
Enter your passcode : 31337   
Correct

Akhir Kata…

Saya sendiri sebenarnya tidak terlalu ahli dalam reverse engineering, saya menulis posting ini ditujukan kepada siapa saja yang ingin belajar sehingga bisa mendapatkan pengetahuan dasar mengenai reverse engineering. Jadi semoga tulisan ini dapat bermanfaat bagi kita semua.