CTF Learning
Balik

Reverse Engineering

Bongkar binary, pahami cara kerjanya

Tools Utama

Ghidra (gratis!)IDA FreeGDB + pwndbgradare2 / rizinobjdumpstrings

Langkah Pertama

Mudah

Sebelum buka disassembler, cek dulu info dasarnya

Reconnaissance awalbash
1# Cek tipe file
2file crackme
3# crackme: ELF 64-bit LSB executable, x86-64...
4
5# Cek proteksi (penting buat pwn juga)
6checksec crackme
7
8# Cari strings menarik
9strings crackme | grep -i flag
10strings crackme | grep -i password
11strings crackme | grep -i correct
12strings crackme | grep -i wrong
13
14# Strings dengan minimum length
15strings -n 10 crackme
16
17# Jalanin dulu, liat behavior
18./crackme
19./crackme password123

Tips

Kadang jawabannya literally ada di strings. Jangan langsung buka Ghidra sebelum cek strings dulu!

Assembly Dasar x86-64

Mudah

Gak perlu jago, yang penting bisa baca

Register pentingasm
1# 64-bit registers:
2RAX, RBX, RCX, RDX → general purpose
3RSI, RDI → source, destination (juga args)
4RSP → stack pointer
5RBP → base pointer
6RIP → instruction pointer (alamat instruksi sekarang)
7
8# Calling convention Linux x64:
9# Argument 1: RDI
10# Argument 2: RSI
11# Argument 3: RDX
12# Argument 4: RCX
13# Return value: RAX
14
15# 32-bit pake E prefix: EAX, EBX, etc.
Instruksi yang sering ketemuasm
1mov rax, rbx ; copy rbx ke rax
2push rax ; taruh rax ke stack
3pop rax ; ambil dari stack ke rax
4
5add rax, 5 ; rax = rax + 5
6sub rax, 5 ; rax = rax - 5
7xor rax, rax ; rax = 0 (cara cepat set 0)
8
9cmp rax, rbx ; bandingkan rax dengan rbx
10test rax, rax ; cek apakah rax == 0
11
12jmp label ; loncat ke label
13je label ; jump if equal (ZF=1)
14jne label ; jump if not equal
15jz label ; jump if zero
16jnz label ; jump if not zero
17
18call func ; panggil fungsi
19ret ; return dari fungsi
20
21lea rax, [rbx+4] ; load effective address (rax = rbx+4)

Pattern Penting: Password Check

1; Biasanya kayak gini:
2mov rdi, user_input ; input user
3mov rsi, correct_pass ; password bener
4call strcmp ; bandingin
5test eax, eax ; hasil di EAX (0 = sama)
6jne wrong ; kalo gak sama, loncat ke wrong
7; ... correct path ...
8
9; Yang perlu kita cari: apa isi correct_pass?
10; Atau: gimana caranya bypass jne?

Pake Ghidra

Mudah

Disassembler + decompiler gratis dari NSA

Workflow di Ghidratext
11. File → Import File → pilih binary
22. Yes untuk analyze
33. Tunggu analysis selesai
4
5Di window utama:
6- Kiri: Symbol Tree (fungsi-fungsi)
7- Tengah: Disassembly (assembly)
8- Kanan: Decompiler (pseudo-C) ← fokus sini
9
10Shortcut penting:
11G → Go to address
12L → Label/rename
13; → Comment
14Ctrl+E → Edit bytes
15X → Cross-references (siapa yg manggil fungsi ini)
16F5 → Refresh decompiler
Contoh output decompilerc
1// Ghidra output (nama fungsi/var bisa di-rename)
2void check_password(char *input) {
3 char correct[16];
4
5 // Hardcoded password!
6 correct[0] = 's';
7 correct[1] = 'e';
8 correct[2] = 'c';
9 correct[3] = 'r';
10 correct[4] = 'e';
11 correct[5] = 't';
12 correct[6] = '';
13
14 if (strcmp(input, correct) == 0) {
15 puts("Correct!");
16 print_flag();
17 } else {
18 puts("Wrong!");
19 }
20}
21
22// Jawaban: password = "secret"

Pattern yang Sering Muncul

Menengah

Soal RE sering pake pattern yang sama

String Compare

Password dicek pake strcmp

XOR Encryption

Flag di-XOR sama key

Character by Character

Tiap karakter dicek satu-satu

Math Operations

Input harus memenuhi persamaan

Pattern: XOR decodec
1// Contoh encrypted flag di binary:
2char encrypted[] = {0x56, 0x51, 0x53, 0x5e, 0x1e, ...};
3char key = 0x37;
4
5// Cara decode:
6for (int i = 0; i < len; i++) {
7 encrypted[i] ^= key;
8}
9// Hasil: "flag{...}"
10
11// Kalo di Python:
12enc = [0x56, 0x51, 0x53, 0x5e, 0x1e]
13key = 0x37
14print(''.join(chr(b ^ key) for b in enc))
Pattern: Character checkc
1// Cek karakter satu-satu
2if (input[0] != 'f') return 0;
3if (input[1] != 'l') return 0;
4if (input[2] != 'a') return 0;
5if (input[3] != 'g') return 0;
6// ... dst
7
8// Solusi: baca aja karakter yang dicek!

Dynamic Analysis: GDB

Menengah

Jalanin program step by step

GDB dasar (pake pwndbg/gef biar enak)bash
1# Jalanin gdb
2gdb ./crackme
3
4# Set breakpoint
5break main # di awal main
6break *0x401234 # di alamat tertentu
7break check_password # di fungsi
8
9# Run
10run
11run argument1 # dengan argument
12
13# Navigation
14n / next # next instruction
15s / step # step into function
16c / continue # lanjut sampai breakpoint
17
18# Liat info
19info registers # isi semua register
20x/s $rdi # print string di RDI
21x/10x $rsp # print 10 hex di stack
22p $rax # print isi RAX
23
24# Modify values (cheat!)
25set $rax = 0 # ubah RAX jadi 0
26set {char}0x404000 = 'A' # ubah memori

Trik: Bypass Check

Kalo ada instruksi jne (jump if not equal), kita bisa:

  • • Set register biar kondisi terpenuhi
  • • Atau skip instruksi jump (set $rip)

Patching Binary

Menengah

Ubah binary biar behavior-nya beda

Kadang lebih gampang patch binary daripada reverse seluruhnya. Misal: ubah jne (jump if not equal) jadi je (jump if equal).

Opcode yang sering dipatchtext
1JNE / JNZ → 75 xx (patch ke 74 = JE)
2JE / JZ → 74 xx (patch ke 75 = JNE)
3JMP → EB xx (short) atau E9 xxxx (near)
4NOP → 90 (no operation, skip instruksi)
5CALL → E8 xxxx
6
7Trik:
8- Ganti JNE ke JE = reverse kondisi
9- Ganti instruksi ke NOP = skip
10- Ganti CALL ke NOP NOP NOP NOP NOP = skip function call
Patch pake Ghidrabash
1# Di Ghidra:
21. Klik instruksi yang mau dipatch
32. Ctrl+Shift+G (Patch Instruction)
43. Ketik instruksi baru
54. File → Export Program → Original File
6
7# Atau pake hex editor (xxd):
8xxd crackme > hex.txt
9# Edit hex.txt, ganti byte yang perlu
10xxd -r hex.txt > crackme_patched
11chmod +x crackme_patched