پیوند، بارگذاری و حذف دوگانه: PLT، GOT، واردات، اصلاحات و شناسایی عملکرد
Type: Build
Languages: Python, C, x86-64 and arm64 assembly
Prerequisites: Phase 13 · 32 (ELF from scratch), 33 (disassembly and control flow), 38 (calling conventions)
Time: ~160 minutes
اهداف یادگیری
- از یک رکورد نقل مکان و جدول های نماد، تصمیم بگیرید که مدیر لینک از آن چه می کند: فاصله ثابت، ورودی PLT با یک نقطه GOT، یا نقل مکان پویا.
- بخش پویا، PLT و GOT یک ELF مستقل از موقعیت اجرا را بخوانید و با استفاده از فرمول psABI یک تماس را از طریق آنها دنبال کنید.
- یک شی COFF (20 بیت عنوان فایل، 40 بیت ورودی بخش، 18 بیت نماد، 10 بیت نقل مکان) و فهرست واردات، صادرات و نقل مکان پایه یک تصویر PE32+ را بخوانید.
- يک زنجیره سازي با زنجيره هاي ماش-او رو کلمه به کلمه رمزگشایی کن و هر کلمه رو با هم مطابقت بده
dyld_info. . - چه چیزی رو بیان کن
stripو آنچه در هر فرمت زنده می ماند را حذف می کند و برنامه ی حذف شده را اجرا می کند تا ثابت کند که هنوز کار می کند. - بازیافت کردن شروع کردن تابع یک بازوی باز شده با
LC_FUNCTION_STARTS، اسکن های پیشگام و هدف های تماس، هر روش را با جدول نماد دوقلوی بدون قطع، و نام دادن به عملکردها با امضا شکل FLIRT.
مشکل
تو ارتباط برقرار کرديmain.cمخالفlibledger.dylibو از يه مامور پرسيد که چه وظيفه اي دارهmainتماس با0x1000005a0مامور دستورات رو از هم جدا کرد و خواندbl 0x100000694اون آدرس 12 بايت دارهadrp x16،ldr x16, [x16, #0x38]،br x16مامور تا بار رو دنبال کرد0x100004038، هشت بايت رو بخونيد00 00 00 00 00 00 10 80، و از طریق یک اشاره کننده فاسد به فضای هسته تماس گرفته شده
بعد از اين، شما ساخت جامد همون برنامه رو از دست داديد و پرسيديد چند تا از وظايفش هستnm، يک اسم ديده بود__mh_execute_header، و به یکی از آنها پاسخ داد
هر دو جواب فایل رو مثل يه پروسه اجرا مي خوانند0x100004038Bit 63 می گوید bind، 12 بیت می گوید fixup بعدی کجاست و bit های پایین می گویند کدام وارداتی را باید ببندد. dyld کلمه را با آدرس_putsقبل ازmainفایل حذف شده جدول نمادش رو از دست داده و حفظ شدهLC_FUNCTION_STARTS، که فهرست تمام پنج تابع را در 9 بایت شروع می کند.
این درس پنج خواننده را در کتابخانه استاندارد پایتون ساخته است. یک خواننده COFF برای اشیاء خودمان و یک خواننده PE32+ برای دایرکتوری های واردات، صادرات و نقل مکان پایه. یک خواننده Mach-O برای دستورات بارگذاری، ستب ها، جدول نماد غیر مستقیم، زنجیره حل و فصل زنجیره ای و آزمایش صادرات، کلمه به کلمه با dyld_info. یک خواننده ELF برای بخش پویا، PLT و GOT، به علاوه یک برنامه نویس که می گوید یک پی ای لینک از اشیاء ما ایجاد خواهد شد. یک جستجوگر تابع برای یک ساخت بدون چهار روش و یک امتیاز برای هر یک. یک ساختاری امضا به شکل FLIRT، با بایت های نقل مکان wildcarded و CRC16 از دم.
فقط ماچ-او در این ماشین وصل شده است. بازدارنده های arm64 و dylib متصل شده اند، از بین رفته و اجرا شده است. اشیاء ELF و COFF در اینجا با clang -target، و هیچ ویرایشگر لینک ELF یا PE نصب نشده است، بنابراین دو تصویر مرتبط در این فرمت از طریق دو اسکریپت پایتون در پوشه فکسچر باایت به باایت نوشته شده است. llvm-objdumpو همچنین تحقیقات کتابخانه هم میخواد. آنها اجرا نشده اند و متن میگه که مهم است.
چه کاری در مورد انتقال لینک انجام می شود
درس 32 پرونده های نقل مکان و درس 33 استفاده شده را مطالعه کنیدS + A - Pبه یکlea. یه سوابق نام یه مکان رو میگهP، یک نوع، یک نمادSو یک اضافهA. جدول 4.9 psABI x86-64 یک فرمول برای هر نوع را ارائه می دهد، با Lبرای مکان ورود PLT نماد، Gو به پاداش پاداش آنGOTبرای آدرس GOT وBبرای پایه بار تصویر، سه نتیجه به اجسام ما مربوط می شود.
مدیر لینک ارزش را به میدان می نویسد و رکورد از بین می رود. R_X86_64_PC32در این مورد، فاصله بین دو بایت یک تصویر هرگز تغییر نمی کند، هرچه آدرس بار باشد.
مدیر لینک یک ورودی PLT و یک نقطه GOT را ایجاد می کند. R_X86_64_PLT32در مورد یک تابع نامعین در این مورد است.L + A - P، فاصله تا ورودی ورودی از طریق سوراخ پر می شودR_X86_64_JUMP_SLOTثبت شده در .rela.pltبه لينکر پديميک ميگه که خال رو پر کنه
مدیر لینک یک نقل مکان برای بارگذاری را حفظ می کند. R_X86_64_64یک آدرس مطلق هشت بایت است و یک اجراگر مستقل از موقعیت تا زمانی که بارگذاری شود آدرس خود را نمی داند.R_X86_64_RELATIVEبا فرمولB + Aدر.rela.dyn. .
main-x86_64-O1.o18 تا سابقه داره: 14 تا.text، 2 در.data.rel.ro، و دو تا در.rodata.plan_dynamic_link()درcode/main.pyسه قانون را به آنها در کنار هم اعمال می کندledger-x86_64-O1.o:
| Record | Count | Decision | Why |
|---|---|---|---|
R_X86_64_PC32 to .rodata, .L.str, fns, the table in .rodata | 16 | in place | the symbol is defined in the inputs |
R_X86_64_PLT32 to percent_change, grade, total, grade_label | 4 | direct, no PLT | defined in ledger-x86_64-O1.o, so the link editor reduces PLT32 to PC32 |
R_X86_64_PLT32 to puts twice and printf twice | 4 | PLT entry and GOT slot | undefined, provided by a shared library |
R_X86_64_64 to grade in fns[] | 2 | R_X86_64_RELATIVE | an absolute field in a PIE |
دو واردات یک.pltاز 48 بایت (PLT0 + دو ورودی از 16) ، یک .got.pltاز 40 بایت (سه نقطه مخصوص به علاوه دو) و یک .rela.pltاز 48 بايت. دو رکورد نسبی نشان می دهد.rela.dynاین اعداد از مشخصات اعمال شده در سوابق ما هستند.tiny-dyn-x86_64بخش PLT این برنامه را برای همان دو واردات اجرا می کند و اندازه آن با برنامه مطابقت دارد.
کامپایلر می نویسدPLT32در هر تماس، تعریف شده یا غیر تعریف شده، از بین دوتا 2.31 (H.J. Lu، 2018-02-13) و LLVM 7.0.0 (D43383, 2018-02-20).PLT32در یک شی به این ترتیب می گوید "یک تماس" و هیچ چیز در مورد اینکه آیا یک ورودی PLT وجود خواهد داشت نمی گوید. دو نوع دیگر در ساخت های دیگر ظاهر می شوند. R_X86_64_GOTPCRELXوR_X86_64_REX_GOTPCRELX(G + GOT + A - P) درخواست یک نقطه GOT بدون PLT را بکنید که -fno-pltتولید می کند و که مدیر لینک می تواند به یک مستقیم آرام کند leaیاcallوقتی نماد محلی است (psABI ضمیمه B). R_X86_64_32وR_X86_64_32Sنمی توان یک آدرس را در یک PIE نگه داشت و پیوند شکست خورده است. هیچ یک از این نوع در دو شی ما رخ نمی دهد.
بخش دینامیک، PLT و GOT
فصل 5 gABI می گوید که یک اجراگر که در پیوند دینامیک شرکت می کند دارای یک PT_INTERPعنوان برنامه که باید قبل از هر بخش قابل بارگذاری باشد و یک PT_DYNAMIC، که شامل .dynamicبخش. بخش یک آرایه ازElf64_Dynجفت ها، یک برچسب امضا شده و یک مقدار، که با DT_NULL. .
tiny-dyn-x86_645184 بايت نوشته شده استbuild_tiny_dyn_elf.pyاز gABI و psABI. بخش پویا آن 12 جفت در0x1000:
| Tag | Number | Value | Meaning |
|---|---|---|---|
DT_NEEDED | 1 | libc.so.6 | a string table offset, 0xb, the library to load |
DT_HASH | 4 | 0x1a0 | the SysV hash table |
DT_STRTAB | 5 | 0x188 | .dynstr |
DT_SYMTAB | 6 | 0x140 | .dynsym, 24 bytes per entry |
DT_STRSZ | 10 | 0x15 | 21 bytes of strings |
DT_SYMENT | 11 | 0x18 | 24 |
DT_PLTGOT | 3 | 0x10c0 | .got.plt |
DT_PLTRELSZ | 2 | 0x30 | two 24-byte records |
DT_PLTREL | 20 | 7 | the records are DT_RELA |
DT_JMPREL | 23 | 0x1b8 | .rela.plt |
DT_FLAGS_1 | 0x6ffffffb | 0x08000000 | DF_1_PIE, a GNU tag |
DT_NULL | 0 | 0 | end |
گابي ميگه چراDT_JMPRELجدا است: "در آن آدرس ورودی های نقل مکان تنها با جدول پیوند فرآیند مرتبط است. جدا کردن این ورودی های نقل مکان اجازه می دهد که لینکر پویا در هنگام شروع فرآیند آنها را نادیده بگیرد، اگر اتصال تنبل فعال باشد". DF_BIND_NOWدرDT_FLAGS،DF_1_NOWدرDT_FLAGS_1، یاLD_BIND_NOWدر محیط، اتصال تنبل را خاموش می کند و لینکر پویا آن ها را در زمان راه اندازی پردازش می کند.
PLT0 و ورودی برای قرار دادن
بخش psABI 5.2 به شکل های این دو شکل در شکل 5.2 اشاره می کند.
text 1f0: ff 35 d2 0e 00 00 pushq 0xed2(%rip) # 0x10c8 = GOT+8
1f6: ff 25 d4 0e 00 00 jmpq *0xed4(%rip) # 0x10d0 = GOT+16
1fc: 0f 1f 40 00 nopl (%rax)
200: ff 25 d2 0e 00 00 jmpq *0xed2(%rip) # 0x10d8 = GOT+24, the slot for puts
206: 68 00 00 00 00 pushq $0x0 # index 0 into DT_JMPREL
20b: e9 e0 ff ff ff jmp 0x1f0 # PLT0یک بار حساب را انجام دهید. تغییر نسبت به RIP نسبت به دستورالعمل بعدی است. 0x1f6 + 0xed2 = 0x10c8، که.got.plt + 8.0x1fc + 0xed4 = 0x10d0، که.got.plt + 16.0x206 + 0xed2 = 0x10d8، چهارمین سوراخ0x210 - 0x20 = 0x1f0هر ورودی 16 بایته، پس ورودی برایexitشروع می شه0x210، فشار میده$0x1و میخواد0x10e0. .
دولت سه نقطه را در اختیار دارد. psABI 5.2: ورودی صفر آدرس _DYNAMIC، و "دخالات یک و دو در جدول جهانی تعویض نیز محفوظ است"..got.pltمیخواد0x1000, 0, 0, 0x206, 0x216. glibc با قسمت اول اش پر ميکنهstruct link_mapو قسمت دوم با_dl_runtime_resolveوقتي پرونده رو بارگذاری ميکنه، قسمت 3 نگه داره0x206در پرونده که این استpushqداخلputs@plt. psABI: اسلايت "در ابتدا ... آدرس دستورات پشوQ زیر را دارد".
پس اولين تماس رو مي گيرمcall 0x200،jmpq *0x10d8زمین هاpushq $0،jmp 0x1f0فشار GOT+8 و از طریق GOT+16 به حل کننده، که می خواند ثبت 0 از DT_JMPREL،R_X86_64_JUMP_SLOT puts، نگاه ميکنهputsبالاlibc.so.6، آدرسش رو به0x10d8و اونم اونجوري ميپرسه.call،jmpq *0x10d8درپر می نویسد که " هزینه های عمومی برای همه به جز اولین تماس به همین دلیل فقط یک پرتاب غیر مستقیم است". نوٹ زیر psABI در %r11در درس 38 یکی از گزینه های ثبت را توضیح می دهد: این یک ثبت سکریچ است بنابراین "کد در PLT نیازی به ریختن هیچ ثبت نیست".
سایت تماس در.textمیخوادe8 d4 ff ff ffدر0x227و0x22c - 0x2c = 0x200.llvm-objdumpچاپcallq 0x200 <puts@plt>برای آن و نام ورودی از .rela.pltثبت شده، که چگونهplt_entries()اسمش رو هم بزني
آنچه در پرونده وجود ندارد
پرونده اي ندارهPT_GNU_RELRO.Jakub Jelinek پیشنهاد RELRO در لیست دو ابزار در 2004-01-06: حرکت بخش های نوشته شده تنها در هنگام نقل مکان به شروع بخش نوشته شده است، بنابراین لینکر پویا می تواند mprotectپس از آن فقط برای خواندن استفاده می شود. اسکریپت پیش فرض GNU ld می گذارد.init_array،.fini_array،.data.rel.ro،.dynamicو.gotداخل و فقط سه قسمت از قسمت های زیر را نگه می دارد.got.pltدر داخل، 24 بايت، چون سلايت هاي ديگه به صورت تنبل نوشته شده اند.-z nowمجموعه هاDF_BIND_NOWو کل رو حرکت ميده.got.pltداخل، ريلرو کامل، چون بعد از شروع هيچ چيز نوشته نمي شود._dl_protect_relroتماس هاmprotect(start, end - start, PROT_READ)در محدوده ی صفحه ای هموار شده-fno-pltدر قسمت کامپایلر یک قدم بیشتر می رود: تماس ها از طریق می روند jmpq *name@GOTPCREL(%rip)،بند کردن تنبل غیرممکن است و راهنمای GCC می گوید که "همه نمادهای خارجی در زمان بارگذاری حل می شوند".
فایل هیچ قسمت نسخه ای هم ندارهlibc.so.6اضافه می کند.gnu.version، يکElfxx_Halfدر هر.dynsymورود و.gnu.version_r، یکVerneedبرای هر کتابخانه با Vernauxثبت نام هر نسخهprintf@GLIBC_2.2.5معنی: وارد کردن printfدر.gnu.versionدر اختیار یک شاخص استVernauxکهvna_otherبرابر با این شاخص استvna_name"GLIBC_2.2.5" در زیرVerneedکهvn_fileاین "libc.so.6" است. شاخص 0 محلی است، 1 جهانی است و بیت 15 (VERSYM_HIDDEN،0x8000) نسخه ای را از ویرایشگر لینک پنهان می کند.
جدول هاشي يک SysV استDT_HASHبا يک سطل و يک زنجیره سه واردات، 24 بايت.DT_HASHیاDT_GNU_HASHاین فایل هیچ چیزی را صادر نمی کند و اینجا اجرا نشده است، بنابراین اینکه آیا glibc یک جدول یک سطل را قبول می کند تایید نشده است.
.dynsym, .symtab, و strip
گابي ميکنه.dynsymو.dynstrبخش های اختصاصی و.symtabو.strtabدر این حالت، یک جدول نماد معمولی در زمان اجرا استفاده نمی شود و بنابراین لازم نیست یک دوگانه را از آن خارج کنید. این هیچ تأثیری بر عملکرد ندارد.
گنوstrip --strip-allحذف می کنه.symtab،.strtab،.debug_*و.commentهر بخش اختصاصي باقي مي ماند:.interp،.dynsym،.dynstr،.gnu.hash،.gnu.version*،.rela.dyn،.rela.plt،.plt،.text،.rodata،.eh_frame،.init_array،.dynamic،.got،.got.plt،.data،.bss، و يادداشت ها . سرپرست بخش ها باقي ميمنن مگر اينکه شما اضافه کنيد--strip-section-headers(بینه های 2.41) یا اجراllvm-strip --strip-sections.--strip-debugنماد ها رو نگه مي داره--only-keep-debugفایل های دیبگ را می نویسد که --add-gnu-debuglinkنام ها از اونی که ازش خلاص شده، با CRC32 در .gnu_debuglinkوld --build-idنوشته شده.note.gnu.build-idپس یک دیبگگر می تواند دو را مطابقت دهد.
موضوع COFF
clang -target x86_64-pc-windows-msvc -O1 -fno-asynchronous-unwind-tables -cتولید شدهmain-x86_64.objوledger-x86_64.obj. صفحه قالب PE، شی را تعریف می کند: یک سرپرستی فایل ۲۰ بایت، هیچ سرپرستی اختیاری، یک جدول بخش از ورودی ۴۰ بایت، یک جدول نماد از رکورد های ۱۸ بایت و رکورد های نقل مکان ۱۰ بایت در هر بخش.
CoffObjectدرcode/main.pyهمه چهارتا رو ميخواد.0x8664، 10 بخش ، 37 رمز ثبت شدهSizeOfOptionalHeader0. نام جدول بخش ها .text،.data،.bss، شش بخش به نام.rdataو/16. اسمي که با شروعش مياد/یک تعویض دسمایی در جدول رشته است که با اندازه چهار بایت خود شروع می شود./16تصمیم می گیرد.llvm_addrsig، که اسمش اینهllvm-objdump -hاثر انگشت
37 رکورد شامل رکورد های دستی است. یک نماد بخش (کلاس ذخیره سازی 3) دارای یک است که دارای طول بخش، تعداد نقل مکان، یک چک سوم و یک انتخاب COMDAT است. پنج از این .rdataبخش ها انتخاب 2، "هر" دارند و هر کدام یک خط حرفی تحت نام MSVC-فراغ دارند: ??_C@_04JDDJEAHN@even?$AA@در این قسمت، یک خط "حساب" است. مدیر لینک یک نسخه از هر یک را نگه می دارد. آخرین رکورد این است.fileبا شماره ی دستی "main.c".llvm-objdump -tاينها رو به عنوان[ 0]،AUX scnlen ...،[ 2]، و غیره، از شاخص های کمک کننده عبور می کنیم، و آزمون، شاخص و نام های ما را با آن متن مقایسه می کند.
نقل مکان ها: 14 IMAGE_REL_AMD64_REL32در.textو 4IMAGE_REL_AMD64_ADDR64در.rdata.REL32"آدرس نسبی 32 بیت از بایت بعد از انتقال" است.R_X86_64_PC32با-4وارد شده: سوابق ELF شامل اضافه شده است -4چون ثبت یک فیلد اضافه دارد و ثبت COFF هیچ فیلدی ندارد. ledger-x86_64.objسه تا دارهREL32در0x36،0x84و0x93، و درس 32ledger-x86_64-O1.oسه تاش دارهR_X86_64_PC32در سه نسخه مشابه، کد یکسان است و فرمت ها تنها در جایی که چهار مورد نوشته شده متفاوت هستند.ADDR64یک آدرس مطلق هشت بایت است،labelsجدول اشاره های رشته ای، و تبدیل به یک نقل مکان پایه در تصویر می شود، به عنوان R_X86_64_64می شهR_X86_64_RELATIVE. .
ELF Elf64_Rela | COFF relocation | Mach-O relocation_info | |
|---|---|---|---|
| record size | 24 bytes | 10 bytes | 8 bytes |
| fields | offset, type and symbol in r_info, addend | offset, symbol index, type | address, then a 32-bit word with symbolnum:24, pcrel:1, length:2, extern:1, type:4 |
| addend | explicit | none, lives in the field | none, or an ARM64_RELOC_ADDEND record before the real one |
the call to puts | R_X86_64_PLT32 puts-0x4 | IMAGE_REL_AMD64_REL32 puts | ARM64_RELOC_BRANCH26 _puts |
تصویر PE: واردات، صادرات و نقل مکان های پایه
tiny-x86_64.exe2560 بايت نوشته شده استbuild_tiny_pe.py. کارش مثل اون ELF کوچولو هستputsوexitازmsvcrt.dllهمچنین یک نام صادر می کند و یک نقل مکان پایگاه را حمل می کند، بنابراین سه دایرکتوری که این درس نیاز دارد همه در دسترس هستند.pefile۲۰۲۴.۸.۲۶ و llvm-objdump -pهر دو آن را بخوانند و هر دو گرفتن وسایل هستند.
سرنخ ها رو مرور کن.MZو در تعویض0x3cنگه دارهe_lfanew،0x40. در0x40امضاPE\0\0. بعدش سرپرستي فایل COFF: ماشین0x8664، 4 بخشSizeOfOptionalHeader240، ویژگی ها 0x22(تصویر قابل اجرا، آدرس بزرگ آگاه) سرگویی اختیاری با شروع می شودMagicمیدان0x20b، که به معنی PE32+ است.AddressOfEntryPoint.0x1000،ImageBase.0x140000000،SectionAlignment 0x1000،FileAlignment 0x200،SizeOfImage 0x5000،Subsystem3 (کنسول)DllCharacteristics 0x8160کد های رمزنگاری شدهHIGH_ENTROPY_VA 0x0020،DYNAMIC_BASE 0x0040،NX_COMPAT 0x0100وTERMINAL_SERVER_AWARE 0x8000سپس 16 دایرکتوری داده از RVA و اندازه.0x2080اندازه0x4d, واردات در0x2000اندازه0x28, نقل مکان پایگاه در0x4000اندازه0xc، IAT در0x2040اندازه0x18. .
آدرس ها در یک تصویر RVAs، تعویضات از پایه بار هستند. جدول بخش آنها را به تعویضات فایل نقشه می زند: .textRVA 0x1000در پرونده0x200،.rdataRVA 0x2000در0x400،.dataRVA 0x3000در0x600،.relocRVA 0x4000در0x800.PeImage.rva_to_offset()اون ميزه
فهرست واردات
در RVA0x2000در این صفحه، یک سری از توضیحات وارداتی 20 بایت قرار دارد که با یک توصیف کننده صفر پایان می یابد.0x2028, زمان مهر 0 , زنجیره فرستنده 0 , نام 0x2068, جدول آدرس واردات 0x2040. نام RVA به "msvcrt.dll" اشاره می کند. جدول جستجو شامل ورودی 64 بت است که با صفر پایان می یابد. مجموعه بیت 63 به معنای واردات با دستور، با دستور در بیت 15 تا 0 است. بیت 63 به معنی روشن بیت 30 تا 0 RVA یک اشاره / نام واردات است: یک اشاره 16 بیت، "یک شاخص به جدول نام صادرات اشاره کننده"، سپس نام ASCII. ما هستند 0x2058(توصیه 0، "پات") و 0x2060(نتیجه 0، "خروجی").
مشخصات می گوید IAT "به محتوای جدول جستجوی واردات یکسان است تا زمانی که تصویر بسته شود".0x2040در این حالت، این دو RVA را دارد و آزمایش می کند که 24 بایت در 0x2028برابر با 24 بايت در 0x2040. "در طول پیوند، ورودی ها در جدول آدرس واردات با آدرس 32 بت (برای PE32) یا 64 بت (برای PE32+) از نماد وارداتی شده ها نوشته می شوند". بارگذاری ویندوز قبل از اجرای نقطه ورود این کار را انجام می دهد. هیچ پیوند تنبل و هیچ ستون وجود ندارد. کد به طور مستقیم به سمت سمت سمت:
text 100b: ff 15 2f 10 00 00 call qword ptr [rip + 0x102f] # 0x1011 + 0x102f = 0x2040, the IAT slot of puts
1013: ff 15 2f 10 00 00 call qword ptr [rip + 0x102f] # 0x1019 + 0x102f = 0x2048, the IAT slot of exitFF /2این دو دستورالعمل باایت یکسان هستند زیرا هر یک 8 بایت بعد از دیگری قرار دارد و یک فاصله 8 بایت بعد از دیگری می خواند. iat_calls()بخش کد رو برای اسکن میکنهff 15، شش و جابجایی را اضافه می کند و به سمت سمت سمت واردات نام می زند.
فهرست صادرات
در RVA0x2080جدول 40 بایت فهرست صادرات: پرچم ها، زمان، نسخه، یک نام RVA که به "tiny-x86_64.exe" اشاره می کند، پایه ی عادی 1، 1 ورودی جدول آدرس، 1 نام اشاره کننده. سه جدول در پی هستند. جدول آدرس صادرات در 0x20a8دارای یک RVA است0x1000جدول نام صادرات در 0x20acیک RVA را به رشته "tiny_entry" نگه دارد. جدول عادی صادرات در 0x20b0دارای یک شاخص غیر جانبدار 16 بایت، 0. نام kنقشه های مربوط به ورودordinals[k]، و آردنال صادر شدهordinals[k] + ordinal base. مشخصات اضافه می کند یک قاعده که ما استفاده نمی کنیم: یک ورودی آدرس که به داخل بخش صادرات اشاره می کند یک رشته فرستنده است مانند MYDLL.expfunc، و جدول نام اشاره به "به ترتیب لغوی برای اجازه جستجوی دوگانه" است.
نقل مکان پایگاه ها
.relocهر بلوک با یک صفحه RVA و یک اندازه بلوک شروع می شود، سپس ورودی 16 بت با نوع در چهار بیت بالا و یک صفحه تعویض در دوازده پایین. یک بلوک ما: صفحه 0x3000، اندازه 12 ، ورودی 0xa000، نوع 10IMAGE_REL_BASED_DIR64, اوفسر 0 و یک ورودی پر کردن نوع 0IMAGE_REL_BASED_ABSOLUTE. هشت بايت در RVA0x3000نگه دار0x1400020d0, پایه تصویر به علاوه RVA رشته "به دست مرتبط". اگر بارگذاری کننده تصویر را در هر نقطه دیگری قرار دهد، تفاوت را به آن زمینه اضافه می کند. مشخصات: "فایل های تصویر حاوی نقل مکانی COFF نیستند ... یک تصویر حاوی اطلاعات نقل مکانی در قالب نقل مکان پایه در بخش .reloc است (مگر اینکه تصویر دارای ویژگی IMAGE_FILE_RELOCS_STRIPPED باشد) "/DYNAMICBASEبه طور پیش فرض در link.exe فعلی فعال شده است، بنابراین تصاویر حمل می کنند .relocوDYNAMIC_BASE. .
یک تصویر PE هیچ جدول نماد برای حذف ندارد.PointerToSymbolTable"باید برای یک تصویر صفر باشد زیرا اطلاعات کاوف با اشکال زدایی قدیمی شده است" و نام ها در یک PDB جداگانه زندگی می کنند. آنچه در هر تصویر باقی می ماند، دایرکتوری واردات، دایرکتوری صادرات و برای کد 64 بت است..pdata، کهRUNTIME_FUNCTIONورودی ها شروع و پایان هر تابع را که دسته را اختصاص می دهد یا تابع دیگری را فرا می خواند، نام می دهند.
تصویر ماچ-او: دستورات بارگذاری، ستوب ها و جدول نماد غیر مستقیم
ledger_main.آرم64 قابل اجراotool -h19 دستور و پرچم بار چاپ شده است 0x00200085.MH_NOUNDEFS 0x1،MH_DYLDLINK 0x4،MH_TWOLEVEL 0x80وMH_PIE 0x20000019 فرمان 4 عدد استLC_SEGMENT_64(__PAGEZERO،__TEXT،__DATA_CONST،__LINKEDIT، دوLC_LOAD_DYLIB(@rpath/libledger.dylibپس/usr/lib/libSystem.B.dylib) و هر یک از آنهاLC_DYLD_CHAINED_FIXUPS،LC_DYLD_EXPORTS_TRIE،LC_SYMTAB،LC_DYSYMTAB،LC_LOAD_DYLINKER،LC_UUID،LC_BUILD_VERSION،LC_SOURCE_VERSION،LC_MAIN،LC_RPATH،LC_FUNCTION_STARTS،LC_DATA_IN_CODEوLC_CODE_SIGNATURE.MachoFile.command_names()همان لیست را در همان ترتیب به عنوان otool -l. .
__TEXTشروع می شه0x100000000.__text256 بايت در 0x100000558،mainو هيچ چيز ديگه اي نيست، چون چهار وظيفه دفترچه در ديليب زندگي مي کنند.__stubs84 بايت در 0x100000658، هفت تا از 12 بايت__DATA_CONSTشروع می شه0x100004000با__got, 64 بایت، 8 نقطه اشاره ای از نوع بخش S_NON_LAZY_SYMBOL_POINTERSو__const، 32 بايت،fns[]وnames[]جدول های main.c. .
یک چوب، به دست
اون چوب برای_putsدر حال حاضر0x100000694:
text 30 00 00 90 adrp x16, 0x100004000
10 1e 40 f9 ldr x16, [x16, #0x38]
00 02 1f d6 br x160x90000030.adrp. سجل پنج بت پایین، 16immlo30 تا 29 بت است. 0immhi23 تا 5 بت است.immhi << 2 | immlo = 4، در صفحه های 4,096 بایت، بنابراین صفحه هدف صفحه دستورالعمل است،0x100000000، به علاوه0x4000.0xf9401e10.ldrبا یک تعویض 12 بت بدون امضا با مقیاس 8: بت 21 تا 10 7 است، ضرب 8 است 0x38، پس بارش رو میخواد0x100004038.0xd61f0200.br x16. دست 64 در منبع ID64 این دقیقاً سه دستور استStubAtom. .
اسم این سلاټ از جدول نماد غیر مستقیم است.LC_DYSYMTABدر جدول نماد ها 15 شاخص وجود دارد.reserved1جایی که جریان شاخص ها شروع می شود و درreserved2اندازه هر ستون (12)reserved1و هشت بايت در هر سلايت__stubsدر شاخص 0 شروع می شود و __gotدر شاخص 7، پس نقشه های 5 را به ورودی جدول نماد 10، _puts، و قسمت 7 از__gotنقشه های همان ورودی. otool -Ivهر دو ران را چاپ مي کند وindirect_table()هر سطر را بازتولید می کند.
فضای نام دو سطح
nm -mچاپ(undefined) external _puts (from libSystem)و(undefined) external _grade (from libledger). کتابخانه از خود نماد ثبت شدهnlist.hتعریف می کندGET_LIBRARY_ORDINAL(n_desc)به عنوان 15 تا 8 قطعه از n_desc، 1 تا اولLC_LOAD_DYLIB، 2 برای دوم0xfeبرای جستجوی پویا0xffبرای اجرا کنندهld(1): "با -two_levelnamespace (پیش فرض) ، لینکر فقط در خط فرمان برای نماد و ثبت نام هایی که در آن dylib یافت شده اند، جستجو می کند". nm_lines()12 تا سوابق را ازn_type،n_sect،n_descوn_value، و آزمایش خط خروجی آن را با خط گرفته شده مقایسه می کند nm -m. دوباره با اون ارتباط برقرار کن-Wl,-flat_namespaceو بخونotool -hتا ببینیمMH_TWOLEVELکمی ناپدید میشه
حل و فصل های زنجیره ای، بایت به بایت
LC_DYLD_CHAINED_FIXUPSیکlinkedit_data_command.dataoff 0x8000،datasize 208. 208 بايت بعدش ميادfixup-chains.h. .
سرش 7 رشته 32 بيت داره:fixups_version 0،starts_offset 32،imports_offset 80،symbols_offset 112،imports_count 8،imports_format 1(DYLD_CHAINED_IMPORT)symbols_format 0(غیر فشرده شده)llvm-objdump --macho --chained-fixupsاین هفت مقدار را چاپ می کند و آزمایش آنها را مقایسه می کند.
در 32موقعdyld_chained_starts_in_image.seg_count 4و چهار تعویض، یک در هر بخش، صفر برای بخش بدون اصلاحات. فقط __DATA_CONSTيه نفر دارهdyld_chained_starts_in_segmentمیخوادsize 24،page_size 0x4000،pointer_format 6(DYLD_CHAINED_PTR_64_OFFSET، "هدف vm تعویض شده است") ،segment_offset 0x4000،max_valid_pointer 0،page_count 1، و يکpage_startاز 0DYLD_CHAINED_PTR_START_NONE،0xffff، به معنی یه صفحه بدون مشکل
زنجیره در تعویض فایل شروع می شود0x4000 + 0هر کلمه 64 بت دو چیز را دارد: چه چیزی را در آن نوشته و کلمه بعدی کجاست.
text dyld_chained_ptr_64_bind ordinal:24 addend:8 reserved:19 next:12 bind:1 = 1
dyld_chained_ptr_64_rebase target:36 high8:8 reserved:7 next:12 bind:1 = 0اولين کلمه رو بخوني0x8010000000000000. بت 63 تنظیم شده ، بستهnext62 تا 51 بت است.0x002، در واحدهای 4 بایت، پس اصلاح بعدی 8 بایت است.0x4058،0x00000000000006db63 تا بازي بازيnextصفر، پایان زنجیره است. هدف0x6db, یک vm تعویض و پایه تصویر 0x100000000. به اين کار مي رسه0x1000006db، رشته "بدون" در__cstring. کلمه قبل از اون0x00100000000006d6، بازده هاnames[0]به "حتي"
راه رفتن 12 کلمه را می خواند: 8 کلمه به هم متصل می شود__gotبا شماره 0 تا 7، دو بسته در __constبا 0 (هر دو ورودی از fns[]نقطه ای در_grade) و دو تخفیف ازnames[].chained_fixups()آنها را با تعویض فایل و کلمات خامشان باز می گرداند و آزمون 12 را مقایسه می کند (offset, raw)جفت ها با dyld_info -fixup_chain_details، که چاپ می کندraw: 0x8010000000000000 bind: (next: 002, bindOrdinal: 0x000000)برای اولین بار
جدول واردات در آفسه 80 هشت ورودی 32 بیت دارد: lib_ordinal:8،weak_import:1،name_offset:23، با نام ها در آفسه 112 ._grade،_grade_label،_percent_change،_totalاز کتابخانه 1 و 4 تا 7 هستند___stack_chk_fail،___stack_chk_guard،_printf،_putsاز کتابخانه 2fixup_rows()دو جدول را به خط ها متصل می کندdyld_info -fixupsچاپ، مانند __DATA_CONST __got 0x100004038 bind libSystem/_puts، و آزمون همه 12 تا را مقایسه می کند.
پس "تباه کننده فاسد" در0x100004038dyld یک بار این زنجیره را در حال بارگذاری انجام می دهد و آدرس را می نویسد_putsبه سمت سوراخ جلسه WWDC22 اپل این را به این شکل بیان کرد: "در موقعیت اشاره 64 بت در DATA، برخی از بیت ها دارای تعویض به محل تنظیم بعدی هستند. همچنین یک بیت وجود دارد که می گوید آیا اصلاح یک پیوند یا یک بازتکنی است". Xcode 13 این فرمت را به عنوان فرمت پیش فرض برای هدف انتشار macOS 12 یا iOS 15 قرار داد و Xcode 13.3 آن را به macOS 11 و iOS 13.4 گسترش داد. هیچ پیوند تنبل در این فرمت وجود ندارد. هر سوراخ قبل از آن بسته شدهmainفرار می کنه
طرحي که عوضش کرد
ledger_main_nochainهمچین ارتباط با-Wl,-no_fixup_chains. . . .LC_DYLD_INFO_ONLYدر عوض، با چهار جدول بایت کدگذاری شده: 8 بایت باز، 72-بند، 122-بند تنبل، 64 صادر کنید. همچنین سه بخش دارد که فایل زنجیره ای از دست داده است: __TEXT,__stub_helper(108 بایت) ، یک__gotفقط 16 بايت نگه دارنده___stack_chk_guardوdyld_stub_binderو__DATA,__la_symbol_ptr(56 بايت، هفت سلايت)dyld_info -fixupsفهرست هفتتاlazy-bindصف ها و هفت تله که هر نقطه تنبل را به ترمپولین خودش نشان می دهند__stub_helperترمپولين يه شاخص رو فشار ميده و به سمت اون مي پرسهdyld_stub_binder، که نام را حل می کند و اسلات را می نویسد. این PLT و GOT بخش قبلی در شکل های Mach-O است: __la_symbol_ptr..got.plt،__stub_helperPLT0 و pushq $indexوdyld_stub_binder._dl_runtime_resolve.code/main.pyگزارش های تعویض و بخش های این پرونده و رمزگذاری کد های bind را نمی کند؛ آزمایشگاه تمرین از این امر می خواهد.
صادرات
LC_DYLD_EXPORTS_TRIEهر گره یک اندازه پایانی uleb128 است، پس اگر غیر صفر باشد، پرچم uleb128 و یک اوفسیت uleb128، سپس یک بایت تعداد کودک و برای هر کودک، یک لبه رشته و یک اوفسیت گره uleb128 است. exports_trie()راه میرهlibledger.dylibاون برگرده_percent_change 0x410،_grade 0x428،_total 0x464،_grade_label 0x498، چهار تعویضdyld_info -exportsبر روی دستگاه اجرا کننده باز می گردد__mh_execute_header،_fnsو_main. .
چه طناب می گذارد
اپلstrip(1)میگه که بدون گزینه ای روی یک اجراگر به طور پویا مرتبط رفتارش مثل-u -r: نماد های غیر تعریف شده و نماد های به طور پویا اشاره شده را ذخیره کنید. -xنماد های محلی را حذف می کند. -Nتمام جدول نماد و جدول رشته ها را حذف می کند. "برای کتابخانه های مشترک پویا، حداکثر سطح تخلیه معمولا -x است" زیرا "تنها نماد های جهانی توسط فرآیند پیوند پویا استفاده می شوند".
در دستگاه های ما مشاهده شدstrip ledger_mainگرفتLC_SYMTABاز 12 تا 10 پرونده حذف شد_main،_fnsو_names. هشت واردات نامشخص باقی می ماند چون باید نام های آنها را به هم متصل کند و__mh_execute_headerچون هستيREFERENCED_DYNAMICALLY. اون شماره 10 يه طعن نوعي هستN_OPTنامشradr://5614542، که ابزار اپل می نویسد تا میز هیچ وقت خالی نباشدnmبرنامه ی خالی شده همان سه خط را با اصلی چاپ می کند و از 0 خارج می شود.LC_FUNCTION_STARTSهنوز یه شروع دارهmain. .
strip libledger.dylibبدون هیچ گزینه ای از حد معمول صفحه مرد رفت-x.LC_SYMTAB0 ثبت شده وnm"هیچ نماد" چاپ می کند. "تری صادرات" هنوز هم چهار تابع را در همان تعویضات لیست می کند، زیرا "دایلد" از طریق "تری" متصل می شود و هرگز از طریق "تری" نیست.LC_SYMTAB.LC_FUNCTION_STARTSهنوز چهار شروع رو ميگهmain.cبا ديليب که از دستش گرفته شده است نشان ميده که رديتور لينک توسط تري هم خدمت مي کنه
| What | ELF after --strip-all | PE image | Mach-O after strip |
|---|---|---|---|
| static symbol table | gone | never present in an image | local and defined names gone, undefined imports stay |
| names the loader binds | .dynsym and .dynstr stay | import directory stays | imports stay in LC_SYMTAB and in the chained imports table |
| exported names | .dynsym stays | export directory stays | exports trie stays |
| function starts | .eh_frame FDEs, unless built without unwind tables | .pdata for non-leaf functions | LC_FUNCTION_STARTS stays |
| debug information | .debug_* gone | in the PDB, never in the image | in the dSYM, never in the image |
| section or load command headers | stay unless --strip-section-headers | stay | stay |
یافتن عملکردهای بدون علامت
static-arm64-O2لینک هاmain-arm64-O2.oوledger-arm64-O2.oبه یک اجراگر با پنج تابع در __text.nm -nاز پرونده ی بدون قطع شده حقیقت اصلی است:_mainدر0x100000500(244 بایت)_percent_changeدر0x1000005f4(24) ، _gradeدر0x10000060c(60)_totalدر0x100000648(248)_grade_labelدر0x100000740(72) static-arm64-O2.strippedنهN_SECTنماد داخل__text.FunctionFinderچهار روش رو اجرا ميکنه وscore()هر لیست رو با حقيقت مقایسه ميکنه
LC_FUNCTION_STARTS
فرمانده ها در 9 بايت در__LINKEDIT.80 0a f4 01 18 3c f8 01 00. فرمت اون "Uleb128 deltas" بود.__TEXTآدرس80 0a.0x500، پس اولين شروع0x100000500.f4 01.0xf4، پس0x1000005f4.18می دهد0x10000060c،3cمی دهد0x100000648،f8 01می دهد0x100000740و00پنج تا از پنجتا، بدون مثبت دروغین، در-O0و در-O2. مدیر لینک این جدول را برای "کتاب و خبرنگار حادثه" می نویسد وstripگيدرا اينو توي تحليل کننده "کار ماش-او شروع ميشه" ميخوادdyld_info -function_startsچاپش ميکنه و LIEF نشان ميده کهfunction_starts. .
اسکن های مقدمه
الگوهای شروع AARCH64 گیدرا با شروع میشنfd 7b bf a9، کهstp x29, x30, [sp, #-0x10]!در پرونده های ما 0 از 5 در هر دو سطح پیدا می کند.sub sp, sp, #Nاول و بعدstp x29, x30, [sp, #M]با تعویض مثبت، بنابراین فرم پیش از شاخص هرگز رخ نمی دهد.sub sp, sp, #imm،(word & 0xff0003ff) == 0xd10003ff، 5 از 5 را پیدا می کند-O0, که هر تابع دارای یک قاب است و 1 از 5 در -O2، کجاpercent_change،grade،totalوgrade_labelعملکردی با برگ بدون قاب است.percent_changeبا شروع می شهcbz w0, ...یک اسکن مقدماتی گزارش می دهد که کامپایلر چه چیزی را انتخاب کرده است و درس 38 نشان می دهد که چقدر اغلب چیزی نیست.
هیچ یک از اسکن ها نتیجه مثبت غلط را پیدا نکردند، چون برنامه کوچک است. الگوهای یک بائتی مانند x86-6455ازpush rbpدر داخل دستورالعمل های دیگر ضربه زد، به همین دلیل است که فایل های الگوی x86-64 Ghidra یک الگوی بعد از الگوی مانند55 48 89 e5با الگوی پیش از این مانند retیاnopکه باید عملکرد قبلی رو تموم کنه
هدف تماس
هر کسblدر__textنام یک تابع شروع می شود، زیرا blدر وسط یک تابع چیزی است که یک کامپایلر برای C منتشر نمی کند. کدگذاری آن 0x94000000با یک تعویض کلمه امضا شده 26 بتblدر0x1000005a0میخواد3d 00 00 94.0x3d۶۱ است، ضرب ۴ است0xf4، پس هدفش0x100000694. درledger_mainاين است که براي_putsدر ساخت جامدcall_targets()هدف ها رو در داخل جمع ميکنه__text، اونايي که واردشون ميشن رو مي کشونه__stubs، و اضافه می کند LC_MAINورود، چون هيچ چيز زنگ نمي زندmain۵ در هر دو سطح. هسته (اندریسه، سلوینسکا، بوس، 2017) کشف عملکرد خود را بر این ایده برای کد تولید شده توسط سازنده ایجاد می کند و اندریسه و دیگران در سال ۲۰۱۶ اندازه گیری کردند که مرزهای عملکرد بخش سخت تر از مرزهای دستورالعمل در تجزیه هستند.
امضا در شکل فلرت
هیکس-ریز در اسنادش، فلایر را توصیف می کند: یک الگوی "اولین 32 بایت یک تابع است که در آن تمام بایت های ویرانت مشخص شده است"، بایت های ویرانت از تنظیمات و مرجع های خارجی می آیند، الگوها در یک درخت زندگی می کنند و فراتر از الگوی "ما CRC16 بایت ها را از موقعیت 33 تا بایت های ویرانت اول محاسبه می کنیم" و این طول را ذخیره می کنیم. دو تابع با الگوی مشابه و CRC با یک بایت دم در موقعیت ای که آنها متفاوت هستند، از یکدیگر جدا می شوند، سپس با نام هایی که اشاره می کنند. برخوردی که هیچ چیز از هم جدا نمی کند "با هوش طبیعی حل می شود". تابع های کوتاه تر از چهار بایت بدون مرجع خارجی حذف می شوند و "فایل امضا شامل هیچ بایت از کتابخانه های اصلی نیست، به جز نام های عملکردها".
signatures_from_object()ازش ساختledger-arm64-O2.oوmain-arm64-O2.o، روش فلر از اشیا کتابخانه ساختهrelocation_infoثبت یک کلمه چهار بایت را پوشش می دهد و این بایت ها تبدیل به ویرانت می شوند..patطرح خط، در پارسر رزین مستند شده است، الگوی، طول CRC، CRC16، طول تابع، :0000و اسمش و^offset nameبرای هر نام مرجع:
textA00000342800004B890C8052087D091B000DC01AC0035FD6 00 0000 0018 :0000 _percent_change
E8CC8C52C8CCAC72087C289B09FD7FD308FD62930801090B081900511F110071 04 9AAF 003C :0000 _grade ^0000 l_switch.table.grade ^0001 l_switch.table.grade
E8CC8C52C8CCAC72087C289B09FD7FD308FD62930801090B081900511F110071 04 9AAF 0048 :0000 _grade_label ^0000 l_switch.table.grade_label ^0001 l_switch.table.grade_label ^0002 _labels ^0003 _labels_percent_change24 بایت است، بنابراین الگوی آن کل تابع است و طول CRC 0 است._gradeاین 60 بایت است با اولین نقل مکان در بایت 36، بنابراین CRC چهار بایت را پوشش می دهد. CRC16 یکی از عموم است.patاستفاده از پارسر: چندگانه 0x8408, ارزش اولیه 0xffff, تکمیل کنید و سپس دو بایت را عوض کنید. ارزش آن برای رشته ASCII "123456789" 0x6e90، و اون پين هاي آزمايشي
match_signatures()هر امضا را در هر شروع تابع از ساخت خالی، نمونه اول، سپس CRC امتحان می کند.-O0همه پنج تابع نامشون رو ميگيرن و هيچ چيز با هم نمي تونه برخورد کنه-O2دو خط بالا با هم برخورد ميکنهgrade_labelخط در خطgrade، بنابراین دو تابع اولین 36 بایت و چهار بایت CRC را به اشتراک می گذارند.0x10000060cو در0x100000740. دمشون رو ميفرقه: در بايت 44_grade.20و_grade_label.28، کهldr w0, [x9, w8, uxtw #2]مخالفldr x8, [x9, w8, uxtw #3]گزارش هم برخورد ها و هم بايتي که آنها را تصميم داد رو ثبت ميکنه.
آزمونtest_object_bytes_equal_linked_bytes_outside_relocated_wordsفرضیه را بررسی می کند: هر بائتی غیر متغیر از هر تابع شی برابر بائتی در همان تعویض در قابل اجرا مرتبط است، بنابراین ویرایشگر لینک فقط کلمات نقل شده را تغییر داد. _totalهیچ مکان و بايت متغیری ندارد
چه کاری ابزارها با همان ایده انجام می دهند
IDA Pro 9.4 امضا FLIRT در هر پردازنده و sigmakeابزار برای ساخت آنها؛ IDA Free فقط x86 و x86-64 را پوشش می دهد و برای استفاده غیر تجاری است. Lumina یک سرور است که کلید متاداتا عملکرد را با md5 از عملکرد و خارج کردن عملکرد زیر 32 بایت می کند. Ghidra 12.1.4 (Apache-2.0) دارای ID عملکرد است: یک هش کامل در mnemonics و حالت های آدرس است که "قابل تغییر ناشی از پیوند" است و یک هشت خاص که شامل آپرندهای ثابت، امتیاز داده شده در هر دستورالعمل مطابقت، با والدین و کودکان به عنوان ربط شکستن عملکرد است. پایگاه داده های ارسال شده آن فقط کتابخانه های Visual Studio را پوشش می دهد و شما خود را از دوگانه های خود پر می کنید. باینری نینجا 6.0 کریپتون (تجاری، با نسخه رایگان) از WARP (Apache-2.0) استفاده می کند: GUID عملکرد UUIDv5 بر روی GUID های بلاک پایه است، هر یک UUIDv5 بر روی بایت های بلاک پس از صفر کردن "همه دستورالعمل های قابل انتقال" و رها کردن NOP ها، با تماس، تماس گیرنده و تابع های مجاور به عنوان محدودیت. BinDiff 8 (Apache-2.0) عملکردهای بین دو دوگانه را با ترتیب ثابت گام ها، از هماهنگی هش از طریق شاخص های MD گراف جریان تا تماس با هماهنگی دنباله دار، مطابقت می دهد و شباهت را از حاشیه های هماهنگ، بلوک ها، دستورالعمل ها و شاخص MD گراف جریان وزن می کند. Diaphora 3.4.3 (AGPL-3.0 فقط، IDA) محصول عدد اول را اضافه می کند، جایی که هر نقشه mnemonic به یک عدد اول و یک تابع محصول است، یک اثر انگشت چند مجموعه بدون ترتیب. رادار2 6.2.4 (LGPL-3.0) دارای امضا (zg،z/،zb) و میخواد FLIRT باشه.sigفایل های با zfs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..patیا.sigاز یک دوگانه باز با Fcو یکی را باFs. .
IDA و Binary Ninja بسته شده اند و در اینجا از اسناد خود توصیف شده اند. رادار 2 و رزین بر روی این دستگاه نصب نشده اند و دستورات آنها از کتاب ها و منابع آنها نقل شده است. ابزار هایی که بر روی این تجهیزات اجرا شده استclang،ld،llvm-objdump،otool،nm،stripوdyld_infoاز طریق ابزار خط فرمان و LIEF 1.0.0، pyelftools 0.33 و پروفایل 2024.8.26 از طریق زبر. LIEF هر فرمت را در اینجا خواند، از جمله اشیاء COFF که از 0.17.0 پشتیبانی کرده است، و ده پیوند و دو بازبینی را در ledger_main، همون 12 تا اصلاحات . ابزار هاي رديف فقط پرونده هاي ELF رو مي خوانن . پروفايل رد شدmain-x86_64.objباPEFormatError: 'DOS Header magic not found.'و تصویر کوچولو رو بخونید.
آن را بسازید
نمایش نمایش را اجرا کن:
bashcd phases/13-tools-and-protocols/40-linking-loading-and-stripped-binaries
python3 code/main.pyمحصول یک گزارش JSON با پنج بخش است. elfتعداد نقل مکان دو شی، برنامه پیوند و بخش پویا، PLT و GOT از tiny-dyn-x86_64.coffدارای بخش ها، نقل مکان ها، عملکردها و نام های نامشخصی دو شی است. peدر این بخش، عنوان ها، فهرست ها، واردات ها، صادرات ها، نقل مکان های پایه ها و تماس های IAT را در اختیار دارد.tiny-x86_64.exe.machoنگه دارهledger_mainبا چوب های آن، حلقه های زنجیره ای، خط های حلقه و صادرات، طرح میراثledger_main_nochain، دیلب و دو گزارش "استریپ"identificationراستش رو ميگيره، چهار روش با نمره و امضا با برخوردشون، در-O0و-O2. .
شکل انتظار می رود:
json{
"elf": {"linkPlan": {"pltSymbols": ["puts", "printf"], "sizes": {".plt": 48, ".got.plt": 40, ".rela.plt": 48, ".rela.dyn": 48}, "...": "..."}, "tiny-dyn-x86_64": {"...": "..."}},
"coff": {"main-x86_64.obj": {"...": "..."}},
"pe": {"imports": [{"dll": "msvcrt.dll", "iat": "0x2040", "...": "..."}], "...": "..."},
"macho": {"ledger_main": {"flags": "0x200085", "fixupRows": ["__DATA_CONST __got 0x100004000 bind libledger/_grade", "..."], "...": "..."}, "strip": {"...": "..."}},
"identification": {"O2": {"methods": {"functionStarts": {"recall": "5/5"}, "prologueSub": {"recall": "1/5"}, "...": "..."}, "correctNames": 5}}
}بخونcode/main.pyدر این ترتیب:
ElfFileسر و قسمت ها، بخش ها، هر دو جدول نماد و نقل مکان ها را می خواند وdynamic_entries()،jump_slots()،plt_entries()وplt0()عکس مرتبط رو بخونيدplan_dynamic_link()جدول 4.9 و بخش 5.2 را برای سوابق نقل مکان اجسام قابل نقل مکان اعمال می کند.CoffObjectعنوان فایل، جدول بخش، نمادهای 18 بایت با سوابق دستی آنها و نقل مکان های 10 بایت را می خواند.PeImageدر این بخش، صفحه اصلی MS-DOS، امضا PE، سرپرست اختیاری، دایرکتوری های داده، بخش ها و دایرکتوری های واردات، صادرات و نقل مکان پایه خوانده می شود وiat_calls()کد هاff 15. .MachoFileدستورات بار، بخش ها را می خواندnlistسوابق، جدول نماد غیرمستقیم، ستوب ها، حل و فصل های زنجیره ای، آزمایش صادرات و نقل مکان اشیاء.FunctionFinderچهار تا تاپیک شروع رو اجرا میکنه وscore()هر دو را با حقیقت مقایسه می کند.signatures_from_object()وmatch_signatures()ساخت و استفاده از امضا های شکل FLIRT- .
parse_*تابع ها متن ابزار ضبط شده را که تست ها با آن مقایسه می کنند، می خوانند.
فرمان هاي ديگه:python3 code/main.py elf FILE،coff FILE،pe FILEوmacho FILEیک گزارش چاپ کنید.python3 code/main.py plan OBJECT...نقشه پیوند برای هر مجموعه ای از اشیاء ELF را چاپ می کند. python3 code/main.py functions STRIPPED UNSTRIPPED OBJECT...نمره هاي پيدا کننده ها و امضا ها رو به يه جفت ديگه از ساختمونات ميده
ازش استفاده کن
از خواننده ها در این ترتیب در برنامه ای که ساختی استفاده کن
- این کتاب را به عنوان کتابچه ای به صورت کامل بخوانید. این کتاب را به عنوان کتابچه ای به صورت کامل بخوانید.
- واردات را با ارائه دهندگانشان فهرست کنید:
DT_NEEDEDو.dynsym، فهرست واردات یا جدول واردات زنجیره ای وLC_LOAD_DYLIBهر تماس با يک اسم در اون ليست تصويري رو ميذاره - یک تماس را به دست به سمت اسلات آن دنبال کنید. باایت های تماس، باایت های استوب یا PLT، آدرس اسلات، کلمه در فایل و آنچه بارگذاری کننده در آن می نویسد را یادداشت کنید. اگر کلمه در فایل مانند زباله به نظر می رسد، آن را به عنوان یک اصلاح رمزگذاری کنید قبل از اینکه آن را زباله نامید.
- جدول نماد را با صادرات مقایسه کنید و تابع شروع می شود. نام های بارگذاری نیاز به زنده ماندن دارند
stripاسم ها فقط يه بازنماينده نياز داره بگو که اسم گمشده به کدام گروه تعلق داشته - در ساخت خالی، پیدا کننده هایی را اجرا کنید که می توانید اجرا کنید و آنها را در برابر دوقلوی خالی با وجود یک جدول انتخاب کنید. جدول هایی را که مدیر لینک نوشته است ترجیح دهید.
LC_FUNCTION_STARTS،.pdata، یا.eh_frame، از الگوهای بائیت استفاده کنید و از هدف های تماس برای پر کردن شکاف ها استفاده کنید. - از اجسام خود امضا بسازید و آنها را اعمال کنید. هر برخورد و بائتهایی که آن را تقسیم می کنند را ثبت کنید. یک نام که دو امضا ادعا می کند ناشناخته است تا زمانی که دم یا نام مرجع تصمیم بگیرد.
متن ابزار ضبط شده را با فایل ها نگه دارید. وقتی زنجیره ابزار تغییر می کند، بازیافت کنید، زیرا لیست تغییر شده یک تنظیم تغییر کرده است.
آزمایشگاه تعاملی
آزمایشگاه A: PLT دست
ازcodeدایرکتوری، پیتون باز:
bashcd phases/13-tools-and-protocols/40-linking-loading-and-stripped-binaries/code
python3 -qراه رفتن:
pythonfrom main import *
elf = load_elf("tiny-dyn-x86_64")
[(e.tag_name, e.text) for e in elf.dynamic_entries()]
elf.plt0()
[(e.symbol, hex(e.address), hex(e.slot), hex(e.slot_initial)) for e in elf.plt_entries()]
[hex(w) for w in elf.got_plt_words()]قبل از هر تماس، جواب را از بائتهای متن بالا محاسبه کنید. سپس تغییر کنید IMPORTSدرbuild_tiny_dyn_elf.pyبه سه اسم، بازسازی، و پیش بینی اندازه های جدید از .plt،.got.pltو.rela.pltقبل از اينکه بخواني
لابراتوار ب: یک حل حل زنجیری
pythonexe = load_macho("ledger_main")
stub = next(s for s in exe.stubs() if s.symbol == "_puts")
stub.lines()
raw = int.from_bytes(exe.read(stub.slot, 8), "little")
hex(raw), raw >> 63, (raw >> 51) & 0xfff, raw & 0xffffff
[(i.index, i.name, i.library) for i in exe.chained_fixups()["imports"]]اول کلمه ی bind را روی کاغذ رمزگذاری کنید: bit bind، the nextبعد کلمه هشت بایت بیشتر را بخوانید و تایید کنید که این است که بعدی است. سپس آخرین کلمه از زنجیره را در0x100004058و توضیح بده چراnextصفر است.
آزمایشگاه C: تخلیه و پیوند مجدد
در فهرست لوازم جانبی، یک برنامه تازه را با دیلیب کاملاً پاک شده پیوند دهید:
bashcd phases/13-tools-and-protocols/40-linking-loading-and-stripped-binaries/code/fixtures
clang -target arm64-apple-macos -O1 main.c -L. -lledger.stripped -Wl,-rpath,@executable_path -o /tmp/relinked
nm /tmp/relinked | grep ' U '
dyld_info -exports libledger.stripped.dylibارتباط با کتابخانه ای کهLC_SYMTABخالی است، چون مدیر لینک، محاسبات صادرات را می خواند.python3 ../main.py macho libledger.stripped.dylibو مقایسه کنیدsymtab،exportsوfunctionStartsبعد از اون ساخت جامد رو از دست بده-Nولي ببینیم چی میشهdyld_info -function_startsهنوز اثر اثر.
لابراتوار D: برخورد
pythonfrom main import *
stripped = load_macho("static-arm64-O2.stripped")
sigs = signatures_from_object(load_macho("ledger-arm64-O2.o"))
[s.pat_line() for s in sigs]
starts = FunctionFinder(stripped).function_starts()
match_signatures(sigs, stripped, starts)دو تا پرونده برخورد رو بخوني و امضا رو ازledger-arm64-O0.o، با هم برکنارstatic-arm64-O0.stripped، و از .patخط هایی که چرا هیچ برخوردی در آن رخ نمی دهد-O0پس کوتاهش کنPATTERN_LENGTHتا 16 و شمارش کنید که چند تا از عملکردها درهم برخورد می کنند.
آزمایشگاه تمرین
جدول های مرتبط قدیمی را رمزگذاری کنید و پی را پیدا کنید.
الزامات:
- رمزگشایی
LC_DYLD_INFO_ONLYبازتاب، پیوند و تنبل پیوند جریان های کد opcode ازledger_main_nochainبه صف هایی با بخش، بخش، آدرس، نوع و هدف تقسیم کنید و آنها را برابر به 21 ردیف در تصویر گرفته شده کنیدdyld_info -fixupsمتن - اضافه کنید
PT_GNU_RELROعنوان برنامه و یکDT_FLAGSباDF_BIND_NOWبهbuild_tiny_dyn_elf.py، حرکت کن.got.pltدر داخل محدوده پوشش داده شده و ساختllvm-objdump -pدر فستورهای README بگو که کدام قسمت از RELRO کامل این بازتولید و کدام قسمت فقط glibc می تواند انجام دهد. - يه حرف بنويس
.pdataخواننده برای یک تصویر PE32+ و یک فنکشن فینڈر که استفاده می کندRUNTIME_FUNCTIONشروع کردن آدرس ها. ساخت یک شی باclang -target x86_64-pc-windows-msvc -cبدون-fno-asynchronous-unwind-tables، مطالعه کن.pdataنقل مکان ها و ذکر اینکه کدام از عملکردهای آن عملکردهای ورق است که جدول حذف می کند. - یک آزمون برای هر خواننده بنویسید که با متن ابزار ضبط شده مقایسه شود.
موفقیت به معنیpython3 code/main.py macho ledger_main_nochainهمان 21 ردیف اصلاحی را چاپ می کند که dyld_infoانگشت ها، ELF کوچولو دارهPT_GNU_RELROاینllvm-objdumpلیست ها و.pdataفینڈر، عملکردی را که می تواند نام دهد و عملکردی را که نمی تواند لیست کند.
درس هنرپیشه
این درس شاملoutputs/skill-linking-loading-and-stripped-binaries.mdازش استفاده کنید تا برنامه ای که ساختید را به یک لیست وارداتش با ارائه دهندگانش تبدیل کنید، یک تماس به سمت نقطه ای که بارگذاری کننده پر می کند، یک بیانیه از آنچهstripاین نیاز به دوقلوی بدون قطع به عنوان حقیقت زمین، یک فهرست ابزار ضبط شده برای هر ادعا و یک رکورد از هر برخورد است.
بررسی کنید
نمایش و مجموعه تعیین کننده را اجرا کنید:
bashcd phases/13-tools-and-protocols/40-linking-loading-and-stripped-binaries
python3 code/main.py
python3 code/tests/test_main.pyبررسی باید ثابت کند:
- بخش پویا از
tiny-dyn-x86_64دوچاپllvm-objdump -pبرچسب به برچسب وDT_FLAGS_1حمل کنندهDF_1_PIE - دوتا
R_X86_64_JUMP_SLOTثبتات همديگهllvm-objdump -Rو اسمشputsوexit - PLT0 GOT+8 را فشار می دهد و از GOT+16 عبور می کند، هر ورودی سلائت خود را می خواند و شاخص خود را فشار می دهد و هر سلائت آدرس خود را دارد
pushq - بخش ها و عنوان برنامه هاي مسابقه ي کوچک ELF
llvm-objdump -h -p - ثبت نقل مکان دو شیء ELF همدست است
llvm-objdump -r - نقشه لینک دو نماد PLT، چهار تماس مستقیم، دو نقل مکان نسبی و اندازه تصویر کوچک را پیدا می کند
- جدول بخش COFF، 37 رکورد نماد با رکورد های دستی و نقل مکان ها مطابقت دارد
llvm-objdump -h -t -rو/16تصمیم می گیرد.llvm_addrsig - سه COFF
REL32ثبتledgerدر سه ELF نشسته باشPC32تعویضات - سرنخ های PE
DllCharacteristics, و فهرست داده ها همدست می شوندllvm-objdump -p - فهرست واردات، اطلاعات اشاره/نام و مطابقت IAT
llvm-objdumpوpefile, و IAT برابر با جدول جستجو قبل از اتصال - فهرست صادرات و
DIR64کد بازکنونی پایه و اشارهگر بازکنونی به رشته "به دست متصل شده" نام می دهد ff 15در RVA0x100bبه قسمت IAT ازputs- پرچم هاي ماچ او، نام هاي فرمان 19 بار و دو کتابخانه همديگه
otool - هفت تا تا تا هشت تا
__gotاسلات و جدول نماد غیر مستقیم مطابقت داردotool -Iv - سرش رو هم با هم مي بينم
llvm-objdump --macho --chained-fixups - زنجیره ی راه رفتن همه ی 12 کلمه خام را تولید می کند
dyld_info -fixup_chain_details - خط های ثابت و جدول واردات همدیگر را هم می سازند
dyld_info -fixupsو-imports - صادرات همبستگی
dyld_info -exportsبرای دیلب و نسخه ی آن nm_lines()برابر استnm -mبرای نسخه قابل اجرا و نسخه ی قطع شده آنstripحذف شد_main،_fnsو_names، 9تا نام و 1تا نام نگه داشتهradr://5614542چاقو، و برنامه جدا شده همان خروجی را چاپ می کند- طرح قدیمی داره
LC_DYLD_INFO_ONLY، هفت تا اشاره ي تنبل و بازي هاي بازي__stub_helper - بازنشستگی های آبرکت arm64 مطابقت دارد
llvm-objdump -r LC_FUNCTION_STARTSپنج تا پنج تا در هر دو سطح و برابر استnmوdyld_info -function_starts- .
sub spاسکن پنج تا پنج تا رو پیدا کرد-O0و یکی از پنجتا-O2وstpاسکن فریم هیچ چیزی پیدا نکرد blهدف ها و اضافه کردنLC_MAINبازیافت ورود پنج از پنج- امضا ها به نام تمام پنج تابع در هر دو سطح و ثبت کردن
gradeبرخورد با بایت 44 - CRC16 از "123456789" است
0x6e90، و هشت بايت تحت جفت بار GOTmainمتغیر هستند - هر بائتی غیر متغیر بائتی بائتی مرتبط برابر است
- نمایش و داده های ارقام گزارش آدرس های مشابه و ماژول سایت داده های مشابه را در ES5 گنجانده است
روش های شکست تولید
| Failure | What the weak tool reports | What the analysis must prove |
|---|---|---|
A bl or call lands in a stub | "calls an unnamed function at 0x694" | the stub bytes, the slot it loads, and the import the slot binds |
| A GOT word read from the file | "corrupt pointer 0x8010000000000007" | bit 63 is bind, next is 2, ordinal 7 is _puts from library 2 |
PLT32 in an object | "every call goes through the PLT" | defined symbols are reduced to a direct distance, only undefined ones get an entry |
| Partial RELRO read as full | "GOT is read-only" | .got.plt slots after the three reserved ones sit outside PT_GNU_RELRO without -z now |
COFF REL32 compared with ELF PC32 | "the Windows build has different relocations" | same offsets, the -4 lives in the ELF addend and in the COFF field |
| IAT read before load | "imports point at strings" | the IAT equals the lookup table until the loader binds, and the strings are hint/name entries |
| A stripped dylib | "no symbols, nothing exported" | the exports trie and LC_FUNCTION_STARTS list every function |
nm on a stripped executable | "one function" | LC_FUNCTION_STARTS lists five starts, nine bytes long |
A prologue scan at -O2 | "one function" | four leaf functions have no frame, call targets and the starts table find them |
| Two functions share 36 bytes | "grade_label is grade" | the tail byte at 44 and the lengths 60 and 72 split the collision |
| A tool run on another machine's build | the numbers in this text | recapture every listing from your own fixtures |
قاعده عملیاتی
هر تماس خارجی را از سایت تماس تا اسلات پر شده توسط بارگذاری دنبال کنید و کلمه را در آن اسلات به عنوان فرمت تعریف می کند قبل از اینکه آن را یک آدرس بخوانید. فقط بعد از اینکه چیزی که بارگذاری هنوز نیاز دارد را ضبط کرده اید، از بین ببرید. عملکرد بازیابی از جدول هایی که مدیر لینک قبل از جستجو برای بایت ها نوشته است شروع می شود، هر جستجوگر را با دوقلو با نمادها مقایسه کنید و هر برخورد امضا با بایت که آن را تقسیم می کند را ثبت کنید.
خواندن بیشتر
- System V gABI, chapter 5: Program Loading and Dynamic Linking
- System V Application Binary Interface, AMD64 Architecture Processor Supplement: section 5.2 and Table 4.9
- Drepper, "How To Write Shared Libraries", version 4.1.2
- Drepper, "ELF Symbol Versioning"
- Jelinek, "Little hardening DSOs/executables against exploits", binutils list, 2004-01-06
- Taylor, "Linker relro", 2008
- binutils commit bd7ab16b: PLT32 for calls, 2018-02-13وLLVM D43383
- GNU Binutils: stripوllvm-objcopy
- Microsoft, PE Format
- CALL instruction reference, FF /2
- Apple, mach-o/loader.hوmach-o/nlist.h
- Apple dyld, mach-o/fixup-chains.h
- Apple ld64, stub_arm64.hpp
- Xcode 13 release notes: chained fixupsوWWDC22 session 110362, "Link fast: Improve build and launch times"
- strip(1)،ld(1)وdyld(1)
- Hex-Rays, IDA F.L.I.R.T. Technology: In-DepthوLumina overview
- Ghidra Function ID helpوAARCH64 function start patterns
- Vector 35, WARPوBinary Ninja WARP guide
- BinDiff manualوBinDiff source
- Diaphora
- rizin pat.c, the .pat parser،radare2 flirt.cوradare2 book: Zignatures
- Andriesse et al., "An In-Depth Analysis of Disassembly on Full-Scale x86/x64 Binaries" (USENIX Security 2016)وAndriesse, Slowinska, Bos, "Compiler-Agnostic Function Detection in Binaries" (EuroS&P 2017)
- Bao et al., ByteWeight (USENIX Security 2014)وShin, Song, Moazzezi, "Recognizing Functions in Binaries with Neural Networks" (USENIX Security 2015)
- LIEF changelog،pyelftoolsوpefile
This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.
Browse the complete course catalog or open this lesson on GitHub.