W świecie Linuksa, gdzie bezpieczeństwo, kontrola nad kodem i inżynieria wsteczna są codziennością, narzędzia do analizy binarnej odgrywają kluczową rolę. Jednym z najbardziej zaawansowanych frameworków w tej dziedzinie jest angr — platforma do analizy binariów, która łączy symboliczną egzekucję, dekompilację i analizę przepływu sterowania w jednym zestawie narzędzi.
Do czego służy angr?
angr to zestaw bibliotek w Pythonie, które umożliwiają:
- Dekompilację i lifting kodu maszynowego do reprezentacji pośredniej
- Symboliczną egzekucję — analizę możliwych ścieżek wykonania programu
- Analizę przepływu sterowania (control-flow analysis)
- Analizę zależności danych (data-dependency analysis)
- Instrumentację programu — modyfikację i śledzenie działania kodu
- Rozwiązywanie zadań CTF i eksplorację luk bezpieczeństwa
To narzędzie jest szczególnie cenione przez zespoły bezpieczeństwa, badaczy akademickich i uczestników zawodów typu Capture The Flag.
Jak używać angr?
angr działa jako biblioteka Pythona i może być używana w skryptach lub interaktywnie (np. w IPythonie). Przykładowe użycie (Python):
import angr
project = angr.Project("/bin/bash")
cfg = project.analyses.CFGFast()
Użytkownik może:
- Załadować binarium jako projekt
- Uruchomić analizę CFG (Control Flow Graph)
- Przeprowadzić symboliczną egzekucję
- Zdefiniować punkty wejścia, warunki zakończenia i ścieżki eksploracji
angr wspiera wiele formatów binarnych (ELF, PE, Mach-O) i architektur (x86, ARM, MIPS).
Historia dekompilacji i narodziny angr
Dekompilacja jako technika sięga lat 70., kiedy to inżynierowie zaczęli analizować kod maszynowy w celu debugowania. Przez dekady dominowały narzędzia komercyjne (IDA Pro) i później open-source’owe (Ghidra, Radare2).
angr powstał jako projekt akademicki w laboratoriach bezpieczeństwa UC Santa Barbara i Arizona State University, wspierany przez zespół CTF Shellphish. Od tego czasu stał się jednym z najważniejszych narzędzi w arsenale analityków bezpieczeństwa i badaczy.
Źródło: GitHub – angr/angr
Popularność dekompilacji w dzisiejszym security
Dekompilacja i analiza binarna są dziś fundamentem pracy zespołów bezpieczeństwa:
- Malware analysis — zrozumienie mechanizmów infekcji
- Reverse engineering — analiza aplikacji zamkniętoźródłowych
- Bug bounty — eksploracja aplikacji w celu wykrycia luk
- Red teaming — identyfikacja wektorów ataku
- DevSecOps — automatyczna analiza komponentów binarnych
angr wyróżnia się tym, że pozwala nie tylko na pasywną analizę, ale także na aktywną eksplorację ścieżek wykonania programu.
Praktyczne zastosowania angr
- Rozwiązywanie zadań CTF i konkursów bezpieczeństwa
- Analiza malware i złośliwego kodu
- Weryfikacja działania aplikacji bez dokumentacji
- Automatyzacja inspekcji binariów
- Edukacja w zakresie inżynierii wstecznej
Moduły i komponenty angr
angr składa się z wielu modułów, które można używać niezależnie lub w ramach pełnej analizy:
Moduł / Komponent | Opis |
---|---|
angr.Project | Ładowanie binariów jako projekt |
CFGFast / CFGAccurate | Analiza przepływu sterowania (szybka vs dokładna) |
SimState | Reprezentacja stanu symbolicznego |
SimProcedure | Definicja procedur systemowych i bibliotekowych |
ExplorationTechnique | Strategie eksploracji ścieżek wykonania |
Claripy | Solver SMT do rozwiązywania warunków logicznych |
VEX IR | Reprezentacja pośrednia kodu maszynowego |
Decompilation | Generowanie pseudokodu z kodu maszynowego |
Przykładowy kod zdekompilowany przey pomocy angr
extern struct_0 *g_403fe8;
void sub_401000()
{
if (g_403fe8)
g_403fe8();
return;
}
extern unsigned long long g_403fa8;
extern unsigned long long g_403fb0;
void sub_401020()
{
unsigned long v0; // [bp-0x8]
v0 = g_403fa8;
goto g_403fb0;
}
void sub_401030()
{
void* v0; // [bp-0x8]
v0 = 0;
sub_401020();
return;
}
void sub_401040()
{
unsigned long long v0; // [bp-0x8]
v0 = 1;
sub_401020();
return;
}
void sub_401050()
{
unsigned long long v0; // [bp-0x8]
v0 = 2;
sub_401020();
return;
}
void sub_401060()
{
unsigned long long v0; // [bp-0x8]
v0 = 3;
sub_401020();
return;
}
int main()
{
unsigned int v0; // [bp-0x11e]
char v1[2]; // [bp-0x11a]
char v2; // [bp-0x118], Other Possible Types: unsigned int
char v3; // [bp-0x114]
strncpy(v1, "h4x0r", 5);
__printf_chk(1, "Enter the password: ");
__isoc99_scanf("%255s", &v2);
if (v0 == v2 && v1 == *((short *)&v3))
{
puts("Good boy!");
return 0;
}
puts("Bad boy!");
return 0;
}
void _start(unsigned long a0, unsigned long a1, unsigned long long a2)
{
unsigned long long v1; // [bp+0x0]
unsigned long v2; // [bp+0x8]
unsigned long long v3; // rax
v1 = v3;
__libc_start_main(main, v1, &(char)v2, init, fini, a2, &v1, v1); /* do not return */
}
void sub_40119e()
{
[D] Unsupported jumpkind Ijk_SigTRAP at address 4198814()
}
void sub_40119f()
{
sub_4011a0();
return;
}
void sub_4011a0()
{
return;
}
long long sub_4011c9()
{
return 0;
}
extern unsigned long long g_403ff8;
extern unsigned long long g_404008;
extern char g_404010;
void sub_401210()
{
if (g_404010)
return;
if (g_403ff8)
__cxa_finalize(g_404008);
sub_4011a0();
g_404010 = 1;
return;
}
void sub_401250()
{
}
extern struct_1 g_403da0;
void init(unsigned int a0, unsigned long long a1, unsigned long long a2)
{
void* v1; // rbx
sub_401000();
v1 = 0;
do
{
*((long long *)((char *)&g_403da0.field_0 + 0x8 * v1))(a0, a1, a2);
v1 += 1;
} while (v1 != 1);
return;
}
void fini()
{
return;
}
void sub_4012d8()
{
return;
}
Korzyści dla programisty
- Zrozumienie działania kodu niskopoziomowego
- Umiejętność analizy cudzych aplikacji
- Rozwój kompetencji w zakresie bezpieczeństwa
- Nauka przez praktykę i eksplorację
- Automatyzacja analizy binariów w projektach CI/CD
angr to narzędzie, które łączy moc analizy symbolicznej z elastycznością Pythona. Dla użytkowników Linuksa, którzy chcą zgłębić tajniki działania aplikacji, zrozumieć malware lub rozwiązywać złożone problemy bezpieczeństwa — angr jest nie tylko przydatny, ale wręcz niezbędny.