Hogyan kukkants be a bináris fájlokba a Linux parancssorból

Van rejtélyes fájlja? A Linux file parancs gyorsan megmondja, hogy milyen típusú fájlról van szó. Ha azonban bináris fájlról van szó, még többet megtudhat róla. fájlban számos istállótárs található, amelyek segítenek az elemzésben. Megmutatjuk, hogyan kell néhány ilyen eszközt használni.

Fájltípusok azonosítása

A fájlok általában rendelkeznek olyan jellemzőkkel, amelyek lehetővé teszik a szoftvercsomagok számára, hogy azonosítsák, milyen típusú fájlról van szó, valamint hogy mit képviselnek a benne lévő adatok. Nem lenne értelme PNG-fájlt MP3-lejátszóban megnyitni, ezért hasznos és gyakorlatias is, ha egy fájl valamilyen azonosítót tartalmaz.

Ez lehet néhány aláírás bájt a fájl legelején. Ez lehetővé teszi, hogy egy fájl egyértelműen kifejezze a formátumát és tartalmát. Néha a fájltípusra magának az adatoknak a belső szervezésének egy jellegzetes aspektusából, az úgynevezett fájlarchitektúrából lehet következtetni.

Egyes operációs rendszereket, például a Windowst, teljes mértékben egy fájlkiterjesztés vezérli. Nevezhetjük hiszékenynek vagy megbízhatónak, de a Windows feltételezi, hogy minden DOCX kiterjesztésű fájl valóban DOCX szövegszerkesztő fájl. A Linux nem ilyen, ahogy hamarosan látni fogod. Bizonyítékot akar, és belenéz a fájlba, hogy megtalálja.

Az itt leírt eszközök már telepítve voltak a Manjaro 20, Fedora 21 és Ubuntu 20.04 disztribúciókra, amelyeket a jelen cikk kutatásához használtunk. Kezdjük a vizsgálatot a használatával a fájl parancsot.

A Command fájl használatával

Jelenlegi könyvtárunkban különféle fájltípusok gyűjteménye található. Ezek dokumentum, forráskód, végrehajtható és szöveges fájlok keverékei.

Az ls parancs megmutatja, hogy mi van a könyvtárban, a -hl (ember által olvasható méretek, hosszú lista) pedig az egyes fájlok méretét:

ls -hl

Próbáljunk meg néhány fájlt ezek közül, és nézzük meg, mit kapunk:

file build_instructions.odt
file build_instructions.pdf
file COBOL_Report_Apr60.djvu

A három fájlformátum helyesen van azonosítva. Ahol lehetséges, a fájl egy kicsit több információt ad nekünk. A PDF-fájl a jelentések szerint a 1.5-ös verzió formátum.

Még ha átnevezzük is az ODT fájlt egy tetszőleges XYZ értékű kiterjesztésre, a fájl továbbra is helyesen azonosításra kerül, mind a Fájlok fájlböngészőben, mind a fájl parancssorban.

A Fájlok fájlböngészőben a megfelelő ikont kapja. A parancssorban a fájl figyelmen kívül hagyja a kiterjesztést, és belenéz a fájlba, hogy meghatározza annak típusát:

file build_instructions.xyz

Fájlok használata médián, például kép- és zenefájlokon általában információkat szolgáltat formátumukkal, kódolással, felbontásukkal és így tovább:

file screenshot.png
file screenshot.jpg
file Pachelbel_Canon_In_D.mp3

Érdekes módon a fájl még egyszerű szöveges fájlok esetén sem ítéli meg a fájlt a kiterjesztése alapján. Ha például van egy „.c” kiterjesztésű fájlja, amely szabványos egyszerű szöveget tartalmaz, de nem forráskódot, akkor a fájl nem téveszti össze az eredeti C-vel. forráskód fájl:

file function+headers.h
file makefile
file hello.c

file helyesen azonosítja a fejlécfájlt (.h) egy C forráskód-gyűjtemény részeként, és tudja, hogy a makefile egy szkript.

  Bash Script szüneteltetése a Linux Sleep Command segítségével

Fájl használata bináris fájlokkal

A bináris fájlok inkább „fekete dobozok”, mint mások. A megfelelő szoftvercsomaggal a képfájlok megtekinthetők, a hangfájlok lejátszhatók, a dokumentumfájlok megnyithatók. A bináris fájlok azonban nagyobb kihívást jelentenek.

Például a „hello” és „wd” fájlok bináris végrehajtható fájlok. Ezek programok. A „wd.o” nevű fájl egy objektumfájl. Amikor a forráskódot fordító fordítja le, egy vagy több objektumfájl jön létre. Ezek tartalmazzák azt a gépi kódot, amelyet a számítógép végül végrehajt, amikor a kész program fut, valamint a linker információit. A linker minden objektumfájlban ellenőrzi a függvénytárak függvényhívásait. Összekapcsolja őket a program által használt bármely könyvtárral. A folyamat eredménye egy végrehajtható fájl.

