- Kita lakukan analisis terhadap file ELF tersebut terlebih dahulu. Kita bisa menggunakan command file namafile. Buat yang belum tahu aja ya ?…
┌─[riordens17@tH4n4ToZ]─[~]
└──╼ $file Downloads/simpleinteger1
Downloads/simpleinteger1: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=dd414a406f088b1ae28ed1c048382eca999de962, not stripped
Dari situ bisa terlihat bahwa file tersebut adalah file ELF 64bit executable. Dia udah static tapi ngga stripped, kalo Reverse Engineering biasanya yang diperhatiin ya itu. 64 bit / 32 bit, static /dynamic , sama stripped / not stripped.
- Disini saya akan melakukan reversing dengan GDB sama IDA, biar lengkap ✌
a. GDB
- Kita Bisa Menggunakan Command gdb namafile , disini saya menggunakan gdb-peda. Bisa cari di google cara masang peda nya. Terus kita lakukan disassembly pada fungsi main. Karena saya make gdb-peda, saya bisa menggunakan pdisas main. Kalo gdb biasa bisanya make disas main (bedanya apa sih ?, ya cuman pdisas itu lebih berwarna & jelas menurut saya). Seperti Ini Tampilannya :
┌─[riordens17@tH4n4ToZ]─[~]
└──╼ $gdb -q Downloads/simpleinteger1
Reading symbols from Downloads/simpleinteger1...(no debugging symbols found)...done.
gdb-peda$ pdisas main
Dump of assembler code for function main:
0x00000000004009ae <+0>: push rbp
0x00000000004009af <+1>: mov rbp,rsp
0x00000000004009b2 <+4>: sub rsp,0x20
0x00000000004009b6 <+8>: mov DWORD PTR [rbp-0x14],edi
0x00000000004009b9 <+11>: mov QWORD PTR [rbp-0x20],rsi
0x00000000004009bd <+15>: mov rax,QWORD PTR fs:0x28
0x00000000004009c6 <+24>: mov QWORD PTR [rbp-0x8],rax
0x00000000004009ca <+28>: xor eax,eax
0x00000000004009cc <+30>: cmp DWORD PTR [rbp-0x14],0x3
0x00000000004009d0 <+34>: jne 0x4009f9 <main+75>
0x00000000004009d2 <+36>: mov rax,QWORD PTR [rbp-0x20]
0x00000000004009d6 <+40>: add rax,0x10
0x00000000004009da <+44>: mov rax,QWORD PTR [rax]
0x00000000004009dd <+47>: mov rsi,rax
0x00000000004009e0 <+50>: mov edi,0x4a1388
0x00000000004009e5 <+55>: mov eax,0x0
0x00000000004009ea <+60>: call 0x40f420 <printf>
0x00000000004009ef <+65>: mov edi,0x4a13a8
0x00000000004009f4 <+70>: call 0x40fe20 <puts>
0x00000000004009f9 <+75>: cmp DWORD PTR [rbp-0x14],0x2
0x00000000004009fd <+79>: jne 0x400a97 <main+233>
0x0000000000400a03 <+85>: mov rax,QWORD PTR [rbp-0x20]
0x0000000000400a07 <+89>: add rax,0x8
0x0000000000400a0b <+93>: mov rax,QWORD PTR [rax]
0x0000000000400a0e <+96>: mov esi,0x4a13cb
0x0000000000400a13 <+101>: mov rdi,rax
0x0000000000400a16 <+104>: call 0x400360
0x0000000000400a1b <+109>: test eax,eax
0x0000000000400a1d <+111>: jne 0x400a70 <main+194>
0x0000000000400a1f <+113>: mov edi,0x4a13d1
0x0000000000400a24 <+118>: mov eax,0x0
0x0000000000400a29 <+123>: call 0x40f420 <printf>
0x0000000000400a2e <+128>: lea rax,[rbp-0xc]
0x0000000000400a32 <+132>: mov rsi,rax
0x0000000000400a35 <+135>: mov edi,0x4a13ea
0x0000000000400a3a <+140>: mov eax,0x0
0x0000000000400a3f <+145>: call 0x40f550 <isoc99_scanf>
0x0000000000400a44 <+150>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000400a47 <+153>: cmp eax,0x150ca89
0x0000000000400a4c <+158>: jne 0x400a5f <main+177>
0x0000000000400a4e <+160>: mov edi,0x4a13f0
0x0000000000400a53 <+165>: call 0x40fe20 <puts>
0x0000000000400a58 <+170>: mov eax,0x0
0x0000000000400a5d <+175>: jmp 0x400ad1 <main+291>
0x0000000000400a5f <+177>: mov edi,0x4a1420
0x0000000000400a64 <+182>: call 0x40fe20 <puts>
0x0000000000400a69 <+187>: mov eax,0x1
0x0000000000400a6e <+192>: jmp 0x400ad1 <main+291>
0x0000000000400a70 <+194>: mov rax,QWORD PTR [rbp-0x20]
0x0000000000400a74 <+198>: add rax,0x8
0x0000000000400a78 <+202>: mov rax,QWORD PTR [rax]
0x0000000000400a7b <+205>: mov rsi,rax
0x0000000000400a7e <+208>: mov edi,0x4a1440
0x0000000000400a83 <+213>: mov eax,0x0
0x0000000000400a88 <+218>: call 0x40f420 <printf>
0x0000000000400a8d <+223>: mov edi,0x4a1460
0x0000000000400a92 <+228>: call 0x40fe20 <puts>
0x0000000000400a97 <+233>: cmp DWORD PTR [rbp-0x14],0x1
0x0000000000400a9b <+237>: jne 0x400acc <main+286>
0x0000000000400a9d <+239>: mov edi,0x4a1488
0x0000000000400aa2 <+244>: mov eax,0x0
0x0000000000400aa7 <+249>: call 0x40f420 <printf>
0x0000000000400aac <+254>: lea rax,[rbp-0xc]
0x0000000000400ab0 <+258>: mov rsi,rax
0x0000000000400ab3 <+261>: mov edi,0x4a13ea
0x0000000000400ab8 <+266>: mov eax,0x0
0x0000000000400abd <+271>: call 0x40f550 <isoc99_scanf>
0x0000000000400ac2 <+276>: mov edi,0x4a14b0
0x0000000000400ac7 <+281>: call 0x40fe20 <puts>
0x0000000000400acc <+286>: mov eax,0x0
0x0000000000400ad1 <+291>: mov rdx,QWORD PTR [rbp-0x8]
0x0000000000400ad5 <+295>: xor rdx,QWORD PTR fs:0x28
0x0000000000400ade <+304>: je 0x400ae5 <main+311>
0x0000000000400ae0 <+306>: call 0x442fe0 <__stack_chk_fail>
0x0000000000400ae5 <+311>: leave
0x0000000000400ae6 <+312>: ret
End of assembler dump.
- Nah, disitu terlihat yang saya block ada function cmp (compare == membandingkan), dia membandingan pointer [rbp-0x14] dengan 0x3 (3 dalam decimal). [rbp-0x14] ini kemungkinan besar adalah argc, Karena dibawahnya juga ada perbandingan yang sama dengan 0x2. Jadi kalo argument nya ada 3 (contoh : ./simpleinteger1 tes1 tes2, disitu simpleinteger1 sbg argument 1, tes1 sbg argument 2,dan tes2 sbg argument 3).
Nah, jika argc == 3, dia akan melakukan printf (0x4009ea), lalu langsung puts(0x4009f4) berarti jika dia tidak meminta inputan kita (scanf) kemungkinan besar cuman tipuan. Di setelah cmp dengan 0x3, ada function jne tuh (jump if not equal). Jadi kalo argc tidak = 3,dia akan melakukan jump ke 0x4009f9 (atau compare [rbp-0x14 dengan 0x2). Selanjutnya kita lihat yang argc == 2.
0x00000000004009cc <+30>: cmp DWORD PTR [rbp-0x14],0x3
0x00000000004009d0 <+34>: jne 0x4009f9 <main+75>
0x00000000004009d2 <+36>: mov rax,QWORD PTR [rbp-0x20]
0x00000000004009d6 <+40>: add rax,0x10
0x00000000004009da <+44>: mov rax,QWORD PTR [rax]
0x00000000004009dd <+47>: mov rsi,rax
0x00000000004009e0 <+50>: mov edi,0x4a1388
0x00000000004009e5 <+55>: mov eax,0x0
0x00000000004009ea <+60>: call 0x40f420 <printf>
0x00000000004009ef <+65>: mov edi,0x4a13a8
0x00000000004009f4 <+70>: call 0x40fe20 <puts>
0x00000000004009f9 <+75>: cmp DWORD PTR [rbp-0x14],0x2
0x00000000004009f9 <+75>: cmp DWORD PTR [rbp-0x14],0x2
0x00000000004009fd <+79>: jne 0x400a97 <main+233>
0x0000000000400a03 <+85>: mov rax,QWORD PTR [rbp-0x20]
0x0000000000400a07 <+89>: add rax,0x8
0x0000000000400a0b <+93>: mov rax,QWORD PTR [rax]
0x0000000000400a0e <+96>: mov esi,0x4a13cb
0x0000000000400a13 <+101>: mov rdi,rax
0x0000000000400a16 <+104>: call 0x400360
0x0000000000400a1b <+109>: test eax,eax
0x0000000000400a1d <+111>: jne 0x400a70 <main+194>
0x0000000000400a1f <+113>: mov edi,0x4a13d1
0x0000000000400a24 <+118>: mov eax,0x0
0x0000000000400a29 <+123>: call 0x40f420 <printf>
0x0000000000400a2e <+128>: lea rax,[rbp-0xc]
0x0000000000400a32 <+132>: mov rsi,rax
0x0000000000400a35 <+135>: mov edi,0x4a13ea
0x0000000000400a3a <+140>: mov eax,0x0
0x0000000000400a3f <+145>: call 0x40f550 <__isoc99_scanf>
0x0000000000400a44 <+150>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000400a47 <+153>: cmp eax,0x150ca89
Langsung saja fokus ke (0x400a1b / test eax,eax). Sebelum melakukan test, dia melakukan call 0x400360 (seharusnya keluar itu call fungsi apa, tetapi Karena ini static jadi dia sudah kehilangan nama / library sudah jadi 1 dengan file). Biasanya test itu digunakan oleh strcmp (string compare / membandingkan antara 2 string). Nah untuk mengetahui dia melakukan test antara string apa dan string apa, kita bisa melakukan break saat call fungsi 0x400360 tsb. Perintah : break address / b address
Bisa juga seperti dibawah ini ya, b *main+104.
gdb-peda$ b *main+104
Breakpoint 1 at 0x400a16
- Lalu kita run , perintah : run / r saja. Jika anda menggunakan gdb-peda, akan keluar guess-argument di bawah. Nah kita bisa lihat di gambar berikut, dia membandingkan string apa dengan string apa. Disini saya menggunakan run 1234 (agar argc == 2).
gdb-peda$ r 1234
Starting program: /home/riordens17/Downloads/simpleinteger1 1234
[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffe3b1 --> 0x554c430034333231 ('1234')
RBX: 0x4002c8 (<_init>: sub rsp,0x8)
RCX: 0x4
RDX: 0x7fffffffe040 --> 0x7fffffffe3b6 ("CLUTTER_IM_MODULE=xim")
RSI: 0x4a13cb --> 0x4d0a00626177616a ('jawab')
RDI: 0x7fffffffe3b1 --> 0x554c430034333231 ('1234')
RBP: 0x7fffffffdee0 --> 0x6ca018 --> 0x43b290 (<strcpy_sse2_unaligned>: mov rcx,rsi)
RSP: 0x7fffffffdec0 --> 0x7fffffffe028 --> 0x7fffffffe387 ("/home/riordens17/Downloads/simpleinteger1")
RIP: 0x400a16 (<main+104>: call 0x400360)
R8 : 0x2
R9 : 0x6
R10: 0x3d ('=')
R11: 0xb ('\x0b')
R12: 0x401650 (<libc_csu_init>: push r14)
R13: 0x4016e0 (<libc_csu_fini>: push rbx)
R14: 0x0
R15: 0x0
EFLAGS: 0x216 (carry PARITY ADJUST zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x400a0b <main+93>: mov rax,QWORD PTR [rax]
0x400a0e <main+96>: mov esi,0x4a13cb
0x400a13 <main+101>: mov rdi,rax
=> 0x400a16 <main+104>: call 0x400360
0x400a1b <main+109>: test eax,eax
0x400a1d <main+111>: jne 0x400a70 <main+194>
0x400a1f <main+113>: mov edi,0x4a13d1
0x400a24 <main+118>: mov eax,0x0
Guessed arguments:
arg[0]: 0x7fffffffe3b1 --> 0x554c430034333231 ('1234')
arg[1]: 0x4a13cb --> 0x4d0a00626177616a ('jawab')
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdec0 --> 0x7fffffffe028 --> 0x7fffffffe387 ("/home/riordens17/Downloads/simpleinteger1")
0008| 0x7fffffffdec8 --> 0x2006ca018
0016| 0x7fffffffded0 --> 0x401650 (<libc_csu_init>: push r14)
0024| 0x7fffffffded8 --> 0xe50a4eb46921b700
0032| 0x7fffffffdee0 --> 0x6ca018 --> 0x43b290 (<__strcpy_sse2_unaligned>: mov rcx,rsi)
0040| 0x7fffffffdee8 --> 0x400d36 (<generic_start_main+582>: mov edi,eax)
0048| 0x7fffffffdef0 --> 0x0
0056| 0x7fffffffdef8 --> 0x200000000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x0000000000400a16 in main ()
Nah kan, 1234 itu inputan saya, dibandingkan dengan string jawab. Brarti kita bisa langsung coba dengan command : r jawab, lalu dia akan segfault, lalu continue saja (command : continue / c).
gdb-peda$ r jawab
Starting program: /home/riordens17/Downloads/simpleinteger1 jawab
[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffe3b0 --> 0x4c4300626177616a ('jawab')
RBX: 0x4002c8 (<_init>: sub rsp,0x8)
RCX: 0x4
RDX: 0x7fffffffe040 --> 0x7fffffffe3b6 ("CLUTTER_IM_MODULE=xim")
RSI: 0x4a13cb --> 0x4d0a00626177616a ('jawab')
RDI: 0x7fffffffe3b0 --> 0x4c4300626177616a ('jawab')
RBP: 0x7fffffffdee0 --> 0x6ca018 --> 0x43b290 (<strcpy_sse2_unaligned>: mov rcx,rsi)
RSP: 0x7fffffffdec0 --> 0x7fffffffe028 --> 0x7fffffffe386 ("/home/riordens17/Downloads/simpleinteger1")
RIP: 0x400a16 (<main+104>: call 0x400360)
R8 : 0x2
R9 : 0x6
R10: 0x3d ('=')
R11: 0xb ('\x0b')
R12: 0x401650 (<libc_csu_init>: push r14)
R13: 0x4016e0 (<libc_csu_fini>: push rbx)
R14: 0x0
R15: 0x0
EFLAGS: 0x216 (carry PARITY ADJUST zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x400a0b <main+93>: mov rax,QWORD PTR [rax]
0x400a0e <main+96>: mov esi,0x4a13cb
0x400a13 <main+101>: mov rdi,rax
=> 0x400a16 <main+104>: call 0x400360
0x400a1b <main+109>: test eax,eax
0x400a1d <main+111>: jne 0x400a70 <main+194>
0x400a1f <main+113>: mov edi,0x4a13d1
0x400a24 <main+118>: mov eax,0x0
Guessed arguments:
arg[0]: 0x7fffffffe3b0 --> 0x4c4300626177616a ('jawab')
arg[1]: 0x4a13cb --> 0x4d0a00626177616a ('jawab')
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdec0 --> 0x7fffffffe028 --> 0x7fffffffe386 ("/home/riordens17/Downloads/simpleinteger1")
0008| 0x7fffffffdec8 --> 0x2006ca018
0016| 0x7fffffffded0 --> 0x401650 (<libc_csu_init>: push r14)
0024| 0x7fffffffded8 --> 0x9bdfcef73f6e2d00
0032| 0x7fffffffdee0 --> 0x6ca018 --> 0x43b290 (<__strcpy_sse2_unaligned>: mov rcx,rsi)
0040| 0x7fffffffdee8 --> 0x400d36 (<generic_start_main+582>: mov edi,eax)
0048| 0x7fffffffdef0 --> 0x0
0056| 0x7fffffffdef8 --> 0x200000000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x0000000000400a16 in main ()
gdb-peda$ c
Continuing.
Masukkan tebakan anda:
Ternyata dia minta inputan kita , berupa masukkan tebakan anda : , kita masukkan saja terserah, lalu lihat assembly selanjutnya setelah test eax eax. kita pdisas main lagi disini.
0x0000000000400a1b <+109>: test eax,eax
0x0000000000400a1d <+111>: jne 0x400a70 <main+194>
0x0000000000400a1f <+113>: mov edi,0x4a13d1
0x0000000000400a24 <+118>: mov eax,0x0
0x0000000000400a29 <+123>: call 0x40f420 <printf>
0x0000000000400a2e <+128>: lea rax,[rbp-0xc]
0x0000000000400a32 <+132>: mov rsi,rax
0x0000000000400a35 <+135>: mov edi,0x4a13ea
0x0000000000400a3a <+140>: mov eax,0x0
**0x0000000000400a3f <+145>: call 0x40f550 <__isoc99_scanf>**
0x0000000000400a44 <+150>: mov eax,DWORD PTR [rbp-0xc]
**0x0000000000400a47 <+153>: cmp eax,0x150ca89**
Kita fokuskan di call scanf (melakukan scan pada inputan kita, lalu melakukan compare eax, dengan 0x150ca89. Disini kita lakukan kembali break di cmp eax,0x150ca89. Bisa gunakan b 0x400a47 / b main+153. Lalu run jawab / r jawab.
gdb-peda$ r jawab
Starting program: /home/riordens17/Downloads/simpleinteger1 jawab
gdb-peda$ c
Continuing.
Masukkan tebakan anda: 1234
- Nah, setelah di run jawab,kita continue hingga dimintai inputan masukkan tebakan anda, isi terserah saja dulu. Disini saya menggunakan angka 1234, lalu gdb akan menampilkan hasil break, lalu kita bisa melihat isi eax, dengan perintah (info registers $eax / i r $eax biar singkat) . lalu terlihat isi eax sekarang. Disitu terlihat 0x4d2.
gdb-peda$ i r $eax
eax 0x4d2 0x4d2
- coba kita convert ke decimal, kita bisa gunakan python. Ketik python, setelah masuk ke shell, masukkan nilai hexadecimalnya.
┌─[riordens17@tH4n4ToZ]─[~]
└──╼ $python
Python 2.7.13 (default, Jan 19 2017, 14:48:08)
[GCC 6.3.0 20170118] on linux2
Type "help", "copyright", "credits" or "license" for more information.
0x4d2
1234
Nah, ternyata itu adalah inputan kita, dan dia membandingkan dengan 0x150ca89. Kita coba convert juga 0x150ca89 ke decimal.
0x150ca89
22071945
Ternyata inputan kita dibandingkan dengan 22071945. Mungkin ini jawabannya :”v , kita coba langsung saja. Command : ./simpleinteger1 jawab. Lalu masukkan 22071945.
┌─[riordens17@tH4n4ToZ]─[~]
└──╼ $./Downloads/simpleinteger1 jawab
Masukkan tebakan anda: 22071945
Selamat tebakan anda menghasilkan hadiah
Dan ternyata Benar :”v, ini mungkin agak ruwet ya kalo make GDB, kalo make IDA lebih gampang sih :3. Kita coba ya sekarang make IDA.
b. IDA
- Kita buka sesuai bitnya, kalo file nya ELF 32bit, buka dengan IDA 32 bit, kalo file nya 64bit, buka dengan 64bit.
- Setelah analisis selesai, kita bisa melakukan decompile pada fungsi main (biar kita bisa mengetahui source codenya) walau ga sesuai.. kita bisa melakukan decompile dengan menggunakan F5.
if ( !sub_400360(v7[1], "jawab", envp) )
{
printf((unsigned __int64)"\nMasukkan tebakan anda: ");
_isoc99_scanf((unsigned __int64)"%d");
if ( v8 == 22071945 )
{
puts("Selamat tebakan anda menghasilkan hadiah \n", &v8);
result = 0;
}
else
{
puts("Maaf tebakan anda belum benar \n", &v8);
result = 1;
}
goto LABEL_12;
}
v5 = v7[1];
printf((unsigned __int64)"Memeriksa tebakan anda %s \n");
puts("tebakan yang anda masukkan salah ", v5);
}
if ( argc == 1 )
{
printf((unsigned __int64)"\nMasukkan angka keberuntungan anda: ");
_isoc99_scanf((unsigned __int64)"%d");
puts("Maaf angka keberuntungan anda belum bisa menghasilkan hadiah \n", &v8);
}
result = 0;
LABEL_12:
v6 = *MK_FP(__FS__, 40LL) ^ v9;
return result;
}
Nah, disitu terlihat jelas,
jika (argc == 3), dia melakukan print memeriksa password, lalu puts password salah.
Jika (argc == 2), dia melakukan perbandingan v7[1] atau (argv[1]) dengan string “jawab”. Argv[1] adalah inputan kita. (Contoh : ./simpleinteger1 jawab 212, disitu simpleinteger1 sebagai argv[0], jawab sebagai argv[1] dan 212 sebagai argv[2]). Brarti jika argv[1] = “jawab” , maka dia akan melakukan printf “Masukkan Tebakan Anda :”), lalu scanf pada inputan kita berupa integer, nah jika inputan kita == 22071945, maka puts “Selamat bla bla” kalo tidak, puts “ Maaf blabla”. Brarti kita bisa simpulan untuk melakukan command : ./simpleinteger1 jawab, lalu memasukkan inputan 22071945. Lebih simple ya kelihatannya, silahkan kalian mau make yang mana .
Sekian dari saya, kalo ada yang salah, tolong para mastah disini membenahi, Karena saya sendiri baru belajar reverse engineering sekitar 1 bulan ini :”v. thanks buat Om Ahmad Prayitno sama SHL