Chapter 34 Exercises: Reverse Engineering
Warm-Up Exercises
Exercise 34.1 — Syntax conversion Convert the following AT&T syntax instructions to Intel syntax:
movq %rbx, %rax
addl $5, %ecx
leaq (%rsp), %rdi
movb $0x41, (%rdi)
subq $0x20, %rsp
Exercise 34.2 — objdump flags
For each task, write the exact objdump command:
a) Disassemble the binary ./mystery using Intel syntax
b) Show the symbol table of ./server
c) Show the dynamic symbols of /usr/bin/curl
d) Show all sections and their addresses in ./program
e) Dump the contents of the .rodata section as hex
Exercise 34.3 — Compiler pattern identification Label each assembly snippet with the C construct it represents:
; Snippet A:
xor eax, eax
jmp .check
.body:
call process
inc eax
.check:
cmp eax, 10
jl .body
; Snippet B:
cmp edi, 3
ja .default
lea rax, [rip+.table]
mov rax, [rax + rdi*8]
jmp rax
; Snippet C:
mov rax, [rdi]
mov rax, [rax+0x18]
call rax
; Snippet D:
test edi, edi
jle .else
call positive_case
jmp .end
.else:
call non_positive_case
.end:
Static Analysis Exercises
Exercise 34.4 ⭐ — Disassembly annotation Annotate the following disassembly with comments explaining each instruction's purpose. Reconstruct the equivalent C function.
0000000000401160 <????>:
401160: 55 push rbp
401161: 48 89 e5 mov rbp,rsp
401164: 48 89 7d f8 mov [rbp-0x8],rdi
401168: 48 89 75 f0 mov [rbp-0x10],rsi
40116c: c7 45 e8 00 00 00 00 mov DWORD [rbp-0x18],0x0
401173: eb 13 jmp 0x401188
401175: 48 8b 45 f8 mov rax,[rbp-0x8]
401179: 0f b6 00 movzx eax,BYTE [rax]
40117c: 84 c0 test al,al
40117e: 75 05 jne 0x401185
401180: ff 45 e8 inc DWORD [rbp-0x18]
401183: eb 03 jmp 0x401188
401185: 48 ff 45 f8 inc QWORD [rbp-0x8]
401189: 48 8b 45 f0 mov rax,[rbp-0x10]
40118d: 48 39 45 f8 cmp [rbp-0x8],rax
401191: 72 e2 jb 0x401175
401193: 8b 45 e8 mov eax,[rbp-0x18]
401196: 5d pop rbp
401197: c3 ret
What are the parameters? What is returned? What does this function compute?
Exercise 34.5 — Jump table analysis The following disassembly includes a jump table. Identify: a) The bounds check instruction b) The jump table load c) How many cases exist d) Reconstruct the switch statement structure
4011a0: 83 ff 04 cmp edi, 0x4
4011a3: 77 2c ja 0x4011d1
4011a5: 89 ff mov edi, edi
4011a7: 48 8d 35 52 0e 00 00 lea rsi, [rip+0xe52] ; .jumptable
4011ae: 48 63 04 be movsxd rax, DWORD [rsi+rdi*4]
4011b2: 48 01 f0 add rax, rsi
4011b5: ff e0 jmp rax
Exercise 34.6 — String extraction Given this disassembly snippet from a program that prints a message:
401204: 48 8d 3d f9 0d 00 00 lea rdi, [rip+0xdf9]
40120b: e8 30 fe ff ff call 0x401040 <puts@plt>
The instruction at 0x40120b is at address 0x40120b and is 5 bytes long. The constant loaded into RDI is rip + 0xdf9 where RIP is the address of the next instruction. Calculate the address of the string and explain how you would read its contents.
Dynamic Analysis Exercises
Exercise 34.7 ⭐ — GDB commands Write the GDB commands to accomplish each task. Assume a stripped binary (no symbols):
a) Set a breakpoint at address 0x40128c
b) Run the program with arguments hello world
c) Display the next 10 instructions from the current position
d) Show the value of all general-purpose registers
e) Show 8 64-bit words from memory at RSP
f) Print the string pointed to by RDI
g) Step one instruction without following calls
h) Step one instruction, following calls
i) Continue until next breakpoint
j) Show a backtrace (even in stripped binary — addresses only)
Exercise 34.8 — GDB Python script
Write a GDB Python script that:
1. Sets a breakpoint at 0x401196 (a hypothetical strcmp call site)
2. When the breakpoint is hit, prints both string arguments (RDI and RSI)
3. Does NOT stop execution — continues automatically
4. Logs all calls to a file named strcmp_log.txt
Exercise 34.9 — pwndbg workflow List five pwndbg commands (not standard GDB commands) that would be useful when analyzing a binary for security research, and describe what each shows.
Pattern Recognition Exercises
Exercise 34.10 — Identify the construct For each disassembly snippet, identify whether it shows: (a) a function call, (b) a virtual method call, (c) a function pointer call through a struct, (d) a tail call, or (e) a leaf function with no frame.
; Pattern 1:
mov rax, [rdi+0x10]
call rax
; Pattern 2:
mov rax, [rdi]
mov rax, [rax+0x28]
call rax
; Pattern 3:
jmp helper_function ; at the end of a function
; Pattern 4:
push rbp
mov rbp, rsp
; ... body with no sub rsp ...
pop rbp
ret
; Pattern 5:
sub rsp, 0x8
call some_function
add rsp, 0x8
ret
Exercise 34.11 — Magic constant identification Identify the algorithm or context associated with each constant:
| Constant | Likely Algorithm/Use |
|---|---|
0x5A4D |
? |
0x7F454C46 |
? |
0xCAFEBABE |
? |
0x9E3779B9 |
? |
0x67452301 |
? |
0xDEADBEEF |
? |
0x80000000 |
? |
0x0000FFFF |
? |
Exercise 34.12 ⭐ — Reconstruct from assembly Reconstruct the complete C source for this function:
; Function takes two arguments
strlen_bounded:
push rbp
mov rbp, rsp
mov [rbp-8], rdi ; arg1: const char *str
mov [rbp-16], rsi ; arg2: size_t maxlen
mov QWORD [rbp-24], 0 ; size_t n = 0
.loop:
mov rax, [rbp-24]
cmp rax, [rbp-16]
jae .done ; if n >= maxlen, stop
mov rax, [rbp-8]
mov rdx, [rbp-24]
movzx eax, BYTE [rax+rdx] ; str[n]
test al, al
je .done ; if str[n] == '\0', stop
inc QWORD [rbp-24] ; n++
jmp .loop
.done:
mov rax, [rbp-24]
pop rbp
ret
Reverse Engineering Challenges
Exercise 34.13 — Crackme analysis Consider a program that calls the following validation function. Without running the program, determine what input produces a return value of 1:
validate:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov [rbp-8], rdi ; input string pointer
; Check length == 6
mov rdi, [rbp-8]
call strlen
cmp rax, 6
jne .fail
; Check first char is 'A' (0x41)
mov rax, [rbp-8]
movzx eax, BYTE [rax]
cmp al, 0x41
jne .fail
; Check last char is 'Z' (0x5A)
mov rax, [rbp-8]
movzx eax, BYTE [rax+5]
cmp al, 0x5A
jne .fail
; Check sum of middle 4 chars == 0x100
mov rax, [rbp-8]
movzx ecx, BYTE [rax+1]
movzx edx, BYTE [rax+2]
add ecx, edx
movzx edx, BYTE [rax+3]
add ecx, edx
movzx edx, BYTE [rax+4]
add ecx, edx
cmp ecx, 0x100
jne .fail
.success:
mov eax, 1
jmp .done
.fail:
xor eax, eax
.done:
leave
ret
a) What are all the conditions the input must satisfy? b) Give three different valid inputs. c) Could you automate finding all valid inputs? Describe how.
Exercise 34.14 — Tool selection For each scenario, choose the most appropriate RE tool and justify your choice:
a) Quick check of what library functions a binary imports b) Deep analysis of a complex, obfuscated malware sample with many cross-references c) Finding all calls to a specific address in a binary while it is running d) Automated analysis of 500 malware samples to find those using RC4 encryption e) Understanding the decompiled logic of a stripped function
Exercise 34.15 ⭐ — Compiler detective
The following two disassemblies compile the same C code, but with different optimization levels. Identify which is -O0 and which is -O2, and explain three specific differences you observe:
; Version A:
f:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov [rbp-4], edi
mov [rbp-8], esi
mov eax, [rbp-4]
add eax, [rbp-8]
leave
ret
; Version B:
f:
lea eax, [rdi+rsi]
ret
Deep-Dive Exercises
Exercise 34.16 — Ghidra workflow Describe the step-by-step process for using Ghidra to analyze a password-protected binary where you want to find the validation logic. Include: where to start, how to navigate, what to look for, and how to confirm your analysis.
Exercise 34.17 — Stripped binary navigation
A stripped x86-64 ELF binary's entry point is at 0x401080. The _start code calls __libc_start_main. Describe in detail how you would use GDB to find the address of main() in this binary without symbols.
Exercise 34.18 — Cross-architecture RE How does reverse engineering ARM64 binaries differ from x86-64? Specifically: a) What are the equivalent patterns for function prologue/epilogue? b) How does the calling convention affect register usage patterns? c) How do you identify a function's return value in ARM64? d) What Ghidra settings or considerations are different?
Exercise 34.19 — Obfuscation recognition Describe how you would identify and handle each of these obfuscation techniques encountered while reverse engineering: a) UPX-packed executable (the binary is compressed) b) Opaque predicates (always-taken or never-taken branches) c) String encryption (strings are decrypted at runtime) d) Control flow flattening (all basic blocks dispatched through a central switch)
Exercise 34.20 ⭐ — Complete RE exercise You are given a binary with no symbols. Using the skills from this chapter:
- It prints something when run with the right argument
stringsshows:"Correct!","Wrong!","Usage: crackme <key>"- The validation function (which you found by following strings cross-refs) is 40 instructions long
Write out the complete analysis workflow you would follow, the GDB commands you would use, and how you would extract the correct key. You do not need to analyze a real binary — describe the methodology in detail, step by step.