Phase 13: Tools & Protocols

लिंकिंग, लोडिंग और स्ट्रिप बाइनरीः 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

सीखने के लक्ष्य

  • स्थानांतरण रिकॉर्ड और प्रतीक तालिकाओं से तय करें कि लिंक संपादक इससे क्या बनाता हैः एक निश्चित दूरी, एक GOT स्लॉट के साथ एक PLT प्रविष्टि, या एक गतिशील स्थानांतरण।
  • स्थिति-निर्भर ELF निष्पादित करने योग्य के गतिशील अनुभाग, PLT और GOT को पढ़ें और psABI सूत्रों के साथ उन पर एक कॉल का पालन करें।
  • COFF ऑब्जेक्ट (20 बाइट फ़ाइल हेडर, 40-बाइट अनुभाग प्रविष्टियाँ, 18-बाइट प्रतीक, 10-बाइट स्थानांतरण) और एक PE32+ छवि के आयात, निर्यात और आधार स्थानांतरण निर्देशिकाएँ पढ़ें।
  • एक Mach-O चेन फिक्सअप श्रृंखला शब्द के लिए शब्द को डिकोड और प्रत्येक शब्द के खिलाफ मेलdyld_info. .
  • क्या बताओstripहटाता है और प्रत्येक प्रारूप में क्या जीवित रहता है, और यह साबित करने के लिए हटाया कार्यक्रम चलाएं कि यह अभी भी काम करता है.
  • के साथ एक डिस्ट्रिप किया गया arm64 निर्माण के कार्य प्रारंभ को पुनर्प्राप्त करेंLC_FUNCTION_STARTS, प्रोग्रैग स्कैन, और कॉल लक्ष्य, अंक अंक प्रत्येक विधि के साथ प्रतीक तालिका के साथ अनडिस्ट्रिप्ड जुड़वां, और एक FLIRT के आकार के हस्ताक्षर के साथ कार्यों का नाम.

समस्या

आप लिंक किया main.clibledger.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, और एक का जवाब दिया।

दोनों उत्तरों में फ़ाइल को ऐसा पढ़ा जाता है जैसे यह चल रही प्रक्रिया है।0x100004038बिट 63 कहता है कि बांधें, बारह बिट कहते हैं कि अगला फिक्सअप कहां है, और निचले बिट कहते हैं कि कौन सा आयात करना है।_putsपहलेmainहटाए गए फ़ाइल ने अपने प्रतीक तालिका खो दिया और रखा गयाLC_FUNCTION_STARTS, जो सभी पांच कार्यों की सूची नौ बाइट में शुरू होता है।

इस पाठ में मानक पुस्तकालय पायथन में पांच रीडर बनाए गए हैं। हमारे स्वयं के वस्तुओं के लिए एक COFF रीडर और आयात, निर्यात और आधार स्थानांतरण निर्देशिकाओं के लिए एक PE32+ रीडर। लोड कमांड, स्टब, अप्रत्यक्ष प्रतीक तालिका, चेन फिक्सअप श्रृंखला और निर्यात ट्रे के लिए एक मैक-ओ रीडर, शब्द के लिए शब्द के खिलाफ चेक किया गया dyld_info. गतिशील अनुभाग, PLT, और GOT के लिए एक ELF रीडर, साथ ही एक प्लानर जो बताता है कि हमारे वस्तुओं के एक PIE लिंक क्या बनाएगा। चार तरीकों के साथ एक डिस्ट्रिप बिल्ड के लिए एक फ़ंक्शन फाइंडर और प्रत्येक के लिए एक स्कोर। एक हस्ताक्षर बिल्डर FLIRT के आकार में, वाइल्डकार्ड रीलोकेशन बाइट्स और पूंछ के CRC16 के साथ।

केवल Mach-O इस मशीन पर लिंक. arm64 निष्पादन और dylib जुड़े थे, डिलीब, और चलाया. ELF और COFF वस्तुओं यहाँ संकलित किया गया थाclang -target, और कोई ELF या PE लिंक संपादक स्थापित नहीं है, इसलिए उन प्रारूपों में दो जुड़े छवियों को फिक्स्चर फ़ोल्डर में दो पायथन स्क्रिप्ट द्वारा विनिर्देशों से बाइट द्वारा बाइट लिखा गया था। llvm-objdumpवे नहीं चलाए गए थे, और पाठ कहता है कि जहां यह मायने रखता है।

स्थानांतरण के साथ लिंक संपादक क्या करता है

पाठ 32 में स्थानांतरण रिकॉर्ड और पाठ 33 में लागू किया गया है ।S + A - Pएक leaएक रिकॉर्ड एक जगह का नाम हैP, एक प्रकार, एक प्रतीक S, और एक अतिरिक्त A. x86-64 psABI तालिका 4.9 में प्रत्येक प्रकार के लिए एक सूत्र दिया गया है, जिसमें Lप्रतीक के PLT प्रविष्टि के स्थान के लिए, Gऔर उसके (अज़ाब के) बदले मेंGOTGOT पते के लिए, और 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, और 2 में .rodata. .plan_dynamic_link()में code/main.pyइन तीनों नियमों को लागू करता है।ledger-x86_64-O1.o:

RecordCountDecisionWhy
R_X86_64_PC32 to .rodata, .L.str, fns, the table in .rodata16in placethe symbol is defined in the inputs
R_X86_64_PLT32 to percent_change, grade, total, grade_label4direct, no PLTdefined in ledger-x86_64-O1.o, so the link editor reduces PLT32 to PC32
R_X86_64_PLT32 to puts twice and printf twice4PLT entry and GOT slotundefined, provided by a shared library
R_X86_64_64 to grade in fns[]2R_X86_64_RELATIVEan absolute field in a PIE