A „watch.exe” fájl egy bináris végrehajtható fájl, amelyet keresztbefordítottak a Windows rendszeren való futtatáshoz:

file wd
file wd.o
file hello
file watch.exe

Az utolsót tekintve a fájl azt mondja, hogy a „watch.exe” fájl egy PE32+ futtatható, konzolprogram, a Microsoft Windows x86 processzorcsaládjához. A PE a hordozható végrehajtható formátumot jelenti, amelynek 32 és 64 bites változata van. A PE32 a 32 bites, a PE32+ pedig a 64 bites verzió.

A másik három fájl mind a következőként van azonosítva: Futtatható és linkelhető formátum (ELF) fájlokat. Ez a futtatható fájlok és a megosztott objektumfájlok, például a könyvtárak szabványa. Hamarosan megnézzük az ELF fejlécformátumot.

Ami megakadhat, az az, hogy a két végrehajtható fájl („wd” és „hello”) a következőképpen van azonosítva Linux Standard Base (LSB) megosztott objektumokat, és a „wd.o” objektumfájlt LSB áthelyezhetőként azonosítja. A futtatható szó hiányában nyilvánvaló.

Az objektumfájlok áthelyezhetők, vagyis a bennük lévő kód bárhol betölthető a memóriába. A végrehajtható fájlok megosztott objektumokként vannak felsorolva, mert a linker hozta létre őket az objektumfájlokból oly módon, hogy öröklik ezt a képességet.

Ez lehetővé teszi a Címterület-elrendezés véletlenszerűsítése (ASMR) rendszer, amely a végrehajtható fájlokat a memóriába tölti be az általa választott címeken. A szabványos végrehajtható fájlok fejlécébe egy betöltési cím van kódolva, amely megszabja, hogy hol töltődnek be a memóriába.

Az ASMR egy biztonsági technika. A végrehajtható fájlok memóriába való betöltése előrelátható címeken teszi őket támadásra. Ennek az az oka, hogy belépési pontjaik és funkcióik helye mindig ismert lesz a támadók számára. Pozíció Független Végrehajtók A véletlenszerű címen elhelyezett (PIE) felülmúlja ezt az érzékenységet.

  Hogyan lehet javítani az akkumulátor élettartamát Linux laptopokon

Ha mi állítsuk össze programunkat a gcc fordítóval, és megadjuk a -no-pie opciót, akkor egy hagyományos végrehajtható fájlt generálunk.

A -o (kimeneti fájl) opció lehetővé teszi, hogy nevet adjunk a végrehajtható fájlnak:

gcc -o hello -no-pie hello.c

A fájlt fogjuk használni az új futtatható fájlban, és megnézzük, mi változott:

file hello

A végrehajtható fájl mérete megegyezik az előzővel (17 KB):

ls -hl hello

A bináris fájl mostantól szabványos végrehajtható fájlként van azonosítva. Ezt csak demonstrációs célból tesszük. Ha így fordítja le az alkalmazásokat, elveszíti az ASMR minden előnyét.

Miért olyan nagy egy végrehajtható?

Példa hello programunk 17 KB, tehát aligha nevezhető nagynak, de hát minden relatív. A forráskód 120 bájt:

cat hello.c

Mit jelent a bináris tömbösítése, ha csak egy karakterláncot nyomtat a terminálablakba? Tudjuk, hogy létezik ELF fejléc, de ez csak 64 bájt hosszú egy 64 bites bináris esetében. Nyilvánvalóan valami másnak kell lennie:

ls -hl hello

Gyerünk szkennelje be a binárist a strings parancs egyszerű első lépésként, hogy felfedezze, mi van benne. Kevesebbre tesszük:

strings hello | less

A „Hello, Geek world” mellett számos karakterlánc található a binárison belül. forráskódunkból. Legtöbbjük a binárison belüli régiók címkéi, valamint a megosztott objektumok nevei és hivatkozási információi. Ide tartoznak a könyvtárak és azokon belüli függvények, amelyektől a bináris függ.

A ldd parancs megmutatja nekünk egy bináris megosztott objektumfüggőségeit:

ldd hello

Három bejegyzés található a kimenetben, és ezek közül kettő tartalmaz egy könyvtár elérési utat (az első nem):

