
Di Rusia, tidak ada informasi yang cukup tentang cara bekerja dengan file ELF (Format Executable dan Linkable - format utama untuk file yang dapat dieksekusi dari Linux dan banyak sistem Unix). Kami tidak mengklaim untuk sepenuhnya mencakup semua kemungkinan skenario bekerja dengan elf, tetapi kami berharap bahwa informasi tersebut akan berguna dalam bentuk buku referensi dan koleksi resep untuk programmer dan insinyur balik.
Dapat dipahami bahwa pembaca pada tingkat dasar sudah terbiasa dengan format ELF (jika tidak, kami merekomendasikan serangkaian artikel yang dapat dijalankan dan Format yang Dapat Ditautkan 101 ).
Di bawah potongan akan terdaftar alat untuk bekerja, teknik yang dijelaskan untuk membaca meta-informasi, modifikasi, verifikasi dan berkembang biak membuat elf, serta tautan ke materi yang bermanfaat.
"Aku juga peri ... Biru merah ... Peri sangat sabar ... Biru merah ... Dan kita peri! ... Biru merah ... Hanya ada masalah dari sihir ...
(c) Kerajaan Kecil Ben dan Holly
Alat-alatnya
Dalam kebanyakan kasus, contoh-contoh dapat dijalankan di Linux dan Windows.
Dalam resep kami akan menggunakan alat-alat berikut:
- utilitas dari set binutils (objcopy, objdump, readelf, strip);
- kerangka kerja radare2 ;
- hex editor dengan dukungan untuk templat file (contoh menunjukkan 010Editor , tetapi Anda dapat menggunakan, misalnya, Veles gratis);
- Python dan perpustakaan LIEF ;
- utilitas lain (tautan ada di resep).
Tes elf
Sebagai "eksperimental" kita akan menggunakan file ELF sederhana dari tugas PieIsMyFav nutcake di crackmes.one, tetapi perwakilan keluarga "elven" akan melakukannya. Jika file selesai dengan karakteristik yang diperlukan tidak ditemukan di domain publik, maka metode untuk membuat peri seperti itu akan diberikan.
Elf Gratis juga dapat ditemukan di tautan:
Jenis File, Judul, Bagian
Tergantung pada tugasnya, berikut ini mungkin menarik:
- tipe file (DYN - library, EXEC - executable, RELOC - linkable);
- arsitektur target (E_MACHINE - x86_64, x86, ARM, dll.);
- titik masuk aplikasi (Entry Point);
- informasi bagian.
010 Editor
Editor HEX 010Editor menyediakan sistem template. Untuk file ELF, templat ini disebut, cukup aneh, ELF.bt dan terletak di kategori Eksekusi (Templat menu - Eksekusi).
Yang menarik, misalnya, titik masuk ke file yang dapat dieksekusi (titik masuk) (direkam di header file).