दो आयात एक .plt48 बाइट्स (PLT0 प्लस दो प्रविष्टियाँ 16), एक .got.plt40 बाइट्स (तीन आरक्षित स्लॉट प्लस दो) और एक .rela.pltदो सापेक्ष रिकॉर्ड एक .rela.dyn48 बाइट्स के साथ. ये संख्या हमारे रिकॉर्ड पर लागू विनिर्देश से आते हैं. हाथ से बनाया गयाtiny-dyn-x86_64इस योजना के PLT भाग को उसी दो आयातों के लिए लागू करता है, और इसका आकार योजना के अनुरूप है।

संकलक लिखता है PLT32प्रत्येक कॉल पर, परिभाषित या अपरिभाषित, क्योंकि binutils 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) बिना PLT के GOT स्लॉट के लिए पूछें, जो -fno-pltउत्पादन करता है और जो लिंक संपादक एक प्रत्यक्ष करने के लिए आराम कर सकते हैं leaया callजब प्रतीक स्थानीय हो (psABI परिशिष्ट B) । R_X86_64_32और R_X86_64_32Sएक पीआईई में एक पता नहीं रख सकते हैं और लिंक विफल रहता है. दोनों प्रकार हमारे दोनों वस्तुओं में नहीं होता है.

गतिशील खंड, पीएलटी और जीओटी

gABI अध्याय 5 में कहा गया है कि एक निष्पादनशील जो गतिशील लिंक में भाग लेता है एक है PT_INTERPकार्यक्रम हेडर, जो किसी भी लोड करने योग्य खंड से पहले होना चाहिए, और एक PT_DYNAMIC, जो .dynamicअनुभाग। अनुभाग की एक सरणी हैElf64_Dynजोड़े, एक हस्ताक्षरित टैग और एक मूल्य, द्वारा समाप्तDT_NULL. .

tiny-dyn-x86_64द्वारा लिखा गया है 5184 बाइट्स है build_tiny_dyn_elf.pyइसके गतिशील खंड में 12 जोड़े हैं।0x1000:

TagNumberValueMeaning
DT_NEEDED1libc.so.6a string table offset, 0xb, the library to load
DT_HASH40x1a0the SysV hash table
DT_STRTAB50x188.dynstr
DT_SYMTAB60x140.dynsym, 24 bytes per entry
DT_STRSZ100x1521 bytes of strings
DT_SYMENT110x1824
DT_PLTGOT30x10c0.got.plt
DT_PLTRELSZ20x30two 24-byte records
DT_PLTREL207the records are DT_RELA
DT_JMPREL230x1b8.rela.plt
DT_FLAGS_10x6ffffffb0x08000000DF_1_PIE, a GNU tag
DT_NULL00end

GABI क्यों कहता है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 बाइट्स है, तो प्रविष्टि के लिए exit0x210, धक्का देता है $0x1और पढ़ता है 0x10e0. .

सरकार तीन स्लॉट आरक्षित करती है। psABI 5.2: प्रविष्टि शून्य में _DYNAMIC, और "विश्व ऑफसेट तालिका में एक और दो प्रविष्टियों भी आरक्षित हैं।.got.pltपढ़ता है 0x1000, 0, 0, 0x206, 0x216. glibc अपने साथ स्लॉट एक भरता है struct link_mapऔर स्लॉट दो के साथ _dl_runtime_resolveजब यह फ़ाइल लोड करता है. स्लॉट तीन पकड़ता है0x206फ़ाइल में, जो है pushqअंदरputs@plt. psABI: स्लॉट "शुरुआत में ... निम्नलिखित पुशक्यू निर्देश का पता रखता है।

तो पहली कॉल चला जाता है call 0x200,jmpq *0x10d8भूमि परpushq $0,jmp 0x1f0GOT+8 को धक्का देता है और GOT+16 के माध्यम से रिज़ॉल्वर में कूदता है, जो कि रिकॉर्ड 0 को पढ़ता है DT_JMPREL,R_X86_64_JUMP_SLOT puts, दिखता हैputsऊपर में libc.so.6, अपना पता लिखता है 0x10d8और वहाँ कूदता है. दूसरा कॉल चलता हैcall,jmpq *0x10d8ड्रेपर लिखते हैं कि "पहली कॉल को छोड़कर सभी के लिए ओवरहेड इसलिए 'केवल' एक अप्रत्यक्ष छलांग है।%r11पाठ 38 में एक रजिस्टर विकल्प समझाता हैः यह एक खरोंच रजिस्टर है इसलिए "PLT में कोड को किसी भी रजिस्टर को spill करने की आवश्यकता नहीं है।

कॉल साइट में .textपढ़ता है e8 d4 ff ff ffपर0x227और 0x22c - 0x2c = 0x200. .llvm-objdumpछापें callq 0x200 <puts@plt>इसके लिए और से प्रविष्टि का नाम.rela.pltरिकॉर्ड, जो कि कैसे है plt_entries()इसे भी नाम दें।

फ़ाइल में क्या नहीं है

फ़ाइल में कोई नहीं है PT_GNU_RELRO. जैकब जेलेनक ने 2004-01-06 को द्वि-उपयोग सूची में RELRO का प्रस्ताव रखाः केवल स्थानांतरण के दौरान लिखे गए खंडों को लेखन योग्य खंड की शुरुआत में स्थानांतरित करें, ताकि गतिशील लिंकर mprotectGNU ld के डिफ़ॉल्ट स्क्रिप्ट डालता है.init_array,.fini_array,.data.rel.ro,.dynamicऔर .gotअंदर, और केवल तीन आरक्षित स्लॉट रखता है.got.pltअंदर, 24 बाइट्स, क्योंकि अन्य स्लॉट आलसी लिखा जाता है. यह आंशिक RELRO है. -z nowसेट DF_BIND_NOWऔर पूरे को ले जाता है .got.pltअंदर, पूर्ण RELRO, क्योंकि स्टार्टअप के बाद कुछ भी नहीं लिखा जाता है. glibc के _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सूचकांक 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. पीई प्रारूप पृष्ठ वस्तु को परिभाषित करता हैः एक 20-बाइट फ़ाइल हेडर, कोई वैकल्पिक हेडर नहीं, 40-बाइट प्रविष्टियों की एक अनुभाग तालिका, 18-बाइट रिकॉर्डों की एक प्रतीक तालिका, और 10-बाइट प्रति अनुभाग स्थानांतरण रिकॉर्ड।

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और 4 IMAGE_REL_AMD64_ADDR64में .rdata. .REL32यह "पहले स्थानान्तरण के बाद बाइट से 32 बिट सापेक्ष पता" है।R_X86_64_PC32के साथ -4में निर्मितः ELF रिकॉर्ड में अतिरिक्त है -4क्योंकि रिकॉर्ड में एक अतिरिक्त फ़ील्ड है, और COFF रिकॉर्ड में कोई नहीं है। ledger-x86_64.objतीन है REL32पर0x36,0x84और 0x93, और पाठ 32 ledger-x86_64-O1.oउसके तीन है R_X86_64_PC32कोड एक ही है, और प्रारूप केवल चार में अलग है जहां लिखा गया है। ADDR64एक आठ बाइट पूर्ण पता है, labelsस्ट्रिंग पॉइंटर की तालिका, और यह छवि में एक आधार स्थानांतरण बन जाता है, के रूप में R_X86_64_64बन जाता हैR_X86_64_RELATIVE. .

