Reverse Engineering
Last modified: 2023-09-09
Analyze and get the knowledge of executables.
Investigation
file ./sample
strings ./sample
# -i: Ignore case
# -A: Print N lines of trailing context
# -B: Print N lines of leading context
strings ./example | grep -i password -A 10 -B 10
# -B: signature
binwalk -B ./sample
# Dump hex
hexdump ./sample
# -C: canonical hex+ASCII display
# -n: length
hexdump -C -n 64 ./sample
# Dump hex
hd ./somefile
# -n: only length bytes of input (ex. display the first 28 bytes)
# -s: skip offset bytes from the beginning (ex. no display the first 568 bytes)
hd -n 28 -s 568 example.so
# only display the first 64 bytes
hd -n 64 example.bin
xxd ./sample
xxd ./sample | head
# Hex editor with GUI
ghex ./sample.bin
Security Properties
checksec --file=./sample
- RELRO
Relocation Read-Only, which makes the global offset table (GOT) read-only. - Stack Canaries
Tokens placed after a stack to detect a stack overflow. - NX
Non-Executable. It prevents from shellcode. - RWX
Read-Write-Executable. It's vulnerable to shellcode. - PIE
Position Independent Executable. It loads the program dependencies into random locations.
ELF
# Get information
readelf -a ./sample
# Change MSB <=> LSB by editing binary number.
hexedit ./sample
(MSB) 7F 45 4C 46 02 02 01 ... <=> (LSB) 7F 45 4C 46 02 01 01 ...
Objdump
# -d: disassemble
objdump -d example.obj
# -M: option
objdump -M intel -d example.obj
OLE Files
OLE is a mechanism that allows users to create and edit documents containing items or "objects" created by multiple applications.
-
Oledump
It dumps the information of the OLE files.
oledump.py example.doc # -s: stream number to analyze # -d: dump oledump.py -s 8 -d example.doc oledump.py -s 9 -d example.doc
Then decrypt the output using online tools like CyberChef.
-
Olevba
Download the Oletools to use it.
olevba example.docm
Copy the above Visual Basic code, and access to OneCompiler.
Select the programming language "Visual Basic".
Paste the copied code to the editor, then click Run.
Packer
To check if a binary is compressed with packer such as UPX, dump the hex and extract text related to the packer as below.
# -B: Print before 20 lines from matched string.
# -A: Print after 20 lines from matched string.
hd ./sample | grep UPX -B 20 -A 20
xxd ./sample | grep UPX -B 20 -A 20
If found, we can decompress it.
upx -d ./sample
Debugger, Decompiler
Cutter
Cutter is a reverse engineering platform powered by Rizin.
cutter ./sample
Decompiler Explorer
We can also use Decompiler Explorer online tool.
Ghidra
ghidra ./sample
- If you find “??” instructions in the analyzer of Ghidra, right-click on it and select “Disassemble”.
- If you find “UD2 (Undefined Instruction)” instruction in the analyzer of Ghidra, replace them with “NOP” by right-clicking and selecting “patch instruction”.
ILSpy
It is used for decompiling .NET files.
AvaloniaILSpy is also available for Linux.
Run a Program
chmod 700 sample
./sample
If the program allow you to input some text, you can try first.
Format String Attack
"printf", a function in the C language, is vulnerable to display the internal values from inputs.
# the value of the pointer
> %p
# the value of the 10th pointer
> %10$p
Dynamic Analysis with GDB
GDB is a GNU debugger which is used for reverse engineering.
1. Start the debugger
Before starting, you need to change the permission for the executable so that the program can be executed.
chmod +x ./executable
Now statt gdb.
gdb ./executable
2. Investigation
Find the interesting function and get the address.
gdb> info function
3. Set breakpoints
When you find the interesting function, such as main, strcmp, etc., set the breakpoint at the address.
gdb> break *<address-of-the-function>
# e.g.
gdb> break *0x0000000000400580
By the way, you can delete them if you want.
gdb> info breakpoints
# Delete all breakpoints
gdb> delete
# Delete the specific breakpoint
gdb> delete <the-number-of-the-breakpoint>
# e.g.
gdb> delete 1
gdb> delete 2
4. Run the program
Since you set the breakpoint, the program will stop at the breakpoint.
gdb> run
To observe the information of the current position in the function, run the following command.
gdb> disassemble
# for the specific function
gdb> disassemble <function>
To proceed step by step.
gdb> stepi
# to proceed until the next function
gdb> step
To proceed until the next function.
gdb> continue
5. Examin values of registers
First off, check the address of registers.
gdb> info registers
Then examine values of registers.
-
String
To get the value as string,
gdb> x/s <address-of-the-register> # e.g. gdb> x/s 0x7fffffffdeb0 # or you can specify register names directly gdb> x/s $rax gdb> x/s $rbx gdb> x/s $rcx gdb> x/s $rdx
-
Decimal
To get the value as decimal,
gdb> x/d <address-of-the-register> # e.g. gdb> x/d 0x7fffffffdeb0 # or you can specify register names directly gdb> x/d $rax gdb> x/d $rbx gdb> x/d $rcx gdb> x/d $rdx
6. Quit the debugger
gdb> quit
Tips in GDB
Set addresses to pointers
gdb> set $eip = <address>
# e.g.
gdb> set $eip = 0x565561a9
Set values to registers
Coming soon.
Jump to the destination address
gdb> jump *0x0040096a