Reverse-Engineering & Exploitation Fundamentals
GCC 2022 (Taiwan-Online)
Overview
We've prepared this series of lectures and mini-challenges to teach the fundamentals of
Reverse-Engineering and Exploitation.
If you need supplementary materials, you can find more in our omu platform.
Specifically, the ASM (x86-64) module would be most relevant.
# Lesson 1: x86-64 Assembly
Learn about the basic building blocks running our computer programs!
## Challenges
Mini #1: Move It!
For this challenge, we will familiarise ourselves with the basics operations of copy (mov
)ing data from register to memory, and vice versa.
In omulator, we have an input memory region from 0x1000-0x1fff
, and output in 0x2000-0x2fff
.
We will refer to these regions as IN and OUT.
Write the x86-64 assembly code to do the following:
- 1. Copy the value from
rdi
torax
.- 2. Copy 1 DWORD from input (at address
0x1000
) toebx
.- 3. Copy the DWORD value from
esi
to output (at address0x2000
).Hint: An example for loading a
DWORD
from memory ismov eax, DWORD PTR [r9]
.Click the to test your solution.
You can also click on each test case to load their input values as the omulator's initial state.
To simplify your experience, r8
is initialised to 0x1000
(IN), and r9
to 0x2000
(OUT).
Initializing...
Mini #2: Two Plus Two Is Four Minus One Thats Three
In this challenge, we will do some simple arithmetic operations.
Write the x86-64 assembly code to do the following:
Given 3 values stored in
rdi
,rsi
,rdx
, and aWORD
value in IN(call itn
):
- 1. Save the result of
rdi
+rsi
-rdx
*n
intorax
.- 2. Save the result (
QWORD
) ofrdi
+rsi
-rdx
*n
into the OUT.Click the to test your solution.
You can also click on each test case to load their input values as the omulator's initial state.
To simplify your experience, r8
is initialised to 0x1000
(IN), and r9
to 0x2000
(OUT).
Initializing...
Mini #3: Height Check
In this challenge, we will do some simple control flow branching.
Write the x86-64 assembly code to do the following:
Given
n
(stored inrdi
) values stored in IN:
- 1. For each of
BYTE
valuex
taken from IN:
- i. If
x > 0x50
, writex - 0x37
to OUT.- ii. Else, write
x + 0x13
to OUT.Hint: Note that values from
0x80
to0xff
are considered as negative values when they are aBYTE
(because MSB is set). Make sure you use the unsigned versions of thejcc
instructions.Click the to test your solution.
You can also click on each test case to load their input values as the omulator's initial state.
To simplify your experience, r8
is initialised to 0x1000
(IN), and r9
to 0x2000
(OUT).
Initializing...
# Lesson 2: Linux Reverse-Engineering
Reversing programs written for Linux operating systems >:)
## Challenges
Mini #1: intern decompiler
For the following challenges, we will provide a snippet of assembly code (x86-64) generated from a C function.
In the panel on the right, you are expected to write the corresponding C code to create a function that would match the behaviour of the assembly snippet provided.
Tip #1: Register convention
The register convention used by our code snippets follow the System V ABI, which is the default with GCC on Linux.
The most important piece of information you need from the link is this:
This is a 64-bit platform. The stack grows downwards. Parameters to functions are passed in the registers rdi, rsi, rdx, rcx, r8, r9, and further values are passed on the stack in reverse order.
...
The return value is stored in the rax register
Make sure you place your return value in rax
!
We'll start easy with this one, try to read each instruction and understand what's going on.
Quiz
Write the equivalent C code for the following assembly (x86-64) snippet.
Assembly (x86-64)
C code
Mini #2: junior decompiler
This should be a code structure that you use very often when programming!
Quiz
Write the equivalent C code for the following assembly (x86-64) snippet.
Assembly (x86-64)
C code
Mini #3: middle decompiler
The final challenge, you're almost there!
Quiz
Write the equivalent C code for the following assembly (x86-64) snippet.
Assembly (x86-64)
C code
## Resources
# Lesson 3: Buffer Overflows
First steps in exploitation!
## Challenges
Mini #1: No Touching!
For this challenge, you will be trying to create buffer overflow exploit payloads yourselves.
Each of the following mini-challenges will provide you with a code snippet, that has code reflected in the omulator.
The code snippets call the custom gets()
function, which will read input from IN till it reaches a null (00
) byte.
Your goal is to provide the right payload in IN to cause the program to trigger the win()
function!
Write a payload in IN that will achieve the following:
- 1. call win()
Click the to test your solution.
C code:
int main() {
char buf[16];
int untouched = 0;
gets(buf);
if (untouched) { // How can you change this?
win();
}
}
Initializing...
Mini #2: Mind-control
Write a payload in IN that will achieve the following:
- 1. call win()
Click the to test your solution.
Tip: Remember that integers are stored in little-endian in x86-64 cpus.
C code:
int main() {
char buf[16];
int untouched = 0;
gets(buf);
if (untouched == 0xdeadbeef) { // How can you control this value?
win();
}
}
Initializing...
Mini #3: Teleportation
Write a payload in IN that will achieve the following:
- 1. call win()
Click the to test your solution.
Tip: What else could we overwrite other than user variables?
C code:
int main() {
char buf[16];
gets(buf);
}
// Never called in main! How can we even reach this?
void win(){
...
}
Initializing...