ELF Elf64_RelaCOFF relocationMach-O relocation_info
record size24 bytes10 bytes8 bytes
fieldsoffset, type and symbol in r_info, addendoffset, symbol index, typeaddress, then a 32-bit word with symbolnum:24, pcrel:1, length:2, extern:1, type:4
addendexplicitnone, lives in the fieldnone, or an ARM64_RELOC_ADDEND record before the real one
the call to putsR_X86_64_PLT32 puts-0x4IMAGE_REL_AMD64_REL32 putsARM64_RELOC_BRANCH26 _puts

पीई छविः आयात, निर्यात और आधार स्थानांतरण

tiny-x86_64.exeद्वारा लिखा गया है 2,560 बाइट्स है build_tiny_pe.pyयह एक ही काम करता है छोटे ELF: कॉलputsऔर exitसेmsvcrt.dll. यह एक नाम का निर्यात भी करता है और एक आधार स्थानांतरण भी करता है, इसलिए इस पाठ की आवश्यकता वाले तीन निर्देशिकाएं सभी मौजूद हैं। pefile2024.8.26 और 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 0x8160HIGH_ENTROPY_VA 0x0020,DYNAMIC_BASE 0x0040,NX_COMPAT 0x0100और TERMINAL_SERVER_AWARE 0x8000. फिर 16 RVA और आकार के डेटा निर्देशिकाएँ सेट की जाती हैं.0x2080आकार 0x4d, आयात 0x2000आकार 0x28, बेस रिलॉकेशन 0x4000आकार 0xc, IAT पर 0x2040आकार 0x18. .

एक छवि में पते आरवीए हैं, लोड आधार से ऑफसेट। अनुभाग तालिका उन्हें फ़ाइल ऑफसेट के लिए मानचित्रित करती हैः .textआरवीए 0x1000फ़ाइल पर 0x200,.rdataआरवीए 0x2000पर0x400,.dataआरवीए 0x3000पर0x600,.relocआरवीए 0x4000पर0x800. .PeImage.rva_to_offset()यह है कि टेबल.

आयात सूचकांक

आरवीए में 0x2000एक शून्य वर्णक के साथ समाप्त 20 बाइट आयात वर्णक के एक सरणी में स्थित है. हमारे पास एक हैः आयात खोज तालिका 0x2028, समय टिकट 0, प्रेषक श्रृंखला 0, नाम 0x2068, आयात पता तालिका 0x2040. नाम RVA "msvcrt.dll" पर इंगित करता है। खोज तालिका में 64 बिट प्रविष्टियाँ हैं जो शून्य से समाप्त होती हैं। बिट 63 सेट का अर्थ है ऑर्डरल द्वारा आयात, 15 से 0 बिट्स में ऑर्डरल के साथ। बिट 63 स्पष्ट अर्थ है कि 30 से 0 बिट्स एक संकेत / नाम प्रविष्टि का RVA हैंः एक 16-बिट संकेत, "एक्सपोर्ट नाम पॉइंटर्स टेबल में एक सूचकांक", फिर ASCII नाम। हमारे हैं 0x2058(संकेत 0, "पॉट्स") और 0x2060(संकेतक 0, "प्रस्थान") ।

विनिर्देश में कहा गया है कि आईएटी "आयात खोज तालिका की सामग्री के समान है जब तक छवि बाध्य नहीं होती है।"0x2040एक ही दो आरवीए रखता है, और परीक्षण जांच करता है कि 24 बाइट्स पर 0x2028बराबर 24 बाइट्स पर 0x2040. "बंद करने के दौरान, आयात पता तालिका में प्रविष्टियों को आयात किए जा रहे प्रतीकों के 32-बिट (पीई 32 के लिए) या 64-बिट (पीई 32+ के लिए) पते के साथ ओवरराइट किया जाता है।" विंडोज लोडर प्रवेश बिंदु चलाने से पहले ऐसा करता है। कोई आलसी बाध्यकारी और कोई स्टब नहीं है। कोड सीधे स्लॉट तक पहुंचता हैः

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 exit

FF /2दो निर्देशों में एक ही बाइट्स हैं क्योंकि प्रत्येक दूसरे के बाद आठ बाइट्स बैठता है और एक स्लॉट को दूसरे के बाद आठ बाइट्स पढ़ता है। iat_calls() के लिए कोड अनुभाग स्कैन करता हैff 15, 6 और विस्थापन जोड़ता है, और आयात निर्देशिका से स्लॉट का नाम देता है।

निर्यात निर्देशिका

