iOS App Security 5. – iOS binárisok statikus analízise, második rész

Ez a cikk legalább 1 éve frissült utoljára. A benne szereplő információk a megjelenés idején pontosak voltak, de mára elavultak lehetnek.

Az alábbi cikket Ys. írta a 0x90 blogon, és mivel a cikksorozata kapcsolódik az iPhone-hoz, mi érdekesnek gondoljuk a számotokra is, így ezeket engedelmével egymás után át is emelnénk ide, a Szifonra.

***

Az előző részben esett szó arról, hogy az iOS-es binárisok statikus analízise elég egyszerű és sok esetben igencsak gyümölcsöző tevékenység. Ezt tudják az Apple-nél is, és amikor egy appot letöltesz az AppStore-ból, akkor a binárisa nem is plain-textben jön, hanem bizonyos részei titkosítva lesznek – pont a bináris felboncolását megnehezítendő. Triviális egyébként rájönni, hogy ilyen binárist küldtél be az IDA Próba, ugyanis ilyenkor a parszer úgy szórja a syntax errorokat, mint hülyegyerek a légpuskalőszert a zalaszentgróti búcsú céllövöldéjében.

Maga a titkosítás egyébként elég egyszerűen megkerülhető, ugyanis amikor az iOS betölti a binárist a memóriába, feloldja a titkosítást és ilyenkor nem kell mást tennünk, mint kilapátolni a dekriptált bájthalmazt és visszaírni az eredeti binárisba.

Hogy találjuk meg a binárist? Amikor telepítünk egy alkalmazást, az a /var/mobile/Applications/[random GUID]/ könyvtárba pakolja a saját fájljait. Itt mindenképp lesz egy XY.App nevű könyvtár, ami az app futtatásához szükséges fájlokat tartalmazza – esetünkben a PhotoVault, de igazoljuk először is.