membaca sendiri
Utilitas readelf dapat dianggap sebagai standar de facto untuk mendapatkan informasi tentang file ELF.
- Baca tajuk file:
$ readelf -h simple
Hasil tim ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x1070 Start of program headers: 64 (bytes into file) Start of section headers: 14800 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 11 Size of section headers: 64 (bytes) Number of section headers: 30 Section header string table index: 29
- Baca informasi tentang segmen dan bagian:
$ readelf -l -W simple
Hasil timUntuk keterbacaan, alamat dikonversi ke format 32-bit:
Elf file type is DYN (Shared object file) Entry point 0x1070 There are 11 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x00000040 0x00000040 0x000268 0x000268 R 0x8 INTERP 0x0002a8 0x000002a8 0x000002a8 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x00000000 0x00000000 0x0005f8 0x0005f8 R 0x1000 LOAD 0x001000 0x00001000 0x00001000 0x00026d 0x00026d RE 0x1000 LOAD 0x002000 0x00002000 0x00002000 0x0001b8 0x0001b8 R 0x1000 LOAD 0x002de8 0x00003de8 0x00003de8 0x000258 0x000260 RW 0x1000 DYNAMIC 0x002df8 0x00003df8 0x00003df8 0x0001e0 0x0001e0 RW 0x8 NOTE 0x0002c4 0x000002c4 0x000002c4 0x000044 0x000044 R 0x4 GNU_EH_FRAME 0x002070 0x00002070 0x00002070 0x00003c 0x00003c R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x002de8 0x00003de8 0x00003de8 0x000218 0x000218 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 03 .init .plt .plt.got .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .got.plt .data .bss 06 .dynamic 07 .note.ABI-tag .note.gnu.build-id 08 .eh_frame_hdr 09 10 .init_array .fini_array .dynamic .got
- Baca informasi bagian:
$ readelf -S -W simple
Hasil timUntuk keterbacaan, alamat dikonversi ke format 32-bit:
There are 30 section headers, starting at offset 0x39d0: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 000002a8 0002a8 00001c 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 000002c4 0002c4 000020 00 A 0 0 4 [ 3] .note.gnu.build-id NOTE 000002e4 0002e4 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 00000308 000308 000024 00 A 5 0 8 [ 5] .dynsym DYNSYM 00000330 000330 0000d8 18 A 6 1 8 [ 6] .dynstr STRTAB 00000408 000408 0000a2 00 A 0 0 1 [ 7] .gnu.version VERSYM 000004aa 0004aa 000012 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 000004c0 0004c0 000030 00 A 6 1 8 [ 9] .rela.dyn RELA 000004f0 0004f0 0000c0 18 A 5 0 8 [10] .rela.plt RELA 000005b0 0005b0 000048 18 AI 5 23 8 [11] .init PROGBITS 00001000 001000 000017 00 AX 0 0 4 [12] .plt PROGBITS 00001020 001020 000040 10 AX 0 0 16 [13] .plt.got PROGBITS 00001060 001060 000008 08 AX 0 0 8 [14] .text PROGBITS 00001070 001070 0001f2 00 AX 0 0 16 [15] .fini PROGBITS 00001264 001264 000009 00 AX 0 0 4 [16] .rodata PROGBITS 00002000 002000 000070 00 A 0 0 8 [17] .eh_frame_hdr PROGBITS 00002070 002070 00003c 00 A 0 0 4 [18] .eh_frame PROGBITS 000020b0 0020b0 000108 00 A 0 0 8 [19] .init_array INIT_ARRAY 00003de8 002de8 000008 08 WA 0 0 8 [20] .fini_array FINI_ARRAY 00003df0 002df0 000008 08 WA 0 0 8 [21] .dynamic DYNAMIC 00003df8 002df8 0001e0 10 WA 6 0 8 [22] .got PROGBITS 00003fd8 002fd8 000028 08 WA 0 0 8 [23] .got.plt PROGBITS 00004000 003000 000030 08 WA 0 0 8 [24] .data PROGBITS 00004030 003030 000010 00 WA 0 0 8 [25] .bss NOBITS 00004040 003040 000008 00 WA 0 0 1 [26] .comment PROGBITS 00000000 003040 00001c 01 MS 0 0 1 [27] .symtab SYMTAB 00000000 003060 000630 18 28 44 8 [28] .strtab STRTAB 00000000 003690 000232 00 0 0 1 [29] .shstrtab STRTAB 00000000 0038c2 000107 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
- Baca informasi simbol:
$ readelf -s -W simple
Hasil timOutput disingkat agar mudah dibaca:
Symbol table '.dynsym' contains 9 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable 2: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2) 3: 00000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 4: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 5: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 6: 00000000 0 FUNC GLOBAL DEFAULT UND __isoc99_scanf@GLIBC_2.7 (3) 7: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 8: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 66 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 000002a8 0 SECTION LOCAL DEFAULT 1 2: 000002c4 0 SECTION LOCAL DEFAULT 2 3: 000002e4 0 SECTION LOCAL DEFAULT 3 4: 00000308 0 SECTION LOCAL DEFAULT 4 5: 00000330 0 SECTION LOCAL DEFAULT 5 6: 00000408 0 SECTION LOCAL DEFAULT 6 7: 000004aa 0 SECTION LOCAL DEFAULT 7 .... 26: 00000000 0 SECTION LOCAL DEFAULT 26 27: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 28: 000010a0 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones 29: 000010d0 0 FUNC LOCAL DEFAULT 14 register_tm_clones 30: 00001110 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux 31: 00004040 1 OBJECT LOCAL DEFAULT 25 completed.7389 ....
Opsi -W
diperlukan untuk meningkatkan lebar keluaran konsol (default, 80 karakter).
Lief
Anda dapat membaca informasi tajuk dan bagian menggunakan kode Python dan perpustakaan LIEF (menyediakan API tidak hanya untuk Python):
import lief binary = lief.parse("simple.elf") header = binary.header print("Entry point: %08x" % header.entrypoint) print("Architecture: ", header.machine_type) for section in binary.sections: print("Section %s - size: %s bytes" % (section.name, section.size)
Untuk informasi tentang kompiler dan build, lihat .note
dan .note
.
objdump
$ objdump -s --section .comment simple
Hasil tim simple: file format elf64-x86-64 Contents of section .comment: 0000 4743433a 20284465 6269616e 20382e32 GCC: (Debian 8.2 0010 2e302d39 2920382e 322e3000 .0-9) 8.2.0.
membaca sendiri
$ readelf -p .comment simple
Hasil tim String dump of section '.comment': [ 0] GCC: (Debian 8.2.0-9) 8.2.0
$ readelf -n simple
Hasil tim Displaying notes found at file offset 0x000002c4 with length 0x00000020: Owner Data size Description GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag) OS: Linux, ABI: 3.2.0 Displaying notes found at file offset 0x000002e4 with length 0x00000024: Owner Data size Description GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID: dae0509e4edb79719a65af37962b74e4cf2a8c2e
Lief
import lief binary = lief.parse("simple") comment = binary.get_section(".comment") print("Comment: ", bytes(comment.content))
Saya akan menghitung Anda dengan ... RPATH
Elf dapat menyimpan jalur untuk menemukan perpustakaan yang terhubung secara dinamis. Agar tidak mengatur variabel sistem LD_LIBRARY_PATH
sebelum memulai aplikasi, Anda bisa "menyematkan" jalur ini ke file ELF.
Untuk melakukan ini, gunakan entri di bagian .dynamic
dengan tipe DT_RPATH
atau DT_RUNPATH
(lihat Direktori yang Dicari oleh bab Runtime Linker dalam dokumentasi).
Dan berhati-hatilah, pengembang muda, jangan "tidur" direktori proyek Anda!
Bagaimana RPATH muncul?
Alasan utama untuk penampilan catatan RPATH di peri adalah opsi linker -rpath
untuk mencari pustaka dinamis. Sesuatu seperti ini:
$ gcc -L./lib -Wall -Wl,-rpath=/run/media/pablo/disk1/projects/cheat_sheets/ELF/lib/ -o test_rpath.elf bubble_main.c -lbubble
Perintah seperti itu akan membuat catatan RPATH di bagian .dynamic
dengan nilai /run/media/pablo/disk1/projects/cheat_sheets/ELF/lib/
.
membaca sendiri
Anda dapat melihat elemen dari bagian .dynamic
(di antaranya ada RPATH) sebagai berikut:
$ readelf -d test_rpath.elf
Hasil timUntuk memudahkan membaca, hasil dari perintah diperpendek:
Dynamic section at offset 0x2dd8 contains 28 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libbubble.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000f (RPATH) Library rpath: [/run/media/pablo/disk1/projects/cheat_sheets/ELF/lib/] 0x000000000000000c (INIT) 0x1000 0x000000000000000d (FINI) 0x11c8 ....
Lief
Menggunakan perpustakaan LIEF, Anda juga dapat membaca catatan RPATH di peri:
import lief from lief.ELF import DYNAMIC_TAGS elf = lief.parse("test_rpath.elf") if elf.has(DYNAMIC_TAGS.RPATH): rpath = next(filter(lambda x: x.tag == DYNAMIC_TAGS.RPATH, elf.dynamic_entries)) for path in rpath.paths: print(path) else: print("No RPATH in ELF")
Baca tentang bagian .dinamik
Memeriksa Elf untuk Keamanan
Skrip pemeriksaan keamanan checksec.sh dari peneliti Tobias Klein (penulis A Bug Hunter's Diary ) belum diperbarui sejak 2011. Script file ELF ini memeriksa ketersediaan opsi RelRO (Read Only Relocations), NX (Non-Executable Stack), Stack Canaries, PIE (Position Independent Executables) dan menggunakan utilitas readelf untuk pekerjaannya.
Lief
Anda dapat membuat analog sendiri lutut Python dan LIEF (sedikit lebih pendek dari nenek moyang dan dengan verifikasi tambahan dari opsi kode terpisah ):
import lief from lief.ELF import DYNAMIC_TAGS, SEGMENT_TYPES def filecheck(filename): binary = lief.parse(filename)
Radare2
Terima kasih kepada dukebarman untuk penambahan penggunaan Radare2 untuk menampilkan informasi yang mirip dengan checksec :
> r2 -ci~pic,canary,nx,crypto,stripped,static,relocs test_stack_proteck
Kode Mentah dari Elf (biner dari ELF)
Ada situasi ketika "pakaian elf" dalam bentuk struktur ELF tidak diperlukan, tetapi hanya kode aplikasi yang dapat dieksekusi "telanjang" yang diperlukan.
keberatan
Menggunakan objcopy mungkin tidak asing bagi mereka yang menulis firmware:
$ objcopy -O binary -S -g simple.elf simple.bin
-S
- untuk menghapus informasi karakter;-g
- untuk menghapus informasi debug.
Lief
Tanpa sihir. Ambil saja isi bagian yang dimuat dan buat binar darinya:
import lief from lief.ELF import SECTION_FLAGS, SECTION_TYPES binary = lief.parse("test") end_addr = 0 data = [] for section in filter(lambda x: x.has(SECTION_FLAGS.ALLOC) and x.type != SECTION_TYPES.NOBITS, binary.sections): if 0 < end_addr < section.virtual_address: align_bytes = b'\x00' * (section.virtual_address - end_addr) data.append(align_bytes) data.append(bytes(section.content)) end_addr = section.virtual_address + section.size with open('test.lief.bin', 'wb') as f: for d_bytes in data: f.write(d_bytes)
Mangled - nama fungsi demangled
Dalam ELF yang dibuat dari kode C ++, nama-nama fungsi didekorasi (di-mangled) untuk mempermudah pencarian fungsi kelas yang sesuai. Namun, membaca nama-nama seperti itu dalam analisis tidaklah nyaman.
Uji peri
nm
Untuk mewakili nama dalam bentuk yang dapat dibaca manusia, Anda dapat menggunakan utilitas nm dari set binutils:
Lief
Menampilkan nama simbol dalam bentuk demangulasi menggunakan perpustakaan LIEF:
import lief binary = lief.parse("demangle-test-cpp") for symb in binary.symbols: print(symb.name, symb.demangled_name)
Perakitan, perekaman, modifikasi peri
Setelah aplikasi debugged dan dirilis ke dunia liar, masuk akal untuk menghapus meta-informasi:
- bagian debug - tidak berguna dalam banyak kasus;
- nama-nama variabel dan fungsi - benar-benar tidak mempengaruhi apa pun untuk pengguna akhir (sedikit mempersulit kebalikannya);
- tabel bagian - sama sekali tidak diperlukan untuk menjalankan aplikasi (kekurangannya akan sedikit menyulitkan kebalikannya).
Informasi karakter adalah nama-nama objek dan fungsi. Tanpa itu, kebalikan dari aplikasi sedikit lebih rumit.
menelanjangi
Dalam kasus paling sederhana, Anda dapat menggunakan utilitas strip dari set binutils. Untuk menghapus semua informasi karakter, cukup jalankan perintah:
sstrip
Untuk menghapus informasi karakter dengan hati-hati (termasuk nol byte yang tidak perlu di akhir file), Anda dapat menggunakan utilitas sstrip dari suite ELFkickers . Untuk menghapus semua informasi karakter, cukup jalankan perintah:
$ sstrip -z simple
Lief
Menggunakan perpustakaan LIEF, Anda juga dapat membuat strip cepat (tabel simbol dihapus - bagian .symtab
):
import lief binary = lief.parse("simple") binary.strip() binary.write("simple.stripped")
Menghapus Tabel Partisi
Seperti disebutkan di atas, ada / tidaknya tabel bagian tidak mempengaruhi operasi aplikasi. Tetapi pada saat yang sama, tanpa tabel bagian, kebalikan dari aplikasi menjadi sedikit lebih rumit.
Kami akan menggunakan perpustakaan LIEF di bawah Python dan contoh menghapus tabel bagian :
import lief binary = lief.parse("simple") binary.header.numberof_sections = 0 binary.header.section_header_offset = 0 binary.write("simple.modified")
Ubah dan hapus RPATH
chrpath, PatchELF
Untuk mengubah RPATH di Linux, Anda dapat menggunakan utilitas chrpath (tersedia di sebagian besar distribusi) atau PatchELF .
Ubah RPATH:
$ chrpath -r /opt/my-libs/lib:/foo/lib test_rpath.elf
atau
$ patchelf --set-rpath /opt/my-libs/lib:/foo/lib test_rpath.elf
Hapus RPATH:
$ chrpath -d test_rpath.elf
atau
$ patchelf --shrink-rpath test_rpath.elf
Lief
Perpustakaan LIEF juga memungkinkan Anda untuk memodifikasi dan menghapus data RPATH.
Ubah RPATH:
import lief binary = lief.parse("test_rpath.elf") rpath = next(filter(lambda x: x.tag == lief.ELF.DYNAMIC_TAGS.RPATH, binary.dynamic_entries)) rpath.paths = ["/opt/my-lib/here"] binary.write("test_rpath.patched")
Hapus RPATH:
import lief binary = lief.parse("test_rpath.elf") binary.remove(lief.ELF.DYNAMIC_TAGS.RPATH) binary.write("test_rpath.patched")
Untuk mempersulit kebalikan dari aplikasi, Anda dapat menyimpan informasi simbolik, tetapi membingungkan nama-nama objek. Kami menggunakan elf crackme01_32bit dari crackme01 oleh seveb sebagai subjek uji.
Versi sederhana dari contoh dari perpustakaan LIEF mungkin terlihat seperti ini:
import lief binary = lief.parse("crackme01_32bit") for i, symb in enumerate(binary.static_symbols): symb.name = "zzz_%d" % i binary.write("crackme01_32bit.obfuscated")
Sebagai hasilnya, kita mendapatkan:
$ readelf -s crackme01_32bit.obfuscated ... Symbol table '.symtab' contains 78 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND zzz_0 1: 08048154 0 SECTION LOCAL DEFAULT 1 zzz_1 2: 08048168 0 SECTION LOCAL DEFAULT 2 zzz_2 3: 08048188 0 SECTION LOCAL DEFAULT 3 zzz_3 4: 080481ac 0 SECTION LOCAL DEFAULT 4 zzz_4 5: 080481d0 0 SECTION LOCAL DEFAULT 5 zzz_5 6: 080482b0 0 SECTION LOCAL DEFAULT 6 zzz_6 7: 0804835a 0 SECTION LOCAL DEFAULT 7 zzz_7 8: 08048378 0 SECTION LOCAL DEFAULT 8 zzz_8 9: 080483b8 0 SECTION LOCAL DEFAULT 9 zzz_9 10: 080483c8 0 SECTION LOCAL DEFAULT 10 zzz_10 ...
Substitusi fungsi melalui PLT / GOT
Juga dikenal sebagai INFEKSI ELF PLT .
Agar tidak menyalin, tempel tautan di topik:
Ubah titik masuk
Ini dapat berguna saat membuat tambalan, memasang kait dan instrumentasi dinamis lainnya, atau untuk menjalankan fungsi tersembunyi. Sebagai percobaan, kami menggunakan elf crackme01_32bit dari crackme01 oleh seveb
radare2
radare2 dimulai dalam mode perekaman (opsi -w
) - perubahan akan dilakukan ke file asli:
$ ./crackme01_32bit Please enter the secret number: ^C $ r2 -w -nn crackme01_32bit [0x00000000]> .pf.elf_header.entry=0x0804860D [0x00000000]> q $ ./crackme01_32bit Nope.
Lief
import lief binary = lief.parse("crackme01_32bit") header = binary.header header.entrypoint = 0x0804860D binary.write("crackme01_32bit.patched")
Patch kode
Sebagai tes sederhana, ambil crackmepal novn91 dengan crack . Ketika diluncurkan tanpa parameter, program menampilkan:
$ ./crackmeMario usage <password>
Saat diluncurkan dengan parameter string acak, ini menampilkan:
./crackmeMario qwerty try again pal.
Kami akan membuat tambalan sehingga program segera saat startup menampilkan pesan βpekerjaan bagus! sekarang keygen aku! "
radare2
radare2 dapat menambal format apa pun yang didukungnya sendiri. Dalam hal ini, dimungkinkan untuk menggambarkan tambalan dalam format teks:
# Rapatch for https://crackmes.one/crackme/5ccecc7e33c5d4419da559b3 !echo Patching crackme 0x115D : jmp 0x1226
Anda dapat menerapkan tambalan seperti itu dengan perintah:
$ r2 -P patch.txt crackmeMario
Baca tentang menambal kode melalui radare2:
Lief
LIEF memungkinkan Anda untuk menambal elf (menimpa byte) di alamat virtual yang ditentukan. Patch bisa dalam bentuk array byte atau sebagai nilai integer:
import lief binary = lief.parse("crackmeMario") binary.patch_address(0x115D, bytearray(b"\xe9\xc4\x00\x00\x00")) binary.write("crackmeMario.patched")
Setelah menerapkan tambalan, program akan menampilkan:
$ ./crackmeMario.patched good job! now keygen me!
Tambahkan Bagian ke ELF
keberatan
objcopy memungkinkan Anda untuk menambahkan bagian, tetapi bagian ini tidak akan menjadi bagian dari segmen apa pun dan tidak akan dimuat ke dalam RAM ketika aplikasi dimulai:
$ objcopy --add-section .testme=data.zip \ --set-section-flags .testme=alloc,contents,load,readonly \ --change-section-address .testme=0x08777777 \ simple simple.patched.elf
Lief
Perpustakaan LIEF memungkinkan Anda untuk menambahkan bagian baru dan segmen yang sesuai ( loaded=True
flag) ke ELF yang ada:
import lief binary = lief.parse("simple") data = bytearray(b"\xFF" * 16) section = lief.ELF.Section(".testme", lief.ELF.SECTION_TYPES.PROGBITS) section += lief.ELF.SECTION_FLAGS.EXECINSTR section += lief.ELF.SECTION_FLAGS.ALLOC section.content = data binary.add(section, loaded=True) binary.write("simple.testme.lief")
Ubah Bagian
keberatan
objcopy memungkinkan Anda untuk mengganti konten bagian dengan data dari file, serta mengubah alamat virtual bagian dan bendera:
$ objcopy --update-section .testme=patch.bin \ --change-section-address .testme=0x08999999 simple simple.testme.elf
Lief
import lief binary = lief.parse("simple") data = bytearray(b"\xFF" * 17) section = binary.get_section(".text") section.content = data binary.write("simple.patched")
Hapus Bagian
keberatan
Keberatan memungkinkan Anda untuk menghapus bagian tertentu dengan nama:
$ objcopy --remove-section .testme simple.testme.elf simple.no_testme.elf
Lief
Menghapus bagian menggunakan perpustakaan LIEF terlihat seperti ini:
import lief binary = lief.parse("simple.testme.elf") binary.remove_section(".testme") binary.write("simple.no_testme")
Wadah elf
Resep ini terinspirasi oleh sihir GREMLIN dan ELF: bagaimana jika file ELF adalah sebuah wadah? . Ada juga man's tentang utilitas elfwrap yang berasal dari Solaris, yang memungkinkan Anda untuk membuat file ELF dari data sewenang-wenang, dan format ELF digunakan hanya sebagai wadah.
Mari kita coba melakukan hal yang sama dengan Python dan LIEF.
Sayangnya, saat ini, perpustakaan LIEF tidak dapat membuat file elf dari awal, jadi Anda perlu membantunya - membuat templat ELF kosong:
$ echo "" | gcc -m32 -fpic -o empty.o -c -xc - $ gcc -m32 -shared -o libempty.so empty.o
Sekarang Anda dapat menggunakan templat ini untuk mengisi data:
import lief binary = lief.parse("libempty.so") filename = "crackme.zip" data = open(filename, 'rb').read()
Elf "dengan trailer"
Format ELF tidak memberlakukan batasan pada data yang ada dalam file, tetapi tidak termasuk segmen mana pun. Dengan demikian, dimungkinkan untuk membuat file yang dapat dieksekusi, yang akan disimpan setelah struktur ELF. Ini adalah sesuatu yang tidak akan dimuat ke dalam RAM saat runtime, tetapi akan ditulis ke disk, dan setiap saat dapat dibaca dari disk.
- IDA Pro tidak akan mempertimbangkan data ini saat menganalisis
Contoh struktur file dengan trailer

radare2
Kehadiran "trailer" dapat ditetapkan dengan membandingkan ukuran file yang nyata dan dihitung:
$ radare2 test.elf [0x00001040]> ?v $s 0x40c1 [0x00001040]> iZ 14699
membaca sendiri
readelf tidak menampilkan informasi tentang keberadaan "trailer", tetapi dapat dihitung secara manual:
$ ls -l test.elf
Lief
Perpustakaan LIEF memungkinkan Anda untuk memeriksa keberadaan "trailer" dan menambahkannya. Menggunakan LIEF, semuanya terlihat cukup ringkas:
import lief binary = lief.parse("test")
Void Elf (ELF dari awal)
Di Internet Anda dapat menemukan proyek untuk membuat file ELF "secara manual" - tanpa menggunakan kompiler dan tautan di bawah nama umum "ELF dari awal":
Keakraban dengan proyek-proyek ini memiliki efek menguntungkan pada penyerapan format ELF.
Peri terkecil
Eksperimen menarik dengan meminimalkan ukuran peri dijelaskan dalam artikel:
Secara singkat, elf loader di OS tidak menggunakan semua bidang header dan tabel segmen, dan beberapa kode yang dapat dieksekusi minimal dapat ditempatkan langsung dalam struktur header ELF (kode diambil dari artikel pertama):
; tiny.asm BITS 32 org 0x00010000 db 0x7F, "ELF" ; e_ident dd 1 ; p_type dd 0 ; p_offset dd $$ ; p_vaddr dw 2 ; e_type ; p_paddr dw 3 ; e_machine dd _start ; e_version ; p_filesz dd _start ; e_entry ; p_memsz dd 4 ; e_phoff ; p_flags _start: mov bl, 42 ; e_shoff ; p_align xor eax, eax inc eax ; e_flags int 0x80 db 0 dw 0x34 ; e_ehsize dw 0x20 ; e_phentsize db 1 ; e_phnum ; e_shentsize ; e_shnum ; e_shstrndx filesize equ $ - $$
Merakit dan mendapatkan ELF ukuran ... 45 byte :
$ nasm -f bin -o a.out tiny.asm $ chmod +x a.out $ ./a.out ; echo $? 42 $ wc -c a.out 45 a.out
Pola peri
Untuk membuat peri menggunakan perpustakaan LIEF, Anda dapat mengambil langkah-langkah berikut (lihat resep "wadah-Elf"):
- ambil file ELF sederhana sebagai templat;
- ganti isi bagian, tambahkan bagian baru;
- konfigurasikan parameter yang diperlukan (titik masuk, bendera).
Alih-alih sebuah kesimpulan
Menambah artikel, kami menemukan bahwa itu adalah sesuatu seperti ode ke perpustakaan LIEF. Tapi ini tidak direncanakan - saya ingin menunjukkan cara bekerja dengan file ELF menggunakan alat yang berbeda.
Tentunya ada atau membutuhkan skrip yang tidak disebutkan di sini - tulis tentang ini di komentar.
Referensi dan literatur