आरवीए में 0x208040 बाइट निर्यात निर्देशिका तालिकाः ध्वज, समय टिकट, संस्करण, "tiny-x86_64.exe" पर इंगित करने वाला एक नाम RVA, ऑर्डिनल आधार 1, 1 पता तालिका प्रविष्टि, 1 नाम सूचक। तीन तालिकाएँ निम्नलिखित हैं।0x20a8एक आरवीए रखता है, 0x1000. निर्यात नाम सूचक तालिका 0x20ac"tiny_entry" स्ट्रिंग के लिए एक RVA रखता है।0x20b0एक 16-बिट निष्पक्ष सूचकांक, 0 रखता है। नाम kप्रविष्टि के लिए पता लगाने के लिए मानचित्र ordinals[k], और निर्यात किया गया ऑर्डिनल है ordinals[k] + ordinal base. विनिर्देश एक नियम जोड़ा है कि हम उपयोग नहीं करतेः एक पता प्रविष्टि जो निर्यात अनुभाग के अंदर इंगित करता है एक शिपमेंटर स्ट्रिंग है जैसे MYDLL.expfunc, और नाम पॉइंटर तालिका "बाइनरी खोजों की अनुमति देने के लिए शब्दकोश क्रमबद्ध है।

बेस स्थानांतरण

.relocप्रत्येक ब्लॉक एक पृष्ठ आरवीए और एक ब्लॉक आकार के साथ शुरू होता है, फिर शीर्ष चार बिट्स में प्रकार के साथ 16-बिट प्रविष्टियाँ और निचले बारह में एक पृष्ठ ऑफसेट। हमारा एक ब्लॉकः पृष्ठ 0x3000, आकार 12, प्रविष्टि 0xa000, प्रकार 10, IMAGE_REL_BASED_DIR64, ऑफसेट 0, और प्रकार 0 के पैडिंग प्रविष्टि, IMAGE_REL_BASED_ABSOLUTE. आरवीए पर आठ बाइट्स0x3000रखो0x1400020d0, छवि आधार प्लस स्ट्रिंग का RVA "हैंडलाइन लिंक"। यदि लोडर छवि को कहीं और रखता है, तो यह उस फ़ील्ड में अंतर जोड़ता है। विनिर्देशः "छवि फ़ाइलों में COFF स्थानांतरण नहीं होते हैं ... एक छवि में .reloc अनुभाग में आधार स्थानांतरण के रूप में स्थानांतरण जानकारी होती है (जब तक कि छवि में IMAGE_FILE_RELOCS_STRIPPED विशेषता नहीं है) । "/DYNAMICBASEवर्तमान link.exe में डिफ़ॉल्ट रूप से चालू है, इसलिए छवियों को ले जाने के लिए .relocऔर DYNAMIC_BASE. .

एक पीई छवि में कोई प्रतीक तालिका नहीं है. फ़ाइल हेडर है PointerToSymbolTable"एक छवि के लिए शून्य होना चाहिए क्योंकि COFF डिबगिंग जानकारी अप्रचलित है", और नाम एक अलग PDB में रहते हैं। जो हर छवि में जीवित रहता है आयात निर्देशिका, निर्यात निर्देशिका, और, के लिए 64-बिट कोड, .pdata, जिसका RUNTIME_FUNCTIONप्रविष्टियों प्रत्येक समारोह की शुरुआत और अंत का नाम है जो स्टैक आवंटित करता है या किसी अन्य समारोह को बुलाता है।

Mach-O छविः लोड कमांड, स्टब और अप्रत्यक्ष प्रतीक तालिका

ledger_mainयह लिंक्ड arm64 निष्पादित किया जा सकता है। otool -h19 लोड कमांड और ध्वज प्रिंट करता है 0x00200085. .MH_NOUNDEFS 0x1,MH_DYLDLINK 0x4,MH_TWOLEVEL 0x80और MH_PIE 0x200000उस मूल्य के लिए योग। 19 आदेश चार हैं।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. .

__TEXT0x100000000. .__text पर 256 बाइट है0x100000558,mainऔर कुछ नहीं, क्योंकि चार लेजर कार्यों dylib में रहते हैं।__stubs पर 84 बाइट्स है0x100000658, 12 बाइट्स के सात स्टब। __DATA_CONST0x100004000के साथ__got, 64 बाइट, आठ अनुभाग प्रकार के पॉइंटर स्लॉट 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   x16

0x90000030है adrpरजिस्टर कम पांच बिट है, 16.immlo30 से 29 बिट्स है, 0. immhi23 से 5 बिट्स है।immhi << 2 | immlo = 4, 4,096 बाइट्स के पृष्ठों में, तो लक्ष्य पृष्ठ निर्देश के पृष्ठ है, 0x100000000, प्लस 0x4000. .0xf9401e10है ldrएक असीमित 12-बिट ऑफसेट के साथ 8: बिट 21 से 10 के लिए 7 है, गुना 8 है 0x38, तो लोड पढ़ता है 0x100004038. .0xd61f0200है br x16. ID64 के स्रोत में Arm64 स्टब इस तरह के तीन निर्देश है .StubAtom. .

इस स्लॉट का कौन सा नाम अप्रत्यक्ष प्रतीक तालिका से आता है। LC_DYSYMTABप्रतीक तालिका में 15 सूचकांक पर अंक। एक स्टब खंड में कहा गया है reserved1जहां सूचकांक की अवधि शुरू होती है और reserved2प्रत्येक स्तंभ की मात्रा (12) । एक सूचक खंड का उपयोग करता है reserved1और प्रति स्लॉट आठ बाइट्स। __stubsसूचकांक 0 और पर शुरू होता है__gotसूचकांक 7 पर, तो प्रतीक तालिका प्रविष्टि 10 के लिए 5 नक्शे को स्टब करें। _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 bits के रूप में n_desc, 1 के लिए पहली LC_LOAD_DYLIB, 2 के लिए दूसरे, 0xfeगतिशील खोज के लिए, 0xffनिष्पादन योग्य के लिए।ld(1): " -two_levelnamespace (डिफ़ॉल्ट) के साथ, लिंकर केवल प्रतीक के लिए कमांड लाइन पर डिलीब खोजता है, और रिकॉर्ड करता है कि किस डिलीब में वे पाए गए थे। "nm_lines() से बारह रिकॉर्ड प्रस्तुत करता हैn_type,n_sect,n_descऔर n_value, और परीक्षण अपनी आउटपुट लाइन लाइन के लिए लाइन से कैप्चर की तुलना करता है nm -m. से कनेक्ट करें-Wl,-flat_namespaceऔर पढ़ेंotool -hMH_TWOLEVELथोड़ा गायब हो जाओ।

