rev2_ghidra
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| rev2_ghidra [2025/10/31 17:30] – mbunic | rev2_ghidra [2025/12/01 11:40] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ==== rev2 ==== | ==== rev2 ==== | ||
| - | Uz zadatak je dana samo izvršna datoteka " | + | Uz zadatak je dana samo izvršna datoteka " |
| - | Pokretanjem programa, | + | Pokretanjem programa, |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| Line 15: | Line 15: | ||
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Program je statically | + | Program je statically |
| - | Nakon toga se može pokrenuti naredba, strings da se vidi ima li zanimljivih stringova u datoteci. | + | Nakon toga se može pokrenuti naredba strings da se vidi ima li zanimljivih stringova u datoteci. |
| < | < | ||
| Line 23: | Line 23: | ||
| </ | </ | ||
| - | No ni jedan vraćeni rezultat ne izgleda kao da previše otkriva. Može se također odmah pretražiti | + | No niti jedan vraćeni rezultat ne izgleda kao da previše otkriva. Može se također odmah pretražiti |
| < | < | ||
| Line 29: | Line 29: | ||
| </ | </ | ||
| - | zastavica " | + | zastavica " |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Ovo nam također ništa | + | Ovo nam također ništa korisno ne otkriva o programu, osim što prikazuje tekst koji se ispisuje pri unosu passworda i ispisu pri krivom unosu passworda. |
| Nakon toga se može probati naredba " | Nakon toga se može probati naredba " | ||
| Line 43: | Line 43: | ||
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Također se ne prvi pogled ne mogu pronaći dodatne korisne informacije o programu u ispisu. | + | Također se na prvi pogled ne mogu pronaći dodatne korisne informacije o programu u ispisu. |
| - | Slijedeći korak je korištenje besplatnog Ghidra | + | Sljedeći korak je korištenje besplatnog Ghidra |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| Line 65: | Line 65: | ||
| </ | </ | ||
| - | Na početku main funkcije, | + | Na početku main funkcije, |
| < | < | ||
| Line 77: | Line 77: | ||
| </ | </ | ||
| - | također, vidi se da je drugi argument poziva funkcije | + | također, vidi se da je drugi argument poziva funkcije |
| Treći argument je pointer | Treći argument je pointer | ||
| Line 97: | Line 97: | ||
| </ | </ | ||
| - | odgovarala | + | odgovarala |
| < | < | ||
| Line 103: | Line 103: | ||
| </ | </ | ||
| - | Sad se može označiti varijabla local_118, pritisnuti gumb L i preimenovati u input_buffer. | + | Može se označiti varijabla local_118, pritisnuti gumb L i preimenovati u input_buffer. |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Također se varijable | + | Također se varijabla |
| - | FUN_00404ee0 u fgets. Varijablu lVar2 nećemo preimenovati, | + | FUN_00404ee0 u fgets. Varijablu lVar2 nećemo preimenovati, |
| - | Kako bi se olakšalo praćenje važnih varijabli, varijable koje su bitne u izvođenju programa mogu se označiti i pritiskom desnog klika i opcije highlight, mogu se postaviti da budu bolje naznačenje u ostatku programa. | + | Kako bi se olakšalo praćenje važnih varijabli, varijable koje su bitne u izvođenju programa mogu se označiti i pritiskom desnog klika i opcije highlight, mogu se postaviti da budu istaknuto označenu ostatku programa. |
| - | fgets funkcija pri uspješnom izvršavanju, vraća pointer na string buffer, a ako je vraćena vrijednost NULL, dogodila se greška, što odgovara ovom djelu koda | + | fgets funkcija pri uspješnom izvršavanju vraća pointer na string buffer, a ako je vraćena vrijednost NULL, dogodila se greška, što odgovara ovom dijelu |
| < | < | ||
| Line 122: | Line 122: | ||
| </ | </ | ||
| - | Ako je fgets vratio NULL, varijabla uVar3 se postavlja u 1 i skače se na kraj main funkcije, te se varijabla uVar3 vrača kao return vrijednost main funkcije, zato se varijabla uVar3 može preimenovati u main_func_ret_val. | + | Ako je fgets vratio NULL, varijabla uVar3 se postavlja u 1 i skače se na kraj main funkcije, te se varijabla uVar3 vraća kao return vrijednost main funkcije, zato se varijabla uVar3 može preimenovati u main_func_ret_val. |
| - | Ako se fgets uspješno izvršio, izvršava se else block, koji počinje ovim kodom | + | Ako se fgets uspješno izvršio, izvršava se else blok, koji počinje ovim kodom |
| < | < | ||
| Line 150: | Line 150: | ||
| U tom slučaju bi varijabla | U tom slučaju bi varijabla | ||
| - | Nakon toga, u if statementu, vrijednost varijable | + | Nakon toga, u if statementu, vrijednost varijable lVar2 se uspoređuje s 0x15, odnosno 21 u dekadskom zapisu, što točno odgovara duljini FLAG formata |
| < | < | ||
| Line 156: | Line 156: | ||
| </ | </ | ||
| - | Ako je duljina korisničkog jednaka 21, ulazi se u do - while block, unutar kojega se nalazi switch sa 7 caseva, | + | Ako je duljina korisničkog |
| - | Pregledom switcha, na kraju switcha se odmah može vidjeti case 0, koji samo ispisuje | + | Pregledom switcha, na kraju switcha se odmah može vidjeti case 0, koji samo ispisuje |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Na početku do blocka, se nalazi ova linija | + | Na početku do bloka, se nalazi ova linija |
| < | < | ||
| Line 168: | Line 168: | ||
| </ | </ | ||
| - | koja postavlja varijablu bVar1 na dereferenciranu vrijednost user_input pointera, koji je pointer na string buffer. | + | koja postavlja varijablu bVar1 na dereferenciranu vrijednost user_input pointera, koji je pointer na string buffer. |
| - | može preimenovati u user_input_char. | + | |
| - | U switchu postoji 7 caseva, a case se određuje prema vrijednosti puVar2. | + | U switchu postoji 7 caseva, a case se određuje prema vrijednosti |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| Line 179: | Line 178: | ||
| Vidi se da se u svakom caseu uzima user_input_char, | Vidi se da se u svakom caseu uzima user_input_char, | ||
| - | u case 1 operacija je XOR (^), u case 2 operacije je ADD (+) u case 3 operacije je SUB (-), u case 4 operacije je MUL (*), u case 5 operacija je bitwise SHIFT (<< i >>), u case 6 operacija je bitwise NOT (~) i u case 7 operacije je također ADD (+), kao što je prethodno opisano. | + | u caseu 1 operacija je XOR (^), u caseu 2 operacije je ADD (+) u caseu 3 operacije je SUB (-), u caseu 4 operacije je MUL (*), u caseu 5 operacija je bitwise SHIFT (<< i >>), u caseu 6 operacija je bitwise NOT (~) i u caseu 7 operacije je također ADD (+), kao što je prethodno opisano. |
| odlaskom na adresu gdje je Stack[-0x158] i dvoklikom na XREF[3,12] | odlaskom na adresu gdje je Stack[-0x158] i dvoklikom na XREF[3,12] | ||
| Line 191: | Line 190: | ||
| Još je preostalo pronaći što je varijabla koja određuje koji switch case će biti odabran, operandi u switch caseovima i očekivani rezultati operacija, koji su svi određeni u varijabli puVar2. | Još je preostalo pronaći što je varijabla koja određuje koji switch case će biti odabran, operandi u switch caseovima i očekivani rezultati operacija, koji su svi određeni u varijabli puVar2. | ||
| - | Varijabla puVar2 je definirana pri početku programa i pokazuje na adresu varijable local_158, | + | Varijabla puVar2 je definirana pri početku programa i pokazuje na adresu varijable local_158, |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | No pošto | + | Budući da je program stripped, moguće je da je Ghidra |
| - | Na samoj kraju do blocka, nakon switcha casea-7, se user_input pointer povećava za 1, tako će se za sljedeću iteraciju do blocka | + | Na samom kraju do bloka, nakon switcha casea-7, se user_input pointer povećava za 1, tako će se za sljedeću iteraciju do bloka koristiti |
| - | početak do blocka | + | početak do bloka |
| < | < | ||
| Line 205: | Line 204: | ||
| </ | </ | ||
| - | a puVar2 se povećava za 3 u svakoj iteraciji, što taman odgovara 3 vrijednosti koje se koriste | + | a puVar2 se povećava za 3 u svakoj iteraciji, što taman odgovara 3 vrijednosti koje se koriste u svakom do bloku, puVar2 + 0 određuje koji switch case će se izvršiti, |
| - | u svakom do blocku, puVar2 + 0 određuje koji switch case će se izvršiti, | + | |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Pošto | + | Budući da će se svaki user input character imati jednu vlastitu iteraciju, a puVar2 se povećava za 3 nakon svake iteracije, |
| Ovo se također može vidjeti na slici ispod, while se izvršava sve dok varijabla pbVar2 koja se povećava za 3 nije jednaka adresi spremljenoj na local_119, koja je RSP uvećan za 0x3f, odnosno 63 u dekadskom zapisu, zato što ima 63 byte vrijednosti spremljenih na stacku. | Ovo se također može vidjeti na slici ispod, while se izvršava sve dok varijabla pbVar2 koja se povećava za 3 nije jednaka adresi spremljenoj na local_119, koja je RSP uvećan za 0x3f, odnosno 63 u dekadskom zapisu, zato što ima 63 byte vrijednosti spremljenih na stacku. | ||
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Na slici 16. se vidi da je puVar2 pointer na local_158, sada znamo da local_158 zapravo sadržava 63 byteova, | + | Na slici 16. se vidi da je puVar2 pointer na local_158, sada znamo da local_158 zapravo sadržava 63 bajtova |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| Line 257: | Line 255: | ||
| 0xd5 - 0x92 je 0x43, odnosno 67 u dekadskom zapisu, što odgovara ASCII vrijednosti " | 0xd5 - 0x92 je 0x43, odnosno 67 u dekadskom zapisu, što odgovara ASCII vrijednosti " | ||
| - | Sada se ili ovako " | + | Sada se ili ovako " |
| - | U python | + | U Python |
| < | < | ||
| Line 267: | Line 265: | ||
| I nakon toga možemo samo prekopirati sve linije koje sadržavaju definirane vrijednosti varijable local_158, kao što su prikazane na slici 21. | I nakon toga možemo samo prekopirati sve linije koje sadržavaju definirane vrijednosti varijable local_158, kao što su prikazane na slici 21. | ||
| - | Ovime već imamo validan | + | Ovime već imamo validan |
| - | {{ rev2_ghidra: | + | {{ rev2_ghidra: |
| Dodavanjem ovog koda na kraj, možemo dobiti ispis operacija i očekivanih rezultata koji se izvršavaju u programu. | Dodavanjem ovog koda na kraj, možemo dobiti ispis operacija i očekivanih rezultata koji se izvršavaju u programu. | ||
| Line 275: | Line 273: | ||
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Pokretanjem koda sada dobivamo ispis svih operacija nad korsiničkim unosom i očekivane rezultate tih operacija: | + | Pokretanjem koda sada dobivamo ispis svih operacija nad korisničkim unosom i očekivane rezultate tih operacija: |
| {{ rev2_ghidra: | {{ rev2_ghidra: | ||
| - | Sada se samo Python programski kod za ispis operacija programa može promijeniti da radi inverz operacija za svih 7 slučaja, te tako nađe korisnički input koji bi riješio | + | Sada se samo Python programski kod za ispis operacija programa može promijeniti da radi inverz operacija za svih 7 slučaja, te tako nađe korisnički input koji bi riješio |
| + | |||
| + | < | ||
| + | local_158 = [0] * 63 | ||
| + | |||
| + | local_158[0x38] = 0xca | ||
| + | local_158[0x39] = 7 | ||
| + | local_158[0x3a] = 0 | ||
| + | local_158[0x3b] = 0xcc | ||
| + | local_158[0] = 2 | ||
| + | local_158[1] = 0x92 | ||
| + | local_158[2] = 0xd5 | ||
| + | local_158[3] = 7 | ||
| + | local_158[4] = 0 | ||
| + | local_158[5] = 0xac | ||
| + | local_158[6] = 7 | ||
| + | local_158[7] = 0 | ||
| + | local_158[8] = 0xba | ||
| + | local_158[9] = 7 | ||
| + | local_158[10] = 0 | ||
| + | local_158[0xb] = 0xce | ||
| + | local_158[0xc] = 1 | ||
| + | local_158[0xd] = 0x42 | ||
| + | local_158[0xe] = 0x72 | ||
| + | local_158[0xf] = 1 | ||
| + | local_158[0x30] = 1 | ||
| + | local_158[0x31] = 0xb3 | ||
| + | local_158[0x32] = 0x87 | ||
| + | local_158[0x33] = 4 | ||
| + | local_158[0x34] = 0x89 | ||
| + | local_158[0x35] = 0xf8 | ||
| + | local_158[0x36] = 6 | ||
| + | local_158[0x37] = 0 | ||
| + | local_158[0x10] = 0x7f | ||
| + | local_158[0x11] = 0x4d | ||
| + | local_158[0x12] = 7 | ||
| + | local_158[0x13] = 0 | ||
| + | local_158[0x14] = 0xcb | ||
| + | local_158[0x15] = 4 | ||
| + | local_158[0x16] = 0xf1 | ||
| + | local_158[0x17] = 0xab | ||
| + | local_158[0x18] = 6 | ||
| + | local_158[0x19] = 0 | ||
| + | local_158[0x1a] = 0xce | ||
| + | local_158[0x1b] = 4 | ||
| + | local_158[0x1c] = 0x6b | ||
| + | local_158[0x1d] = 0xbc | ||
| + | local_158[0x1e] = 1 | ||
| + | local_158[0x1f] = 0x7d | ||
| + | local_158[0x3c] = 2 | ||
| + | local_158[0x3d] = 0x98 | ||
| + | local_158[0x3e] = 0xf5 | ||
| + | local_158[0x20] = 0x44 | ||
| + | local_158[0x21] = 1 | ||
| + | local_158[0x22] = 0xe5 | ||
| + | local_158[0x23] = 0xd4 | ||
| + | local_158[0x24] = 7 | ||
| + | local_158[0x25] = 0 | ||
| + | local_158[0x26] = 200 | ||
| + | local_158[0x27] = 4 | ||
| + | local_158[0x28] = 0xdd | ||
| + | local_158[0x29] = 7 | ||
| + | local_158[0x2a] = 5 | ||
| + | local_158[0x2b] = 7 | ||
| + | local_158[0x2c] = 0x9a | ||
| + | local_158[0x2d] = 7 | ||
| + | local_158[0x2e] = 0 | ||
| + | local_158[0x2f] = 0xcc | ||
| + | |||
| + | def reconstructUserInput(operation, | ||
| + | def ret(b): | ||
| + | return chr(b & 0xFF) | ||
| + | match operation: | ||
| + | case 1: # XOR | ||
| + | return ret(expected_result ^ operand) | ||
| + | case 2: # ADD | ||
| + | return ret((expected_result - operand) & 0xFF) | ||
| + | case 3: # SUB | ||
| + | return ret((expected_result + operand) & 0xFF) | ||
| + | case 4: # MUL | ||
| + | # solve (user * operand) & 0xFF == expected_result | ||
| + | # since all values are printable and operand is invertible modulo 256, use brute force | ||
| + | for x in range(256): | ||
| + | if (x * operand) & 0xFF == expected_result: | ||
| + | return ret(x) | ||
| + | case 5: # SHIFT (rotate-left) | ||
| + | n = operand & 7 | ||
| + | for x in range(256): | ||
| + | if ((x << n) | (x >> (8 - n))) & 0xFF == expected_result: | ||
| + | return ret(x) | ||
| + | case 6: # BITWISE NOT (no operand) | ||
| + | return ret((~expected_result) & 0xFF) | ||
| + | case 7: # ADD (no operand) | ||
| + | return ret((-expected_result) & 0xFF) | ||
| + | |||
| + | i = 0 | ||
| + | user_input_solve = "" | ||
| + | while i < 63: | ||
| + | operation = local_158[i] | ||
| + | operand = local_158[i + 1] | ||
| + | expected_result =local_158[i + 2] | ||
| + | |||
| + | userInput = reconstructUserInput(operation, | ||
| + | |||
| + | print(userInput) | ||
| + | |||
| + | user_input_solve += userInput | ||
| + | |||
| + | i += 3 | ||
| + | |||
| + | print(" | ||
| + | |||
| + | </ | ||
| - | {{ rev2_ghidra: | ||
| - | Pokretanjem ovog programa, dobiva se rješenje zadatka | + | Pokretanjem ovog programa dobiva se rješenje zadatka |
| - | {{ rev2_ghidra: | + | {{ rev2_ghidra: |
| ==Napomena== | ==Napomena== | ||
| - | Preporučuje se da kad radite reversing, probate otvoriti datoteku i s drugim alatima za reverzno inženjerstvo, | + | Preporučuje se da kad radite reversing, probate otvoriti datoteku i drugim alatima za reverzno inženjerstvo, |
| - | {{ rev2_ghidra: | + | {{ rev2_ghidra: |
| - | Može se vidjeti da je Binary Ninja odmah uspješno rekonstruirala | + | Može se vidjeti da je Binary Ninja odmah uspješno rekonstruirala |
rev2_ghidra.1761931840.txt.gz · Last modified: 2025/12/01 11:40 (external edit)