Your first legal target
10 mindifficulty: beginner
hello ELF(白名单第 3 类:自行编译产物)。授权链:作者=分析者本人。lab 记录:doc/labs/2026-10-12-lab01。The number-one beginner mistake is not technical — it is pointing tools at the wrong binary. Choose the target first, deliberately. Here is the whitelist we use on this site, in order of preference:
| target class | example | authorization basis |
|---|---|---|
| Self-compiled binaries | hello.c you built today | You made it — total rights |
| Open-source releases | OpenSSL libcrypto (lesson 1) | License grants inspection |
| Official demos/samples | vendor-provided sample files | Provided for study |
| Classic DRM-free games | old shareware-era titles | No protection circumvented |
build the target, record the truth (30 seconds)
The cleanest first target is one you compile yourself — and it comes with a superpower: you know the answer, so you can check your reverse-engineering against it. Source used in our lab:
hello.c + build verified: ran 2026-10-12
#include <stdio.h>
int secret(int x){return x*1337+7;}
int main(){printf("hello realearn %d\n", secret(42));return 0;}
$ gcc -O0 -o hello hello.c
$ ./hello
hello realearn 56161
(预期 42*1337+7 = 56161 ✓ —— 运行时基准,供逆向结果对账)
Note the two compile choices, because they matter: -O0 (no optimization — the machine code mirrors the source) and default not-stripped (symbol names survive). Both are beginner training wheels; lesson 3 takes them off.
identify the artifact
bash — lab@realearn verified: ran 2026-10-12
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8a984d6d..., not stripped
find the function by name
Because the binary is not stripped, the symbol table still lists every function with its address:
bash — lab@realearn verified: ran 2026-10-12
$ readelf -h hello Class: ELF64 / Data: 2's complement little endian / Type: EXEC Machine: Advanced Micro Devices X86-64 / Entry point: 0x400320 $ readelf -s hello | grep -E 'secret|main' 27: 0000000000400406 21 FUNC GLOBAL DEFAULT 3 secret 32: 000000000040041b 38 FUNC GLOBAL DEFAULT 3 main
read the disassembly — and recover the secret
objdump — secret() verified: ran 2026-10-12
$ objdump -d -M intel hello | grep -A8 '<secret>:'
0000000000400406 <secret>:
400406: 55 push rbp
400407: 48 89 e5 mov rbp,rsp
40040a: 89 7d fc mov DWORD PTR [rbp-0x4],edi ; 参数 x 入栈
40040d: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
400410: 69 c0 39 05 00 00 imul eax,eax,0x539 ; ×1337(0x539)
400416: 83 c0 07 add eax,0x7 ; +7
400419: 5d pop rbp
40041a: c3 ret
Read it slowly — this is your first real disassembly. The constants give the whole secret away: imul eax,eax,0x539 is ×1337 (0x539 in hex), add eax,0x7 is +7. So the binary says secret(x) = x*1337 + 7 — which matches the source, and matches the runtime output (42 → 56161). Three independent sources agree: source, disassembly, execution. That is the core habit this lesson teaches: reverse engineering is proposing a verifiable hypothesis, then verifying it.
Two extra observations worth pocketing: the first integer argument arrives in edi (System V ABI — your first calling-convention lesson), and when an AI agent later claims "this function computes x*1337+7", you now know exactly how to audit that claim by hand.
One more thing, honestly stated: with no analysis engine installed, REA's deep analysis on this very binary fails closed with provider_unavailable — while the binutils path you just followed works everywhere, always. The setup guide shows both tiers.
next: Reading a disassembly →