चेन फिक्सअप, बाइट फॉर बाइट

LC_DYLD_CHAINED_FIXUPSहै linkedit_data_commanddataoff 0x8000,datasize 208. 208 बाइट्स के बाद fixup-chains.h. .

हेडर में सात 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_imageseg_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_start0 से DYLD_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 बाइट्स पर है. ऑर्डिनल 0 है।0x4058,0x00000000000006db63 बिट खाली, एक रिबेस.next0 है, श्रृंखला के अंत. लक्ष्य है 0x6db, एक vm ऑफसेट, और छवि आधार 0x100000000यह करता है0x1000006db, स्ट्रिंग "असामान्य" में __cstring. . शब्द इससे पहले,0x00100000000006d6, रेबेस names[0]"सही" के लिए।

इस पदयात्रा में बारह शब्द शामिल हैं: आठ शब्द में बंधे हुए हैं।__got0 से 7 तक के क्रम के साथ, दो बंधन में __const0 के साथ (दोनों प्रविष्टियों के साथ fns[]_grade), और के दो रेबेसnames[]. .chained_fixups()उन्हें उनके फ़ाइल ऑफसेट और कच्चे शब्दों के साथ लौटाता है, और परीक्षण तुलना करता है बारह (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। 0 से 3 के लिए सामान्य हैं _grade,_grade_label,_percent_change,_totalपुस्तकालय 1 से 4 से 7 तक हैं ___stack_chk_fail,___stack_chk_guard,_printf,_putsपुस्तकालय से 2। fixup_rows()पंक्तियों में दोनों तालिकाओं को जोड़ता है dyld_info -fixupsछापें, जैसे __DATA_CONST __got 0x100004038 bind libSystem/_puts, और परीक्षण सभी बारह की तुलना करता है।

तो "भ्रष्ट संकेत" पर0x100004038आयात 7 है। dyld इस श्रृंखला एक बार चलता है, लोड पर, और पता लिखता है _putsस्लॉट में. Apple के WWDC22 सत्र ने इसे इस तरह रखाः "डेटा में 64-बिट पॉइंटर स्थान में, कुछ बिट्स में अगले फिक्सअप स्थान पर ऑफसेट होता है। इसमें यह भी बताया गया है कि क्या फिक्सअप एक बेंड या रीबेस है। " एक्सकोड 13 ने मैकोस 12 या आईओएस 15 के एक डिप्लोयमेंट लक्ष्य के लिए प्रारूप को डिफ़ॉल्ट बनाया, और एक्सकोड 13.3 ने इसे मैकोस 11 और आईओएस 13.4 तक बढ़ा दिया। इस प्रारूप में कोई आलसी बंधन नहीं है। हर स्लॉट पहले से बंधा हैmainदौड़ता है।

यह लेआउट की जगह ले लिया

ledger_main_nochain के साथ एक ही संबंध है-Wl,-no_fixup_chains. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .LC_DYLD_INFO_ONLYइसके बजाय, चार बाइट-कोडेड तालिकाओं के साथः रीबेस 8 बाइट्स, बेंड 72, आलसी बेंड 120, निर्यात 64. इसमें तीन अनुभाग भी हैं जो श्रृंखला फ़ाइल में कमी हैः __TEXT,__stub_helper(108 बाइट्स), एक __gotकेवल 16 बाइट्स के रखरखाव के साथ ___stack_chk_guardऔर dyld_stub_binderऔर __DATA,__la_symbol_ptr(56 बाइट, सात स्लॉट) ।dyld_info -fixupsसात सूची lazy-bindपंक्तियों और सात rebases कि अपने स्वयं के ट्रंपोलिन में प्रत्येक आलसी स्लॉट इंगित __stub_helperट्रैंपॉलिन एक सूचकांक धक्का और कूदता हैdyld_stub_binder, जो नाम को हल करता है और स्लॉट लिखता है। यह Mach-O आकारों में पिछले खंड की PLT और GOT है: __la_symbol_ptrहै .got.plt,__stub_helperहै PLT0 और 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_SYMTAB12 से 10 रिकॉर्ड से हटाया गया।_main,_fnsऔर _names. आठ अनिश्चित आयात बने रहेंगे, क्योंकि उन्हें उनके नामों को बाध्य करने की आवश्यकता है, और __mh_execute_headerरहता है क्योंकि यह है REFERENCED_DYNAMICALLYदसवीं रिकॉर्ड एक प्रकार की चाकू हैN_OPTनामितradr://5614542, जो एप्पल के उपकरण लिखते हैं ताकि टेबल कभी खाली नहीं है; nmडिस्ट्रिप प्रोग्राम मूल के समान तीन पंक्तियों को प्रिंट करता है और 0 से बाहर निकलता है।LC_FUNCTION_STARTSअभी भी एक शुरुआत है, main. .

strip libledger.dylibकोई विकल्प के साथ आदमी के पृष्ठ की सामान्य से आगे चला गया -xLC_SYMTAB0 रिकॉर्ड है और nmनिर्यात ट्रे अभी भी चार कार्यों को एक ही ऑफसेट पर सूचीबद्ध करता है, क्योंकि डिल्ड ट्रे के माध्यम से बंधता है और कभी नहीं के माध्यम सेLC_SYMTAB. .LC_FUNCTION_STARTSअभी भी चार स्टार्ट्स सूचीबद्ध है। लैब सी एक नया लिंकmain.cडिलीब के खिलाफ दिखाएं कि लिंक संपादक भी ट्राई द्वारा सेवा की जाती है।

WhatELF after --strip-allPE imageMach-O after strip
static symbol tablegonenever present in an imagelocal and defined names gone, undefined imports stay
names the loader binds.dynsym and .dynstr stayimport directory staysimports stay in LC_SYMTAB and in the chained imports table
exported names.dynsym staysexport directory staysexports trie stays
function starts.eh_frame FDEs, unless built without unwind tables.pdata for non-leaf functionsLC_FUNCTION_STARTS stays
debug information.debug_* gonein the PDB, never in the imagein the dSYM, never in the image
section or load command headersstay unless --strip-section-headersstaystay

बिना प्रतीक के कार्य ढूंढना

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

आदेश नौ बाइट में अंक __LINKEDIT80 0a f4 01 18 3c f8 01 00. प्रारूप Uleb128 डेल्टा है, जो कि पहली बार__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]!. हमारे फ़ाइलों पर यह दोनों स्तरों पर 5 में से 0 पाता है.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 दिखाया कि कितनी बार यह कुछ भी नहीं है.