white-iPhone:/var/mobile/Applications/33347AFA-B579-441D-9A04-8B7DF6A15831/PhotoVault.app root# plutil Info.plist
{
“APP_ID” = 417571834;
“APP_NAME” = “Photo Vault”;
BuildMachineOSBuild = 11D50;
CFBundleDevelopmentRegion = English;
CFBundleDisplayName = “Photo Vault”;
CFBundleExecutable = PhotoVault; […]

Igen, valóban ezt a binárist indítja el az iOS. Tekintsük hát a PhotoVault binárist – amikor letöltjük az AppStore-ból, bizonyos részei titkosítottak (illetve mondjuk, hogy obfuszkáltak). A Mach-O headerök elég elárulják, hogy ez a helyzet:

white-iPhone:/tmp root# otool -l PhotoVault | grep crypt
cryptoff 8192
cryptsize 1970176
cryptid 1

Most jön a dekriptálás, ahogy nálam okosabbak már kitalálták. A menetrend a következő:

  1. Megtudjuk, hogy betöltés után milyen memóriacímek között lesz a dekriptált kód.
  2. GDB-ben elindítjuk az appot és kidumpoljuk a vonatkozó részeket.
  3. Visszamásoljuk az eredeti binárisba a kinyert kódot.
  4. Megpatkoljuk a Mach-O headeröket egy hexaeditorral.
  5. Profit.

1. Megtudjuk, hogy betöltés után milyen memóriacímek között lesz a dekriptált kód.

Lássuk a vonatkozó szegmensek méretét. A kódokat az ARMv7-es szegmensre mutatom meg – a bináris egy fat binary, emiatt ki is hagyom a másik architektúrára vonatkozó részeket. A vastagított sorok fontosak. Kis disclaimer: a szkriptsuttyók távoltartására néhol pontatlanok a címek. A logika stimmel, az összegek úgyszintén, de ha szó szerint ezt a címtartományt dumpolod ki, akkor egyszerűen nem fog működni a binárisod.

Lássuk a Mach-O fejlécek alapján a bináris szegmenseit.

white-iPhone:/var/mobile/Applications/33347AFA-B579-441D-9A04-8B7DF6A15831/PhotoVault.app root# otool -f PhotoVault
[…]
architecture 1
cputype 12
cpusubtype 9
capabilities 0x0
offset 2469888
size 2442336

align 2^12 (4096)
[…]

…és a titkosított blokk offszetjét és méretét. A cryptoff mutatja meg, hogy mekkora offszettel kezdődik az ARMv7-es blokk kezdetétől a titkosított adatkupac, a size meg értelemszerűen a mérete.

white-iPhone:/tmp root# otool -arch armv7 -l PhotoVault | grep crypt
cryptoff 8192
cryptsize 1945600

cryptid 1

Tehát (cryptoff + 0x1000)-től (cryptoff + 0x1000 + cryptsize)-ig lesz a dekriptált cucc. A 0x1000 azért kell bele, mert a mappelésnél nem 0x0000-val kezdődik a címtér, hanem 0x1000-rel.

2. GDB-ben elindítjuk az appot és kidumpoljuk a vonatkozó részeket.

Amikor az app befejezte a beltöltődést, akkor meghívódik a doModInitFunctions nevű függvény. Erre ráakaszkodunk és kitoljuk egy bela.out nevű fájlba a dekriptált jóságot.

(gdb) white-iPhone:/var/mobile/Applications/33347AFA-B579-441D-9A04-8B7DF6A15831Vault.app root# gdb -q -e ./PhotoVault
Reading symbols for shared libraries . done
(gdb) set sharedlibrary load-rules “.*” “.*” none
(gdb) set inferior-auto-start-dyld off
(gdb) set sharedlibrary preload-libraries off
(gdb) rb doModInitFunctions
Breakpoint 1 at 0x2fe0c6d2
__dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE;
(gdb) r
Starting program: /private/var/mobile/Applications/33347AFA-B579-441D-9A04-8B7DF6A15831/PhotoVault.app/PhotoVault
Breakpoint 1, 0x2fe0c6d2 in __dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE ()
(gdb) dump memory bela.out 0x3000 0x1DE000
(gdb) kill
Kill the program being debugged? (y or n) y
(gdb) q

3. Visszamásoljuk az eredeti binárisba a kinyert kódot.

Megvan a dekriptált jóság, most visszamásoljuk a binárisba. Ehhez dd-t használunk a fejlécek alapján összerakott offszetekkel:

offset = architecture offset (2469888)+ encryption offset (8192)

# dd seek=2478080 bs=1 conv=notrunc if=bela.out of=PhotoVault

Ez eltart egy darabig, de végül lefut.

4. Megpatkoljuk a Mach-O headeröket egy hexaeditorral.

Használjunk mindehhez egy jó hexaeditort és tekerjünk a binárisban ahhoz a részhez, amilyen offszettel bemásoltuk a plain-text jóságot. Ugorjunk a fájl eleje felé 0x1000 bájtot és itt lesz egy olyan, egyetlen darab byte, aminek a konkrét offszetje sajna változhat, nem fix. Ami biztos, a dinamikus dependecyk listája előtt kell keresgélni. Nálam így fest:

0025BA20 2F 75 73 72 2F 6C 69 62 2F 64 79 6C /usr/lib/dyl
0025BA2C 64 00 00 00 1B 00 00 00 18 00 00 00 d...........
0025BA38 55 28 07 34 A9 5F 3A 73 8E 37 50 CE U(.4._:s.7P.
0025BA44 45 82 04 B7 25 00 00 00 10 00 00 00 E...%.......
0025BA50 00 00 04 00 00 00 00 00 05 00 00 00 ............
0025BA5C 54 00 00 00 01 00 00 00 11 00 00 00 T...........
0025BA68 00 00 00 00 00 00 00 00 00 00 00 00 ............
0025BA74 00 00 00 00 00 00 00 00 00 00 00 00 ............
0025BA80 00 00 00 00 00 00 00 00 00 00 00 00 ............
0025BA8C 00 00 00 00 00 00 00 00 00 00 00 00 ............
0025BA98 00 00 00 00 00 00 00 00 00 00 00 00 ............
0025BAA4 A8 31 00 00 00 00 00 00 21 00 00 00 .1......!...
0025BAB0 14 00 00 00 00 20 00 00 00 10 1E 00 ..... ......
0025BABC 00 00 00 00 0C 00 00 00 50 00 00 00 ........P...
0025BAC8 18 00 00 00 02 00 00 00 00 00 01 00 ............
0025BAD4 00 00 01 00 2F 53 79 73 74 65 6D 2F ..../System/
0025BAE0 4C 69 62 72 61 72 79 2F 46 72 61 6D Library/Fram
0025BAEC 65 77 6F 72 6B 73 2F 49 6D 61 67 65 eworks/Image
0025BAF8 49 4F 2E 66 72 61 6D 65 77 6F 72 6B IO.framework
0025BB04 2F 49 6D 61 67 65 49 4F 00 00 00 00 /ImageIO....
--- PhotoVault --0x25B8F8/0x4AF460---------------------

A kivastagított bájtot kiütjük és megnézzük, hogy az otool -l mit mond a patkolt binárisra.

white-iPhone:/tmp root# otool -l pv_clutch | grep crypt
cryptoff 8192
cryptsize 1970176
cryptid 0

Öröm, bódottág, a binárisunk plain-text. Mehet rá a class-dump.

5. Profit.

Izzadós volt, nem? De. Szerencsére tök jól szkriptelhető a folyamat és ezt már okos emberek megírták – a konkrét eszközt nem mondom meg, de ha rákerestek a megfelelő kifejezésekre, az első oldalon ott lesz a google találatai között.

Ezek még érdekelhetnek:


  1. Ez tényleg hasznos volt. Holnap megyünk Édesanyámhoz grillezni. Elmondom neki is. Nehogy kimaradjon a jóból. Meg ki is nyomtattam a cikket, mert jól jöhet nyaralásnál is. Vagy ki tudja…

  2. @taky1974: Attól, hogy nem értesz hozzá, nincs szükség a szarkasztikus megjegyzésekre. Gondolom, használtál már crackelt alkalmazást (!?)…
    ***
    Egyébként a “konkrét eszköz”, amit a cikkíró nem említ meg, az a poedCrack BASH szkript. Persze nem illegálisan, törésre használni! Csak fejlesztéshez szükséges visszafejtésre.

  3. @admin:
    Legalább valaki érti a viccet.
    Gyerekek! Azért nem olyan komoly ez az oldal. Egyszer-egyszer el lehet sütni egy poént nem?
    Ebben a nagy válságban besavanyodtatok??

Írd le a véleményedet! (Moderációs elveinket ide kattintva olvashatod.)

Hozzászólás írásához be kell jelentkezned!