Reverse engineering starts with looking
Reverse engineering is working out how a program does its job from the program itself, with no source code.
Defenders do it to understand a strange tool on their own server, and to see how a flaw looks before an attacker finds it. Before anything else, one rule: use these tools only on programs made for this lab, on your own copy of it.
By the end of this lesson
Note
I can learn about a program without running it.
Key words
| Word | What it means | Example |
|---|---|---|
| Binary | a program as the computer runs it, a file of machine instructions | |
| ELF | the file format of programs on Linux | |
| String | a run of readable characters inside a file | |
| Symbol | a name inside a program for one of its functions | main |
| Disassembler | a tool that turns machine instructions back into assembly you can read | |
| Stripped | a program with its symbol names removed |
The cells students fill in are left blank in this preview.
The one rule of this module
Important
Read only programs made for the lab, and only your own copy. Never take apart anybody else's software, a licence check, a game or a protection. The reason is defence: you learn how a flaw looks so that it can be found and fixed. Nothing in this module is aimed at a real system.
What a compiled program file is
Source code is the text a person writes. A binary is what the compiler makes from it, and Linux keeps it in the ELF format.
The file command reads the start of a file and says what it is. For a program it names the processor it was built for, and whether it is stripped, with its function names removed, or not stripped.
A practice program called vault
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 2) { puts("usage: vault WORD"); return 2; }
if (strcmp(argv[1], "blue-harbour") == 0) { puts("Door open."); return 0; }
puts("Door shut.");
return 1;
}
Write the practice program
printf '#include <stdio.h>\n#include <string.h>\nint main(int argc, char **argv) {\n if (argc != 2) { puts("usage: vault WORD"); return 2; }\n if (strcmp(argv[1], "blue-harbour") == 0) { puts("Door open."); return 0; }\n puts("Door shut.");\n return 1;\n}\n' > vault.cShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Compile it into a binary
gcc -O0 -no-pie -fno-stack-protector -o vault vault.cShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Ask what kind of file it is
file vaultShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The strings command prints readable text
A program carries its text inside it. strings scans a file and prints every run of readable characters that is long enough, four by default.
The first Run feeds it a few bytes of our own making. Short runs such as ab and xyz are too short at four, so only two words come out. The second Run keeps the lines of vault that matter.
Worked example: runs of at least four
| Run of readable bytes | Length | Printed with a minimum of 4? |
|---|---|---|
| ab | 2 | No, too short |
| hello | 5 | Yes |
| xyz | 3 | No, too short |
| world! | 6 | Yes |
The cells students fill in are left blank in this preview.
Strings on bytes you made
printf 'ab\x01hello\x02xyz\x00world!' | strings -n 4Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The readable text inside vault
strings vault | grep -E "usage|Door|harbour"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think compiling hides what a program says. It only changes the form. Text the program needs, such as a password it compares with, is still inside the file, so a reader can find it. Never keep a secret in a program.
A disassembler turns bytes back into steps
objdump -d is a disassembler: it prints the instructions of a binary as assembly, one step per line.
--disassemble=main asks for one function only. Each call line is a request to another function, with its name in angle brackets. Reading only the names of the calls already tells you a lot, and it does not run anything.
The functions main calls
objdump -d vault --disassemble=main | grep -o "<[a-z]*@plt>"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.