किसी भी स्कैन में गलत सकारात्मक उत्पन्न नहीं किया गया है, क्योंकि कार्यक्रम छोटा है।55push rbpअन्य निर्देशों के अंदर मारा, यही कारण है कि Ghidra के x86-64 पैटर्न फ़ाइलों एक पोस्ट-पैटर्न की तरह जोड़ी55 48 89 e5जैसे पूर्व-पैटर्न के साथ retया nopजो पिछले कार्य को समाप्त करना चाहिए।

कॉल लक्ष्य

हर blमें __textएक फ़ंक्शन शुरू नाम, क्योंकि एक blएक समारोह के बीच में कुछ है कि एक संकलक C के लिए उत्सर्जित नहीं करता है. एन्कोडिंग है 0x94000000एक हस्ताक्षरित 26-बिट शब्द ऑफसेट के साथ।blपर0x1000005a0पढ़ता है 3d 00 00 940x3dहै 61, गुना 4 है 0xf4, तो लक्ष्य है 0x100000694.ledger_mainयह है _puts. स्थैतिक निर्माण में,call_targets()अंदर के लक्ष्य को एकत्र करता है __text, जो लोग में उतरते हैं गिर जाता है __stubs, और जोड़ता है LC_MAINप्रवेश, क्योंकि कुछ भी नहीं बुलाता mainदोनों स्तरों पर पांच में से पांच। न्यूक्लियस (एंड्रिस, स्लोविनस्का, बोस, 2017) ने संकलक-जनित कोड के इस विचार पर अपने फ़ंक्शन डिटेक्शन का निर्माण किया, और एंड्रिस और अन्य ने 2016 में मापा कि फ़ंक्शन सीमाएं असेंबली का सबसे कठिन हिस्सा हैं, निर्देश सीमाओं से कठिन हैं।

एक फ्लर्ट के आकार का हस्ताक्षर

हेक्स-रेज अपने दस्तावेज में FLIRT का वर्णन करता हैः एक पैटर्न "एक फ़ंक्शन के पहले 32 बाइट्स है जहां सभी वैरिएंट बाइट्स चिह्नित हैं", वैरिएंट बाइट्स फिक्सअप और बाहरी संदर्भों से आते हैं, पैटर्न एक पेड़ में रहते हैं, और पैटर्न के परे "हम स्थिति 33 से शुरू होने वाले बाइट्स की CRC16 की गणना करते हैं पहले वैरिएंट बाइट" और उस लंबाई को संग्रहीत करते हैं। एक ही पैटर्न और सीआरसी वाले दो कार्यों को एक स्थिति में एक पूंछ बाइट द्वारा अलग किया जाता है जहां वे भिन्न होते हैं, फिर उनके द्वारा संदर्भित नामों द्वारा। एक टक्कर जिसे कोई भी अलग नहीं करता है, "प्राकृतिक बुद्धि द्वारा हल किया जाता है। बाहरी संदर्भों के बिना चार बाइट से कम फ़ंक्शन को बाहर रखा गया है, और "हस्ताक्षर फ़ाइल में मूल पुस्तकालयों से कोई बाइट नहीं है, कार्यों के नामों को छोड़कर।

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_changeहै 24 बाइट्स, तो इसके पैटर्न पूरे समारोह है और CRC लंबाई 0 है।_gradeयह 60 बाइट्स है, पहली बार 36 बाइट्स पर स्थानांतरित होने के साथ, इसलिए CRC चार बाइट्स को कवर करता है। CRC16 सार्वजनिक है।.patपारसर्स का उपयोगः बहुपद 0x8408, प्रारंभिक मूल्य 0xffffASCII स्ट्रिंग के लिए इसका मान "123456789" है0x6e90, और परीक्षण pins कि.

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 प्रति प्रोसेसर और sigmakeउन्हें बनाने के लिए उपकरण; IDA Free केवल x86 और x86-64 को कवर करता है और गैर-व्यावसायिक उपयोग के लिए है। Lumina एक सर्वर है जो फ़ंक्शन के md5 द्वारा फ़ंक्शन मेटाडेटा की कुंजी देता है और 32 बाइट्स से कम फ़ंक्शन को छोड़ देता है। गिड्रा 12.1.4 (अपाचे-2.0) में फ़ंक्शन आईडी हैः एमनेमोनिक्स और एड्रेसिंग मोड पर एक पूर्ण हैश जो "लिंकिंग के कारण परिवर्तनों के खिलाफ मजबूत है" और एक विशिष्ट हैश जो प्रति मिलान निर्देशों पर स्कोर किए गए निरंतर ऑपरेन्ड जोड़ता है, जिसमें माता-पिता और बच्चे के कार्य टाई-ब्रेकर के रूप में होते हैं; इसके भेजे गए डेटाबेस केवल विज़ुअल स्टूडियो पुस्तकालयों को कवर करते हैं, और आप अपने स्वयं के बाइनरी से अपना स्वयं का भराव करते हैं। बाइनरी निंजा 6.0 क्रिप्टन (व्यावसायिक, एक मुफ्त संस्करण के साथ) WARP (अपाचे-2.0) का उपयोग करता हैः फ़ंक्शन GUID बुनियादी ब्लॉक GUIDs पर UUIDv5 है, प्रत्येक "सभी स्थानांतरित करने योग्य निर्देश" को शून्य करने और NOPs को छोड़ने के बाद ब्लॉक बाइट्स पर UUIDv5 है, जिसमें कॉल, कॉलर और आसन्न फ़ंक्शन प्रतिबंध के रूप में हैं। BinDiff 8 (अपाचे-2.0) दो द्विआधारी विकल्पों के बीच कार्यों को एक निश्चित क्रम के साथ मेल खाता है, जो प्रवाह ग्राफ एमडी सूचकांक के माध्यम से हैश मिलान से क्रम मिलान को कॉल करता है, और मिलान किनारों, ब्लॉकों, निर्देशों और प्रवाह ग्राफ एमडी सूचकांक से समानता का वजन करता है। डायफ़ोरा 3.4.3 (एजीपीएल-3.0, केवल आईडीए) छोटे प्राइम उत्पाद जोड़ता है, जहां प्रत्येक एमनेमोनिक एक प्राइम और एक फ़ंक्शन के लिए नक्शे बनाता है उत्पाद, एक आदेश मुक्त मल्टीसेट फिंगरप्रिंट। रडार2 6.2.4 (LGPL-3.0) में हस्ताक्षर हैं (zg,z/,zb) और पढ़ता है FLIRT .sig के साथ फ़ाइलेंzfs; रिज़िन 0.9.1 (LGPL-3.0) बनाता है .patया .sigके साथ एक खुले बाइनरी से Fcऔर एक के साथ लागू होता है Fs. .