linux-vdso.so: Virtuális dinamikus megosztott objektum (VDSO) egy kernelmechanizmus, amely lehetővé teszi a kernel-tér rutinok halmazának elérését a felhasználói tér binárisai által. Ez elkerüli a környezetváltás többletköltségét felhasználói kernel módból. A VDSO megosztott objektumok az Executable and Linkable Format (ELF) formátumhoz ragaszkodnak, lehetővé téve, hogy futás közben dinamikusan kapcsolódjanak a binárishoz. A VDSO dinamikusan van lefoglalva, és kihasználja az ASMR előnyeit. A VDSO képességet a szabvány biztosítja GNU C könyvtár ha a kernel támogatja az ASMR-sémát.
libc.so.6: Az GNU C könyvtár megosztott objektum.
/lib64/ld-linux-x86-64.so.2: Ez az a dinamikus linker, amelyet a bináris használni akar. A dinamikus linker lekérdezi a binárist, hogy kiderítse, milyen függőségei vannak. Elindítja a megosztott objektumokat a memóriába. Felkészíti a bináris fájlt a futtatásra, és képes megtalálni és elérni a függőségeket a memóriában. Ezután elindítja a programot.

Az ELF fejléc

Tudunk vizsgálja meg és dekódolja az ELF fejlécet a readelf segédprogram és a -h (fájl fejléc) opció használatával:

readelf -h hello

A fejléc számunkra értelmezve van.

  Linux Xonotic játékszerver hosztolása

Az összes ELF bináris fájl első bájtja 0x7F hexadecimális értékre van állítva. A következő három bájt értéke 0x45, 0x4C és 0x46. Az első bájt egy jelző, amely a fájlt ELF binárisként azonosítja. Hogy ez kristálytiszta legyen, a következő három bájt az „ELF” szót írja be ASCII:

Osztály: Azt jelzi, hogy a bináris fájl 32 vagy 64 bites futtatható (1=32, 2=64).
Adatok: Jelzi a végtelenség használatban. Az Endian kódolás határozza meg a többbájtos számok tárolási módját. A big-endian kódolásban a szám először a legjelentősebb bitekkel kerül tárolásra. A kis végű kódolásban a szám először a legkisebb jelentőségű bitekkel kerül tárolásra.
Verzió: Az ELF verziója (jelenleg 1).
OS/ABI: A típust jelöli bináris alkalmazás interfész használatban. Ez határozza meg az interfészt két bináris modul, például egy program és egy megosztott könyvtár között.
ABI verzió: Az ABI verziója.
Típus: Az ELF bináris típusa. A közös értékek az ET_REL egy áthelyezhető erőforráshoz (például egy objektumfájlhoz), az ET_EXEC a -no-pie kapcsolóval lefordított végrehajtható fájlhoz, és az ET_DYN az ASMR-tudatos végrehajtható fájlhoz.
Gép: A utasításkészlet architektúra. Ez jelzi azt a célplatformot, amelyhez a bináris fájlt létrehozták.
Verzió: Mindig 1-re állítsa az ELF ezen verziójához.
Belépési pont címe: A binárison belüli memóriacím, amelyen a végrehajtás kezdődik.

A többi bejegyzés a binárison belüli régiók és szakaszok mérete és száma, így ezek helye kiszámítható.

Gyors bepillantás a bináris első nyolc bájtjába hexdump-pal A fájl első négy bájtjában az aláírás bájtja és az „ELF” karakterlánc látható. A -C (canonical) opció megadja a bájtok ASCII-ábrázolását a hexadecimális értékeik mellett, az -n (szám) opció pedig megadja, hogy hány bájtot szeretnénk látni:

hexdump -C -n 8 hello

objdump és a Granuláris nézet

Ha meg szeretné tekinteni az aprólékos részleteket, használhatja az objdump parancsot a -d (disassemble) kapcsolóval:

objdump -d hello | less

Ez szétszedi a végrehajtható gépi kódot, és hexadecimális bájtokban jeleníti meg az assembly nyelvi megfelelője mellett. Az első bye cím helye minden sorban a bal szélen látható.

Ez csak akkor hasznos, ha tud assembly nyelvet olvasni, vagy kíváncsi, mi történik a függöny mögött. Sok a kimenet, ezért kevesebbre állítottuk be.

Összeállítás és linkelés

A bináris összeállításának számos módja van. Például a fejlesztő dönti el, hogy belefoglalja-e a hibakeresési információkat. A bináris csatolás módja is szerepet játszik a tartalmában és méretében. Ha a bináris hivatkozások külső függőségekként osztanak meg objektumokat, akkor azok kisebbek lesznek, mint amelyekhez a függőségek statikusan kapcsolódnak.

A legtöbb fejlesztő már ismeri az itt leírt parancsokat. Mások számára azonban néhány egyszerű módot kínálnak a turkálásra, és megnézni, mi rejlik a bináris fekete dobozban.