IDA और बाइनरी निंजा बंद हैं और यहां उनके दस्तावेज से वर्णित हैं। इस मशीन पर रडार 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, एक ही बारह फिक्सअप. पिल्ट टूल्स केवल 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इस सूची में मुख्य पृष्ठ, निर्देशिका, आयात, निर्यात, आधार स्थानांतरण और आईएटी कॉल शामिल हैं।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इस क्रम मेंः

  1. ElfFileशीर्षक, खंड, दोनों प्रतीक तालिकाओं और स्थानांतरण पढ़ता है, और dynamic_entries(),jump_slots(),plt_entries()और plt0()लिंक की गई छवि पढ़ें।
  2. plan_dynamic_link()तालिका 4.9 और धारा 5.2 को स्थानांतरित करने योग्य वस्तुओं के स्थानांतरण रिकॉर्ड पर लागू किया जाता है।
  3. CoffObjectफ़ाइल हेडर, अनुभाग तालिका, उनके सहायक रिकॉर्ड के साथ 18-बाइट प्रतीक, और 10-बाइट स्थानांतरण पढ़ता है।
  4. PeImageMS-DOS स्टब, पीई हस्ताक्षर, वैकल्पिक हेडर, डेटा निर्देशिकाएँ, अनुभाग, और आयात, निर्यात और आधार स्थानांतरण निर्देशिकाएँ पढ़ता है, और iat_calls()डिकोडff 15. .
  5. MachoFileलोड कमांड, खंडों को पढ़ता है, nlistरिकॉर्ड, अप्रत्यक्ष प्रतीक तालिका, स्टब, चेन फिक्सअप, निर्यात ट्रू, और वस्तु स्थानांतरण।
  6. FunctionFinderचार प्रारंभ खोजकर्ताओं को चलाता है और score()और हर एक की तुलना सत्य से करती है।
  7. signatures_from_object()और match_signatures()FLIRT के आकार के हस्ताक्षर बनाएँ और लागू करें।
  8. 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...अपने स्वयं के निर्माण के एक और जोड़े पर खोजकर्ताओं और हस्ताक्षरों को स्कोर करता है।

इसका प्रयोग करें

अपने द्वारा बनाए गए प्रोग्राम पर पाठकों का इस क्रम में उपयोग करें।

  1. हेडर पढ़ें और प्रारूप और प्रकार का नाम देंः स्थानांतरित करने योग्य वस्तु, निष्पादित या साझा पुस्तकालय। पाठक वह नहीं जानता कि क्या अस्वीकार करता है, और यह अस्वीकार सूचना है।
  2. आयातों को उनके प्रदाताओं के साथ सूचीबद्ध करें: DT_NEEDEDऔर .dynsym, आयात निर्देशिका, या श्रृंखलाबद्ध आयात तालिका और LC_LOAD_DYLIBउस सूची में किसी नाम के लिए हर कॉल छवि छोड़ देता है।
  3. एक कॉल को उसके स्लॉट पर हाथ से फॉलो करें। कॉल बाइट्स, स्टब या पीएलटी बाइट्स, स्लॉट पता, फ़ाइल में शब्द, और लोडर वहां क्या लिखता है लिखें। यदि फ़ाइल में शब्द कचरे की तरह दिखता है, तो इसे कचरा कहने से पहले इसे एक फिक्सअप के रूप में डिकोड करें।
  4. प्रतीक तालिका को निर्यात के साथ तुलना करें और फ़ंक्शन शुरू होता है. लोडर के नामों को जीवित रहने की आवश्यकता है strip. नाम केवल एक डिबगर की जरूरत है नहीं. बताओ कि कौन सा समूह एक गायब नाम से संबंधित था.
  5. एक striped निर्माण में, खोजकर्ताओं को चलाएं आप चला सकते हैं और उन्हें अनडिस्ट्रिप्ड जुड़वां के खिलाफ स्कोर करते हैं जबकि आप अभी भी एक है। तालिकाओं लिंक संपादक ने लिखा है पसंद करते हैं, LC_FUNCTION_STARTS,.pdataया .eh_frame, बाइट पैटर्न पर, और रिक्तियों को भरने के लिए कॉल लक्ष्य का उपयोग करें.
  6. अपनी वस्तुओं से हस्ताक्षर बनाएं और उन्हें लागू करें। प्रत्येक टक्कर और बाइट को रिकॉर्ड करें जो इसे विभाजित करता है। एक नाम जो दो हस्ताक्षरों ने दावा किया है वह तब तक अज्ञात है जब तक कि पूंछ या संदर्भित नाम यह तय नहीं करता।

जब टूलचेन बदलता है, फिर से कैप्चर करें, क्योंकि एक बदल गई सूची एक बदल गई फिटिंग है।

इंटरैक्टिव लैब

लैब एः हाथ से पीएलटी

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 शब्द को डिकोड करेंः bind bit, nextचार बाइट्स की इकाइयों में क्षेत्र, ऑर्डरल. फिर शब्द आठ बाइट्स आगे पढ़ें और पुष्टि यह अगले फिक्सअप है. फिर श्रृंखला के अंतिम शब्द पढ़ें0x100004058और समझाएँ कि क्यों nextशून्य है।

लैब सी: स्ट्रिप और रिलिंक

फिचर्स निर्देशिका में, एक नया प्रोग्राम को पूरी तरह से डिलीब के साथ जोड़ेंः

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खाली है, क्योंकि लिंक संपादक निर्यात trie पढ़ता है. फिर चलाएँ python3 ../main.py macho libledger.stripped.dylibऔर तुलना करेंsymtab,exportsऔर functionStarts. फिर स्थैतिक निर्माण को हटा दें-Nइसके बजाय और देखें क्या dyld_info -function_startsअभी भी निशान.

लैब डी: टक्कर

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_LENGTH16 और गणना कितनी फ़ंक्शंस टकराव.

अभ्यास प्रयोगशाला

पुराने बाध्यकारी तालिकाओं को डिकोड करें और पीई खोजक जोड़ें।

आवश्यकताएँः

  • LC_DYLD_INFO_ONLYrebase, bind, और आलसी bind opcode धाराओं के ledger_main_nochainखंड, खंड, पता, प्रकार और लक्ष्य के साथ पंक्तियों में, और उन्हें कैप्चर में 21 पंक्तियों के बराबर बनाने dyld_info -fixupsपाठ.
  • एक जोड़ें PT_GNU_RELROकार्यक्रम शीर्षक और एक DT_FLAGSके साथDF_BIND_NOWbuild_tiny_dyn_elf.py, आगे बढ़ें.got.pltकवर रेंज के अंदर, और बनाने llvm-objdump -pREADME में बताएं कि पूर्ण RELRO का कौन सा हिस्सा यह reproduces और कौन सा हिस्सा केवल glibc perform कर सकता है।
  • एक लिखें .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 REL32ledgerतीन ELF पर बैठें PC32मुआवजा
  • पीई हेडर, DllCharacteristics, और डेटा निर्देशिकाओं मेल खाती हैं llvm-objdump -p
  • आयात निर्देशिका, संकेत/नाम प्रविष्टियाँ और आईएटी मैच llvm-objdumpऔर pefile, और आईएटी बंधन से पहले खोज तालिका के बराबर है
  • निर्यात निर्देशिका और DIR64आधार स्थानांतरण डिकोड, और स्थानांतरित पॉइंटर स्ट्रिंग का नाम "हैंडलाइन लिंक"
  • ff 15आरवीए में 0x100b के IAT स्लॉट में हल करता हैputs
  • Mach-O ध्वज, 19 लोड कमांड नाम, और दो पुस्तकालयों मेल खाते हैं otool
  • सात स्टब को आठ में डिकोड करें __gotस्लॉट और अप्रत्यक्ष प्रतीक तालिका मैच otool -Iv
  • चेन फिक्सअप हेडर मेल खाता है llvm-objdump --macho --chained-fixups
  • श्रृंखला चलती है सभी बारह कच्चे शब्दों को पुनः प्रस्तुत करता है dyld_info -fixup_chain_details
  • फिक्स् अप पंक्तियों और आयात तालिका मेल खाती है dyld_info -fixupsऔर -imports
  • निर्यात के लिए एक मेल dyld_info -exportsऔर (उसकी) एक (अज़ाब) और एक (अज़ाब) और उसकी एक (अज़ाब) का टुकड़ा
  • nm_lines()बराबर nm -mनिष्पादित करने योग्य और उसके निकाले गए प्रति के लिए
  • stripहटा दिया गया_main,_fnsऔर _names, नौ नाम और एक रखा radr://5614542चाकू, और striped कार्यक्रम प्रिंट करता है एक ही आउटपुट
  • विरासत लेआउट है 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
  • "123456789" की CRC16 है 0x6e90, और GOT लोड जोड़ी के नीचे आठ बाइट्स mainवेरिएंट हैं
  • प्रत्येक गैर-वैकल्पिक वस्तु बाइट लिंक किए गए बाइट के बराबर है
  • डेमो और आंकड़े डेटा एक ही पते की रिपोर्ट करते हैं, और साइट मॉड्यूल ES5 में एक ही डेटा एम्बेड करता है

उत्पादन विफलता मोड

FailureWhat the weak tool reportsWhat 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 buildthe numbers in this textrecapture every listing from your own fixtures

परिचालन नियम

कॉल साइट से लोडर भरने वाले स्लॉट तक प्रत्येक बाहरी कॉल का पालन करें, और उस स्लॉट में शब्द को कोड करें जैसा कि प्रारूप इसे परिभाषित करता है इससे पहले कि आप इसे एक पता कहें। लोडर को अभी भी क्या चाहिए, उसे रिकॉर्ड करने के बाद ही strip करें। रिकवरी फ़ंक्शन बाइट्स के लिए स्कैन करने से पहले लिंक संपादक द्वारा लिखी गई तालिकाओं से शुरू होता है, प्रत्येक खोजकर्ता को प्रतीक के साथ जुड़वां के खिलाफ स्कोर करता है, और प्रत्येक हस्ताक्षर को बाइट के साथ रिकॉर्ड करता है जो इसे विभाजित करता है।

आगे पढ़ना

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.