تماس با کنوانسیون ها و فریم های استیک: سیستم V، ویندوز x64 و AArch64
Type: Build
Languages: Python, C, x86-64 and AArch64 assembly
Prerequisites: Phase 13 · 32 (ELF from scratch), Phase 13 · 33 (disassembly and control flow)
Time: ~140 minutes
اهداف یادگیری
- کنوانسیون تماس را از عنوان موضوع انتخاب کنید: ELF x86-64 سیستم V psABI است، COFF AMD64 مایکروسافت x64 است، ELF AArch64 AAPCS64 است، Mach-O arm64 نسخه ای از اپل است.
- پیشگام یک تابع بایت به بایت برای هر ABI را رمزگذاری کنید و هر ثبت ذخیره شده، آدرس بازگشت و اشاره کننده فریم را در تعویض آن از اشاره کننده ستاک ورود قرار دهید.
- ثبت پارامتر یک تابع از ثبت هایی که قبل از نوشتن آن می خواند و سلاٹس استدلال های سقف از بارگذاری های بالای اشاره کننده سقف ورود وارد کنید.
- به دنباله های مستقل سیستم V از نقاط موقعیت مایکروسافت x64 و هر دو از شمارشگر NGRN و NSRN AAPCS64 بگویید.
- هر نتیجه گیری را با امضای منبع، قانون مشخصات و داده های خود را در
.pdata،.xdataو.eh_frame. . - مقایسه کنید که چگونه Ghidra، IDA، Binary Ninja، radare2، rizin، و angr نام و بازیابی از همان حقایق، و ثبت کنید که در آن محصول با منبع مخالف است.
مشکل
تو جمع آوری کردیconvention.cبرای لینوکس x86-64 در -O2و از رادار2.6.2.4 خواستند تا استدلال های eight_argsجوابش با هفت تا بود:rdi،rsi،rdx،r8،r9،rsp+0x8وrsp+0x10. منبع C هشت پارامتر داره . بايت ها می خوانند%rcxدقیقاً یک بار، درleaq (%rdx,%rcx), %rax، و بازیافت متغیر ابزار یک ثبت نام را که فقط در داخل یک آدرس ظاهر می شود، شمارش نمی کند.
سپس نسخه ویندوز از همان فایل را در رزین 0.9.1 باز کرد.amd64و پیدا شدr8،rcx،rdx، و سه نقطه ی سقف. این شی COFF است، بنابراین کنوانسیون مایکروسافت x64 است، استدلال چهارم ثبت کننده r9دو ابزار در یک منبع مختلف را از دست می دهند.
یک لیست یک سری دستورالعمل ها است. یک کنوانسیون تماس یک قرارداد است که خارج از لیست می باشد: چه ثبت کننده ها استدلال های حمل، که تماس گیرنده باید حفظ کند، در کجا آدرس بازگشت و استدلال های دسته قرار دارد و چه چیزی باید تماس گیرنده بالای اشاره کننده دسته باقی بماند. چهار سند قرارداد مهم رو در اين مورد مشخص ميکنه سیستم V AMD64 psABI (ورژن 1.0, ساخت تاریخ 12 مارس 2025) بخش 3.2.1 تا 3.2.3. کنوانسیون تماس های Microsoft x64، استفاده از استیک و صفحات پیشگام و اپیلگ (تاریخ صفحه از 2018-12-17 تا 2025-03-19). بازوی AAPCS64 انتشار 2025Q4 (23 ژانویه 2026) بخش 6.1 تا 6.9. نوتاژ پلتفرم آرم 64 اپل این درس این قوانین را می خواند، آنها را به یک فایل C که به سه روش مرتب شده است، اعمال می کند و تحلیلگر را ایجاد می کند که یک لیست را به یک لیست چک شده از مکان های پارامتر، ثبت های ذخیره شده و فریم آفسیت ها تبدیل می کند.
یک سرنوشت کتاب قوانین را انتخاب می کند
convention.cدوتا وظیفۀ دارد:leaf_add،eight_args،mixed،by_value،big_ret،sum_varargs،keeps، و پنج نفر از تماس گیرندگانexternعملکردهای مشابهی.long long، چونlongاین برنامه 4 بایت در هدف MSVC و 8 بایت در بقیه است و یک ساختار است که تغییر اندازه تغییرات کنوانسیون است. اپل کلینگ 17.0.0 آن را هفت بار از این دستگاه مرتب:-target x86_64-unknown-linux-gnu،x86_64-pc-windows-msvcوaarch64-unknown-linux-gnuدر-O0و-O2وarm64-apple-macosدر-O2هیچ عنوان لینوکس و ویندوز نصب نشده است، بنابراین فایل آنچه را که نیاز دارد اعلام می کند و فقط شامل clang خود است stdarg.hوstddef.h. .
describe_object()درcode/main.pyشماره جادويي 4 بايت و يک فيلد ماشين را مي خواند و نام قرارداد را مي دهد:
| Header | Field | Value | Rulebook |
|---|---|---|---|
7f 45 4c 46 ELF | e_machine at offset 0x12 | 62 | System V AMD64 psABI |
64 86 COFF | Machine at offset 0 | 0x8664 | Microsoft x64 |
7f 45 4c 46 ELF | e_machine | 183 | AAPCS64 |
cf fa ed fe Mach-O 64 | cputype at offset 4 | 0x0100000c | AAPCS64 with Apple differences |
این سه قرارداد تقریبا در هر ردیف جدول زیر با هم متفق نیستند. هر مقدار از سند نامگذاری شده در ردیف سر نوشته شده است و هر یک از آنها با یک آزمایش با فکسچرها بررسی می شود.
| Rule | System V psABI | Microsoft x64 | AAPCS64 |
|---|---|---|---|
| Integer arguments | %rdi %rsi %rdx %rcx %r8 %r9, next free register | RCX RDX R8 R9, by position | x0 to x7, by NGRN |
| Floating-point arguments | %xmm0 to %xmm7, next free register | XMM0 to XMM3, by position | v0 to v7, by NSRN |
| Integer result | %rax, then %rdx | RAX | x0, then x1 |
| Floating-point result | %xmm0, then %xmm1 | XMM0 | v0 |
| Result too large for registers | address passed in %rdi "as if it were the first argument", returned in %rax | pointer in RCX, arguments shifted right, returned in RAX | address in x8, x0 to x7 untouched |
| Callee-saved | %rbp %rbx %r12 to %r15 | RBX RBP RDI RSI RSP R12 to R15, XMM6 to XMM15 | r19 to r29, SP, low 64 bits of v8 to v15 |
| First stack argument on entry | 8(%rsp) | 40(%rsp), above a 32-byte shadow store | 0(sp) |
| Below the stack pointer | 128-byte red zone | "considered volatile" | no red zone (Apple: 128 bytes) |
| Alignment at the call | (%rsp + 8) multiple of 16 on entry | 16-byte aligned outside prolog and epilog | SP mod 16 = 0 |
| Variadic marker | %al holds an upper bound on vector registers used | floats duplicated in the integer register | none in registers; Apple uses 8-byte stack slots |
سیستم V: دو ردیف ثبت مستقل و یک منطقه قرمز
psABI 3.2.3 هر هشت بائیتی از هر استدلال را به عنوان INTEGER، SSE یا MEMORY طبقه بندی می کند و سپس ثبت نام ها را از دو لیست که با هم تعامل ندارند اختصاص می دهد. "INTEGER" "ریستارهای بعدی موجود در ردیف %rdi، %rsi، %rdx، %rcx، %r8 و %r9" را می گیرد. SSE می گیرد %xmm0به%xmm7"اگر برای هر هشت باایت یک استدلال هیچ رکوردی در دسترس نباشد، کل استدلال در استیک منتقل می شود" و استدلال های حافظه "در استیک به ترتیب معکوس (از راست به چپ) فشار می شوند".
eight_args(a, b, c, d, e, f, g, h)در-O227 بایت است:
text 10: 48 01 fe addq %rdi, %rsi
13: 48 8d 04 0a leaq (%rdx,%rcx), %rax
17: 48 01 f0 addq %rsi, %rax
1a: 4c 01 c0 addq %r8, %rax
1d: 4c 01 c8 addq %r9, %rax
20: 48 03 44 24 08 addq 0x8(%rsp), %rax
25: 48 03 44 24 10 addq 0x10(%rsp), %rax
2a: c3 retqشش تا کادر و دو تا بار8(%rsp)و16(%rsp). شکل 3.3 از psABI "دلیل حافظه 8byte 0" را به 16(%rbp)چه وقت%rbpپایه فریم است، که 8(%rsp)قبل از هر فشار وارد شدنgساعت 8هhدر 16 سالگی
mixed(int i, double d, long long l, float f)دو لیست رو نشان ميده%ediو%rsi, اولین و دومین ثبت INTEGER.%xmm0و%xmm1، اولین و دومین ثبتات SSE.cvtsi2sd %edi, %xmm2و%xmm2یک کالا از خاکستری است که تابع قبل از خواندن آن می نویسد. یک تحلیلگر که به مقصد cvtsi2sdبه عنوان یک مطالعه یک استدلال سوم نقطه شناور اختراع می کند. رادار2 دقیقاً همین کار را کرد و گزارش دادmixedمثل(double arg1, double arg2, double arg3)درxmm0،xmm1،xmm2. .
by_value(struct pair p)یک ساختار 16 بایت به عنوان دو 8 بایت کامل در %rdiو%rsi، و به همان روش آن را بازمی گرداند:leaq 0x1(%rdi), %rax; leaq -0x1(%rsi), %rdx; retq.big_ret(long long seed)32 بایت را باز می گرداند که کلاس حافظه است و psABI می گوید "کارگر فضای را برای ارزش بازمی گردد فراهم می کند و آدرس این ذخیره را به %rdi می گذرد انگار که اولین استدلال است". seedبه سمت%rsi، و تابع با شروع می شودmovq %rdi, %raxچون "در بازگشت %rax آدرس که توسط تماس گیرنده در %rdi وارد شده است را در خود خواهد داشت".
منطقه قرمز دیگر امضای سیستم V است. psABI 3.2.2: "جای ۱۲۸ بایت فراتر از محل که توسط %rsp اشاره شده است، به عنوان محفوظ محسوب می شود و نباید توسط کنترل کننده های سیگنال یا قطع تغییر یابد".-O0،eight_args.pushq %rbp; movq %rsp, %rbpو بعد شش مغازه رو به-0x8(%rbp)از طریق-0x30(%rbp)بدون هیچsubqمغازه ها 48 بايت زیر شاخص ستک قرار دارن-O2ساختsum_varargs88 بایت را با subq $0x58, %rspو بعد قسمت ذخیره سازی را در -0x58(%rsp)تا-0x80(%rsp): 128 بايت در زیر اشاره ستک، تمام منطقه قرمز.-mno-red-zoneوleaf_addبه دست می آیدpushq %raxو یکaddq $0x8, %rspتا 8 بايت از مردم محلی رو بالای اشاره دار نگه داره
تماس های مختلف یک ثبت اضافه می کنند. "%al به عنوان استدلال پنهان برای مشخص کردن تعداد ثبت های ویکتور استفاده می شود" یک مرز بالا از 0 تا 8. call_varargsبا هم ميگيرهxorl %eax, %eaxدر-O2وmovb $0x0, %alدر-O0.sum_varargsاول ميخواد:testb %al, %al; jeهشتم پروازmovaps %xmmNدر زمان استفاده از هیچ رکورد متری ذخیره می شود.
مایکروسافت x64: موقعیت ها، یک فروشگاه سایه و هیچ منطقه قرمز
قوانین مایکروسافت موقعیت دارند. "دلگرهای کامل در ثبت RCX، RDX، R8 و R9 عبور می کنند.دلگرهای نقطه شناور در XMM0L، XMM1L، XMM2L و XMM3L عبور می کنند. " و "هر استدلال نقطه شناور و دوگانه دقت در چهار پارامتر اول در XMM0 - XMM3 عبور می شود. بسته به موقعیت. " همان mixedبه عنوان%ecx،%xmm1،%r8،%xmm3: slot 0 یک int است، بنابراین RCX؛ سلايت 1 دو برابر است، پسXMM1؛ سلايت 3 يه شناوريه، پسXMM3.XMM0وXMM2خالی بمون
تماس گیرنده باید فضای کافی را برای ذخیره کردن چهار پارامتر ثبت نام، حتی اگر تماس گیرنده این تعداد پارامتر را نداشته باشد، اختصاص دهد. صفحات آن را فروشگاه سایه یا آدرس خانه می نامند و چهار سلاٹ "فعالانه متعلق به تابع تماس" هستند. در ورود 0(%rsp)آدرس بازگشت است8(%rsp)به39(%rsp)این چهار خانه است و اولین بحث در این باره40(%rsp).eight_argsدر-O2میخواد0x28(%rsp)،0x30(%rsp)،0x38(%rsp)،0x40(%rsp): ۴۰، ۴۸، ۵۶، ۶۴
طرف تماس دهنده حساب حساب را نشان می دهد.call8در-O2.subq $0x48, %rspو بعد مغازه هاي 5، 6، 7، 8 در0x20(%rsp)به0x38(%rsp)قبل ازmovl $1, %ecxو دوستان. 72 بايت 32 برای فروشگاه سایه، 32 برای چهار استدلال ستک و 8 برای اینکه آدرس بازگشت در یک مرز 16 بايت است. call_varargsفقط استدلال ها رو ثبت ميکنه و هنوز هم ميفرسهsubq $0x28, %rsp: 32 تا براي فروشگاه سايه و 8 تا براي همبينيkeepsسه تا ثبت نام غیر متغیر (24 بایت) را فشار می دهد و سپس subq $0x20, %rsp، پس اونext32 بايت سايه خود را در زیر آدرس بازگشت پیدا می کند.
ساختارها قاعده ی خود را دنبال می کنند. "هر استدلال ای که در 8 بایت قرار ندارد، یا 1، 2، 4 یا 8 بایت نیست، باید با مرجع عبور شود". و "منظرات 16 بایت با مرجع عبور می شوند". by_valueبنابراین یک اشاره به یک کپی در %rdx، بعد از يه نشانگر نتيجه پنهان در%rcx: "کارگر باید حافظه را برای ارزش بازگشت اختصاص دهد و یک اشاره را به عنوان استدلال اول به آن منتقل کند. سپس استدلال های باقیمانده یک استدلال به سمت راست منتقل می شود". call_pairنسخه رو در 0x20(%rsp)باmovaps، گذرگاهleaq 0x20(%rsp), %rdx, با leaq 0x38(%rsp), %rcxو میخواد.bاز0x40(%rsp). .
هیچ منطقه قرمز وجود ندارد. "همه حافظه فراتر از آدرس فعلی RSP نامناسب محسوب می شود: OS یا یک debugger ممکن است این حافظه را در طول یک جلسه debug کاربر یا یک دستیار قطع تغییر نامناسب تغییر دهد. "-O0 leaf_add8 بايت از مردم محلی رو ميخواد و باشون ميگيرهpushq %raxدر ورود وpopq %rcxقبل ازretq، دو تا دستورات یک بايت به جای یکsubqو یکaddqصفحه استفاده از استیک صفحه ای را تعریف می کند که می تواند این کار را انجام دهد: "یک تابع ورق یک است که نیازی به ورود به جدول عملکرد ندارد. نمی تواند تغییرات را در هر گونه ثبت نام غیر متغیر، از جمله RSP انجام دهد".
"برای عملکردهای وارارگ یا نمونه های اولیه، هر مقدار نقطه شناور باید در register عمومی مربوطه دوبرابر شود".sum_varargsدر-O2فروشگاه ها%rdx،%r8،%r9به0x18(%rsp)،0x20(%rsp)،0x28(%rsp)بعد از يکpushq %rax, که در حال تعویض ورود 16, 24, 32: خانه های دوم، سوم و چهارم register پارامترها است.va_list.leaq 0x18(%rsp), %rax، خونه ي%rdx، اولین بحث نامعلوم
AAPCS64 و آنچه اپل تغییر می کند
AAPCS64 6.8.2 یک لیست از قوانین را با دو شمارش کننده انجام می دهد. C.9: یک استدلال ادغام "به بیت های کمتر قابل توجه در x [NGRN]" و افزایش NGRN کپی می شود. C.1 برای استدلال های نقطه شناور با NSRN همین کار را انجام می دهد. C.12: ترکیبی از حداکثر 8 - NGRNدو کلمه "در registers عمومی استفاده متوالی کپی شده است". C.13 تنظیم می کند "NGRN به 8" هنگامی که یک استدلال به استیک می رود، بنابراین هیچ چیز به registers پس از آن باز نمی گردد. eight_argsاستفادهx0بهx7و هرگز به دسته دست نزنهmixed.w0،d0،x1،s1.by_value.x0وx1داخل و خارج
6.9 می گوید نتیجه ای که در سوابق منتقل می شود "در همان سوابق بازگردانده می شود"، در غیر این صورت " آدرس بلوک حافظه به عنوان یک استدلال اضافی به تابع در x8 منتقل می شود". big_retنوشته شدهstr x0, [x8]،stur q0, [x8, #0x8]،str x9, [x8, #0x18]و هرگز ننوشتهx0.call_bigمجموعه هاmov x8, spوseedدر اين جا ماندx0، چون 6.9 اضافه می کند "هیچ الزامی برای calllee برای حفظ ارزش ذخیره شده در x8 وجود دارد" و x8یکی از پرونده های استدلال نیست.
6.1.1: "یک دعوت زیرروتین باید محتوای ثبتات r19-r29 و SP را حفظ کند". 6.4.5.2: در یک رابط عمومی "SP mod 16 = 0".-O0 leaf_addانتشاراتsub sp, sp, #0x10براي 8 بايت از مردم محلی که سيستم V از منطقه قرمز استفاده ميکنه
6.4.6 ثبت فریم را تعریف می کند: "یک ثبت فریم دو مقدار 64 بیت در استیک ... کمترین دو کلمه ای با عنوان دو کلمه به ثبت فریم قبلی اشاره می کند و بالاترین دو کلمه ای با عنوان دو کلمه باید حاوی مقدار عبور شده در LR در ورود به تابع فعلی باشد. " و "موقع ثبت فریم در یک فریم استیک مشخص نیست. " clang هر دو موقعیت را در این یک فایل نشان می دهد. keepsدر-O2در لینوکس رکورد را در پایین با stp x29, x30, [sp, #-0x30]!; mov x29, sp. همان عملکرد در -O0اون رو به سمت بالا ميذارهsub sp, sp, #0x20; stp x29, x30, [sp, #0x10]; add x29, sp, #0x10. .
یادداشت های arm64 اپل، ثبت و خط بندی را حفظ می کند و قاب، منطقه قرمز و تماس های مختلف را تغییر می دهد. "ریجستر اشاره کننده قاب (x29) همیشه باید به یک رکورد قاب معتبر مراجعه کند. برخی از عملکردها مانند عملکرد برگ یا تماس های دم ممکن است تصمیم بگیرند که واردات را در این لیست ایجاد نکنند".keepsپس انداز می کنهx22, x21, x20, x19اول و بالاترين رقم را مي گذارد:stp x29, x30, [sp, #0x20]; add x29, sp, #0x20. "پلتفرم ها از register x18 استفاده نکنند. " " منطقه قرمز ARM64 شامل 128 بايت درست زیر شاخص استاک است" و هنوز هم پخش می شودsub sp, sp, #0x10برای-O0ورق، بنابراین سازنده آن را به طور پیش فرض استفاده نمی کند. استدلال های Variadic "به تعداد مناسب از 8 بیت از اسکات های استیک" و "نسل va_list یک نام مستعار برای char*". call_varargsدر فروشگاه های اپل، 10، 20، 30 تا [sp]،[sp, #8]،[sp, #0x10]و فقط عبور می کنهw0؛ ساخت لینوکس از دست می رودw1،w2،w3و تماس های عقب با b extva. سیبsum_varargsمیخوادadd x8, sp, #0x10، اشاره کننده ی تماس گیرنده، به عنوانva_list؛ لینوکسsum_varargsپس انداز می کنهx1بهx7وq0بهq7به یک فریم 224 بایت تبدیل می شود و زمینه های ساختار را شروع می کند __gr_offsتا -56 و__vr_offsتا -128 با یکmov x8, #-0x38; movk x8, #0xff80, lsl #32. .
نماد ها هم فرق ميکنه._، پس لیست نشان میده_keepsو اولین تابع تحت برچسب خصوصی ظاهر می شود ltmp0.تحليل کننده ناميابي برچسب ها را از طریق جدول نماد تغییر ميده
یک پیشگویی را با دست سه بار رمزگذاری کنید
keeps(int n)تماس هاext(i)در حال انجام و نگه داشتنn،iوaccدر طول تماس، پس هر ABI باید ثبت نام ها را ذخیره کند. اولین بائتهای-O2براي هر هدف بسازيد
سیستم V، 4 بایت:
55.push r64با سجل در سه بیت پایین:50 + 5،%rbpعمق 8%rbpدر آفست ورود -8 ذخیره شده است.41 56.41REX باBمجموعه56.50 + 6. REX.B 6 تا 14 طول می کشد:pushq %r14در 1653.50 + 3.pushq %rbxدر -24.
سه فشار 24 بایت است. آدرس بازگشت 8 را اضافه می کند و 32 ضرب 16 است، بنابراین callq extداخل حلقه بدون خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خط خطsubq. وجود ندارهmovq %rsp, %rbp، پس اين ساختمون هيچ راهنماي قابي نداره%rbpو آن را به عنوان دفتر ثبت نام نگه داشته استacc(xorl %ebp, %ebp،addl %eax, %ebp. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5b 41 5e 5d c3. .
مایکروسافت x64، 7 بایت:
56.pushq %rsiدر -857.pushq %rdiدر -16.53.pushq %rbxدر -24. همه سه تا در اینجا غیر متغیر هستند وRDIوRSIاین پرونده ها در سیستم V ثبت شده بودند.48 83 ec 20: REX.W، کد آپ83 /5با 8 بت فوری، ModRMec.11 101 100.subq $0x20, %rspعمق 56
56 + آدرس برگشت 64 است، هموار شده 32 بايت فروشگاه سایه است کهextصفحه ایپلگ تنها اجازه می دهد "RSP، ثابت یا Lea RSP، ثابت [FPReg] را اضافه کنید، سپس یک سری از صفر یا بیشتر 8 بیت ثبت نام پاپ و بازگشت یا jmp" و بایت ها هستند.48 83 c4 20 5b 5f 5e c3. .
AArch64، 16 بايت در چهار کلمه، کوچک-endian:
a9bd7bfd.stpبا پیش انڈیکس. بایت 31:3010شماره 64 بت را انتخاب کنید، 2523 بت011برای ذخیره کردن، بیت 22 0 است. imm7 در بیت 21:15 است1111010, که -6 است ، به اندازه 8: -48 Rt2 در 14:10 30 است Rn در 9:5 31 (sp), Rt در 4:0 29 است.stp x29, x30, [sp, #-0x30]!: شاخص ستک 48 سقوط می کندx29به -48 وx30به -40f9000bf5.strبا یک تعویض 12 بت بدون امضا با مقیاس 8: imm12 در 21:10 2 است ، Rnsp، رتي 21 مي شهstr x21, [sp, #0x10]، بازداري دريافتي -32910003fd.addفوری: imm12 0 است، Rnsp، ردي 29mov x29, sp: نشانگر قاب در -48 است.a9024ff4.stpبا یک تعویض امضا شده: imm7 4 است، به 32 مقیاس شده Rt2 19 است، Rt 20 است.stp x20, x19, [sp, #0x20].x20در -16,x19-8
قاب 48 بايت است:x29در 0x30ساعت 8x21با 16 بايت از پر کردن با 24 بايتx20در 32 سالگیx19در 40. پایین ترین کلمه ی ثبت به ثبت قبلی اشاره دارد و کلمه ی بعدی LR را دارد، همانطور که 6.4.6 می طلبد. cmp w0, #0x1در میان ذخیره اول و دوم قرار دارد؛ برنامه نویس آن را به پیشگویی منتقل کرده و تحلیلگر یک مقایسه یا دستورالعمل ریاضی بین عملیات های دسته را تحمل می کند.
جمع کننده دو بار همان حقایق را نوشت
یک پیشگویی تجزیه یک مشتق است. سازنده یک دوم را برای unwinder منتشر می کند، و هر دو باید موافق باشند.
در ویندوز دومین مشتق این است.pdataو.xdata. ساختش رو-O2بدون هدف-fno-asynchronous-unwind-tablesوllvm-objdump -hنمایش ها.xdataبا متری 0x34 با متری.pdataاز 0x48 بایت. 0x48 برابر 72 است، ششRUNTIME_FUNCTIONنوشته های 12 بایت با 3 IMAGE_REL_AMD64_ADDR32NBهر يک از 6 نفرsum_varargs،keeps،call8،call_varargs،call_pairوcall_big. شش تابع دیگر برگ ها هستند و صفحه مدیریت استثناء می گوید "اگر جستجو یک ورودی از جدول عملکرد را پیدا نکند، فرض می شود کد بخشی از یک تابع برگ است و RSP مستقیماً به اشاره کننده بازگشت مراجعه می کند".
..xdataبائتهای برای keeps.01 07 04 00 07 32 03 30 02 70 01 60.UNWIND_INFOبا نسخه در 3 بیت و پرچم در 5 بیت شروع می شود: نسخه 1، هیچ پرچم نیست. اندازه OfProlog 7 است، CountOfCodes 4 است، FrameRegister و FrameOffset 0 هستند. هر یک UNWIND_CODEیک تعویض در پیشگام و یک بایت از کد و اطلاعات.07 32: در آفست 7، آپ 2 است UWOP_ALLOC_SMALL، اطلاعات 3 يعني3 * 8 + 8 = 32بايت ها03 30: op 0 استUWOP_PUSH_NONVOL، ثبت شماره 3rbx.02 70.rdi.01 60.rsi. کد ها به ترتیب اجرا برعکس ذخیره می شوند و به همان سه فشار و 32 بیت اختصاص داده می شوند که باایت ها هستند 56 57 53 48 83 ec 20.sum_varargsورود این است01 01 01 00 01 02 00 00: یک پیشگویی یک بایت با یک کدUWOP_ALLOC_SMALLاز 8 بايت. اين همونطوريه که اوني که ميخواد ببينهpushq %rax: یک تخصیص، چون%raxو هيچ چيز نجات نميده
در لینوکس، فرات دوم این است.eh_frame, که در psABI 4.2.4 تعریف شده و در بخش 6.4 DWARF 5 کدگذاری شده است. llvm-dwarfdump --eh-frameدر روی شی قابل انتقال یک FDE در هر تابع چاپ می شود و حل می کند R_X86_64_PC32نقل مکان ها، پس دامنه ها قابل استفاده هستند.keeps:
text DW_CFA_def_cfa_offset: +16
DW_CFA_def_cfa_offset: +24
DW_CFA_def_cfa_offset: +32
DW_CFA_offset: RBX -32
DW_CFA_offset: R14 -24
DW_CFA_offset: RBP -16CFA نشان دهنده ی سکه قبل از تماس است، 8 بالاتر از نشان دهنده ی سکه ورود، بنابراین RBP -16این تعویض وارداتی است -8، R14 -24-16.RBX -32-24, و عمیق ترین CFA تعویض 32 است که 24 بایت فریم به علاوه آدرس بازگشت.keepsمیگهDW_CFA_def_cfa: W29 +48باW29 -48،W30 -40،W21 -32،W20 -16،W19 -8در آنجا CFA خود شاخص ستک ورود است، بنابراین تعویضات تعویضات فریم بدون تبدیل هستند و CFA از x29تا وقتي که ضبط قاب زنده باشهeh_frame_cross_check()این مقایسه برای تمام 12 FDE هر دو شی را انجام می دهد. یک ورودی نیاز به مراقبت: call8در سیستم V دو استدلال خارج شده را در وسط بدن فشار می دهد، بنابراین عمیق ترین تعویض CFA آن 32 است در حالی که فریم پیشگویی آن 8 است، و چک با عمیق ترین شاخص ستک که بدن به آن می رسد، 24، به علاوه 8 مقایسه می کند.
چه اسمي به اين ابزار داده شده
هر ابزار در این زمینه دارای ساختار داده ای برای کنوانسیون تماس و یک گذرنامه است که یکی را به یک تابع اختصاص می دهد. نامها متفاوت هستند و شکافها متفاوت هستند. ابزارهای بسته از اسناد آنها توصیف می شوند؛ ابزار باز در وسایل اجرا می شوند و تولید آنها در کنار اشیاء ضبط می شود.
Ghidra 12.1.4 (Apache-2.0).قوانین در فایل های مشخصات کامپایلر زنده است..cspec، کنار زبان "سنگ"x86-64-gcc.cspecاعلام می کنه<default_proto>نامش__stdcall, "استفاده از سیستم V برنامه های دوگانه رابط AMD64 معماری پردازنده مکمل آوریل 2016"، با <pentry>لیست ها برای XMM0_QaبهXMM7_QaوRDI, RSI, RDX, RCX, R8, R9، یک ورودی در آفس 8 ، یک join_dual_classقانون برای انواع تا 16 بایت، خروجی XMM0_Qa, XMM1_Qa, RAX, RDXوhidden_returnبرای بقیهx86-64-win.cspecاعلامیه__fastcallبا چهارتا<group>عناصر که همبستگی دارندXMM0_QaباRCX،XMM1_QaباRDX، و غیره، که قانون موقعیت است، یک ورودی دسته در تعویض 40convert_to_ptrبرای استروک های ۳، ۵، ۶ یا ۷ بایت با این نکته که "تنها استروک های اندازه ۸،۱۶،۳۲،۶۴ بیت را می توان برای ثبت بسته بندی کرد"unaffectedفهرست بندیRBX RBP RDI RSI RSP R12بهR15وXMM6بهXMM15، و یکlocalrangeاز دسته 8 تا 39 که فروشگاه سايهAARCH64.cspecاعلامیه__cdeclکه اولین نوشته اش اینهx8باstorage="hiddenret"، پسq0بهq7وx0بهx7،convert_to_ptrبرای structs 17 byte یا بیشتر وkilledbycallاز جملهx8با نظر "رجستر محل نتایج غیر مستقیم، که در لیست پنتری منعکس نمی شود". مرحله نهایی تجزیه کننده "پروتایپ عملکرد ایجاد کنید" نامیده می شود؛ تحلیلگران "ID کنوانسیون تماس" و "ID پارامتر تجزیه کننده" هستند؛ گزینه برنامه "تقييم نمونه" مدل پیش فرض را انتخاب می کند.
IDA Pro and IDA Free (Hex-Rays, commercial; current release 9.4, build 9.4.260714).نوع تابع یک بیانیه C است که از طریق SetType تنظیم شده است و "IDA از اطلاعات نوع برای اظهار نظر در مورد تجزیه با اطلاعات در مورد استدلال های عملکرد استفاده می کند". مکان هایی که هیچ کنوانسیون استاندارد تولید نمی کند در کنوانسیون خود IDA نوشته شده است: int __usercall func@<ebx>(int x, int y@<esi>)نتیجه رو به EBXوyدرESIو@<^12.4>نام محل یک استیک با تعویض و اندازه. __userpurgeهمونطور که با پاک کردن دسته کالي هم هست__spoilsبرای مجموعه ی کلوپ شده،__hidden،__return_ptrو__struct_ptrبرای استدلال های ضمنی این درس به دست بازیابی می شود. عمل "Decompile as call" از طریق decompiler یک __usercallنمونه ای برای یک دستورالعمل. IDA Free فقط از x86 و x86-64 پشتیبانی می کند.
Binary Ninja 6.0 "Krypton" (Vector 35, commercial, with a Free edition that decompiles x86, x86_64, ARMv7, and AArch64).APlatform"معلومات مربوط به محیط اجرا دوگانه، به طور عمده کنوانسیون های تماس استفاده شده، سیستم عامل و معماری را شامل می شود" و لیست شامل linux-x86_64،windows-x86_64،linux-aarch64وmac-aarch64، هرکدوم با یکdefault_calling_convention.CallingConvention.int_arg_regs،float_arg_regs،callee_saved_regs،caller_saved_regs،int_return_reg،high_int_return_reg،float_return_reg، و دو پرچم که تفاوت ها را در این درس به طور مستقیم رمزگذاری می کنند:arg_regs_share_index"در صورت درست، استدلال Nth، نقطه Nth از لیست های ثبت عدد کامل و فلوت را بدون توجه به نوع آن مصرف می کند" وstack_reserved_for_arg_regs, " فضای سایه / خانه مورد استفاده در کنوانسیون تماس ویندوز x64 "eligible_for_heuristics،required_arg_regsوrequired_clobbered_regsانواع پلتفرم ها در زیر عنوان C هستندtypes/platform/، يک نفر به هر نام پلتفرم
radare2 6.2.4 (LGPL-3.0, run here). afclکنوانسیون های شناخته شده پلاگین معماری را لیست می کند: amd64 amd64syscall dlang golang golang_abi0 ms p9 reg swiftبرای x86-64 و arm64 dlang golang p9 reg swiftبرای AArch64afcگزارش کنوانسیون عملکرد فعلیafcrچاپcc.amd64.arg0: rdiاز طریقarg5: r9وret0: rax، و پروفایل ها فایل های SDB به نامcc-ARCH-BITS.sdb. رادار2 انتخاب شدamd64برای شی ELF و msبرای شی COFF که تقسیم صحیح است. afvفهرست استدلال ها و متغیرها و afsدر لينوکس-O2موضوعafvهفت دليل براي اين پيدا کردمeight_argsو سقوط کردrcx؛ در مورد " ویندوز " که پیدا کردrcx, rdx, r8و چهار سوراخ جمع و بسته و سقوط کردr9هر دو پرونده گمشده فقط داخل یکlea. . درmixedگزارش دادdouble arg1 @ xmm0, arg2 @ xmm1, arg3 @ xmm2در لینوکس و در ویندوز هیچ بحثی نیست. در AArch64 پیدا شدx0بهx7برایeight_argsو برایbig_retاون فهرست شدهx0وdouble arg2 @ d1جایی که تابع میگهx8و ثابت رو وارد ميکنهq1. هرafsامضا با شروع میشهvoid، چون نوع بازگشت نتیجه گیری نشده است.-O0،که هرجنگي به قاب ذخیره ميشهafvتمام هشت استدلال را پیدا کردمeight_argsباrbp+0x10وrbp+0x18برای جفت سنگ
rizin 0.9.1 (LGPL-3.0, run here) and Cutter 2.5.0. afclلیست هاamd64 amd64syscall ms reg swift.afcبرگشتamd64برای شی COFF، بنابراین پروفایل مایکروسافت وجود دارد و از قالب انتخاب نشده است. afiهفت دلیل برایeight_argsدر لینوکس، دوباره بدونrcx، و در ویندوزr8, rcx, rdxبا سه سوراخ دسته ای بدونr9و بدون سوراخ در0x40.afvوجود نداره، فرمان فهرست اينهafvlکتر، قسمت جلو گرافیک روی رزین است
angr 10.0.3 (BSD-2, run here). CFGFastبعدشCompleteCallingConventions(recover_variables=True)مجموعه هاfunction.calling_conventionبهSimCCSystemVAMD64،SimCCMicrosoftAMD64، یاSimCCAArch64, با فرمت دوگانه و function.prototypeبه دستخطي که تمام هشت استدلال را از دست دادeight_argsدر هر سه هدف، اشاره پنهان ازbig_retدر x86-64 به عنوان(BOT*, long long) -> BOT*, ساختار مرجع بالا پنجره هاby_valueمثل(BOT*, BOT*) -> BOT*, و سیستم V متغیرsum_varargsمثل(long long, ...). شکاف هاي آن با رادار2 متفاوت هستند:mixedبرگشتيم و(long long, long long, double, float)در سیستم V و AArch64، ثبت راست در ترتیب اشتباه، زیرا لیست اعداد کامل قبل از لیست شناور چاپ می شود.big_retبرگشتيم و(long long) -> double، پس اونx8کنوانسیون از دست داده شد و به همین دلیل فروشگاه های ویکتور خوانده شد و AArch64 sum_varargsبا 16 پارامتر برگشتم، کل منطقه ذخیره شده را در نظر گرفته شده.
Others.Hopper 6.6.0 یک جداکننده و جداکننده تجاری برای macOS و لینوکس است؛ مدیریت کنوانسیون آن برای این درس اجرا یا مستند نشده است. lldb 1703 و gdb نشان می دهد که فریم زنده با frame infoوregister read, که درسی 42 دید پویا از همان تعویض است. کمپایلر اکسپلورر سه لیست را کنار هم از منبع نشان می دهد، که سریع ترین راه برای تأیید یک قانون است قبل از اینکه به دنبال آن در بائته ها باشید.
| Concept | Ghidra | IDA | Binary Ninja | radare2 / rizin | angr | this lesson |
|---|---|---|---|---|---|---|
| The convention object | prototype in a .cspec | calling convention keyword in the function type | CallingConvention on a Platform | afc name, cc-ARCH-BITS.sdb | SimCC subclass | expected_locations(abi, name) |
| Default per target | <default_proto> per cspec | compiler setting | Platform.default_calling_convention | afc=, anal.cc | by format | describe_object() |
| Argument registers | <pentry> list, <group> for positional | @<reg> in __usercall | int_arg_regs, float_arg_regs, arg_regs_share_index | cc.NAME.argN | ARG_REGS, FP_ARG_REGS | INT_ARG_REGS, FLOAT_ARG_REGS |
| Shadow store | localrange stack 8 to 39 | implicit | stack_reserved_for_arg_regs | cc.ms.argn=stack | STACKARG_SP_DIFF | STACK_ARG_BASE[WIN64] = 40 |
| Hidden result pointer | hidden_return, storage="hiddenret" | __return_ptr, __hidden | return type too large for int_return_reg | not modelled | BOT* first argument | HIDDEN_RETURN_REG |
| Callee-saved | <unaffected> | __spoils lists the opposite | callee_saved_regs | profile | CALLEE_CLEANUP and arch | CALLEE_SAVED |
| Assigning one to a function | "Call Convention ID" analyzer, "Establish Function's Prototype" | user or type library | heuristic detection with required_arg_regs | afc, afva, aaft | CallingConventionAnalysis | read-before-write plus the rulebook |
آن را بسازید
نمایش نمایش را اجرا کن:
bashcd phases/13-tools-and-protocols/38-calling-conventions-and-stack-frames
python3 code/main.pyمحصول یک گزارش JSON است. برای هر یک از هفت شی نامگذاری شده است، فرمت، ماشین و ABI، و برای هر یک از دوازده تابع آن به بایت های پیشگام، ثبت ذخیره شده با تعویض ورود، اندازه فریم، نشان دهنده فریم، ثبت پارامتر، تعویضات استدلال سقف، ورودی، ثبت بازگشت یا نشان دهنده پنهان، عمق تماس و ثبت و ذخیره های خارج از تماس گیران داده شده است. هر تابع با چک های خود به پایان می رسد: قاعده، ارزش انتظار شده از امضا، ارزش مشاهده شده از بایت ها و اینکه آیا آنها موافق هستند. گزارش با دو چک عبور و ضبط ابزار به پایان می رسد. در ۸۴ تحلیل عملکرد، ۴۸۹ چک اجرا شده و ۴۸۹ موافق هستند.
شکل انتظار می رود:
json{
"objects": {
"convention-x86_64-windows-O2": {
"format": "COFF", "machine": "AMD64", "abi": "Microsoft x64", "checks": "73/73 agree",
"functions": {
"keeps": {
"prologue": ["56 pushq %rsi", "57 pushq %rdi", "53 pushq %rbx", "48 83 ec 20 subq $0x20, %rsp"],
"frameBytes": 56,
"savedRegisters": [{"register": "rsi", "entryOffset": -8}, {"register": "rdi", "entryOffset": -16}, {"register": "rbx", "entryOffset": -24}],
"parameterRegisters": ["rcx"],
"returnRegisters": ["rax"],
"calls": [{"callee": "ext", "depth": 56}],
"checks": [{"rule": "Microsoft x64: the caller must always allocate ...", "expected": "at least 32 bytes ...", "observed": [56], "agree": true}, "..."]
}
}
}
},
"sehCrossCheck": ["..."],
"ehFrameCrossCheck": {"...": "..."}
}بخونcode/main.pyدر این ترتیب:
describe_object()در این حالت، این ورودی در حالت "مجموعه ای" قرار دارد.parse_listing()تقسیم می کنهllvm-objdump -d -rمتن را به تابع ها تقسیم می کند، هدف نقل مکان هر تماس و پرش را حفظ می کند و نظرات را با نشانگر ترکیب صحیح حذف می کند:#برای AT&T،//و;برای AArch64، جایی که#به طور فوری معرفی می کند.effect_x86()وeffect_arm()تبدیل یک دستورالعمل به خواندن، خواندن آدرس، نوشتن، بارگذاری، فروشگاه ها و یک دلتا اشاره کننده استیک. آخرین اپراند AT&T مقصد است؛ اولین اپراند AArch64 مقصد است به جز در فروشگاه ها، مقایسه ها و شاخه ها.leaيه آدرس رو ميخواد و هيچ چيز رو نمي باردmov،cvtsi2sd،setcc، و اصطلاح صفرxor r, rفقط یک نوشتن است. یک تماس کل مجموعه متغیر را می نویسد. یک فروشگاه پیش از انڈیکس حرکت می کند.spقبل از دسترسی و بار بعد از شاخصش بعد از آن حرکت می کند.analyze_function()يه بار بدن رو به سمت اول مي گيرهretیا پرتاب دم. آن را ردیابی عمق اشاره ستک زیر مقدار ورود آن، بنابراین یک حافظه آپرندdisp(%rsp)در حال تعویض ورود استdisp - depthوdisp(%rbp)در حال حاضرframe_pointer + disp. آن ثبت ثبت دسته حجت است که قبل از نوشتن آن ها خوانده می شود، بارگذاری در یا بالاتر از اولین استیک حجت تعویض ABI، ذخیره از حجت ثبت در قاب، دسترسی زیر استیک فعلی اشاره، و عمق در هر تماس._return_registers()در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حال حاضر، در حالraxزنده درbig_retدر Microsoft x64، جایی کهmovq %rcx, %raxاز بعد از آن فروشگاه ها از طریق(%rax). .expected_locations()در این روش، سه کتاب قاعده را به یک امضا C اعمال می کند: دو لیست سیستم V با کلاس های هشت بایت، نقاط موقعیت مایکروسافت با structs by-reference و AAPCS64 counters باx8برای نتایج بالاتر از 16 بایت.run_checks()این دو را مقایسه می کند و قوانین چارچوب را اضافه می کند: ثبت نام های ذخیره شده توسط تماس باید ذخیره شوند.(rsp + 8) % 16 == 0یاsp % 16 == 0در هر تماس، 32 بایت سایه در هر تماس مایکروسافت، دسترسی زیر شاخص ستاک در Microsoft و AAPCS64 و حداکثر 128 بایت در سیستم V، و یک اپیلوگ که پیشگام را با شاخص ستاک به مقدار ورودی خود منعکس می کند.seh_cross_check()وeh_frame_cross_check()اطلاعات باز کردن اشیاء ساخته شده بدون آن را بخوانید-fno-asynchronous-unwind-tablesو آن را با تحلیل مقدم مقایسه کنید.
سه فرمان ديگه وجود دارهpython3 code/main.py analyze convention-x86_64-windows-O2 keepsیک تابع را چاپ می کند. python3 code/main.py object FILEو حکم سرنخ ها رو چاپ ميکنهpython3 code/main.py sehچاپ شده رو شفر می کنهUNWIND_INFOاز هر تابع که یک تابع داشته باشد.
ازش استفاده کن
از اين ترتيب براي يه شيوه جديد که ساختي استفاده کن
- فرار کن
python3 code/main.py object FILE.oو ABI را که نامش را می دهد بنویسید. اگر سر و فرمان ساخت شما با هم مخالف باشند، متوقف شوید؛ یکی از آنها اشتباه است. - دستگیرش کن
llvm-objdump -d -r FILE.oقبل از هر چیز دیگری بایت های پیشگام و ثبت های ذخیره شده را بخوانید و اندازه فریم را با فشارها وsub. . - یک ثبت که امضا توضیح نمی دهد یک اشاره پنهان، یک نشانگر متغیر، یا یک ثبت سکریچ است که تحلیلگر برای یک استدلال اشتباه گرفته است. آخرین مورد یک خطا در جدول اثرات است. آن را با یک قانون عمومی برای این دستورالعمل حل کنید.
- چک هایی که با هم موافق نیستند را بخوانید هر کدام قانون را که بر آن است، نام می دهند، بنابراین اولین چیزی که باید بررسی کنید، قانون است، سپس بایت ها، سپس تحلیلگر.
- وقتی که این شی داده های باز شده را داشته باشد، چک متقابل را اجرا کنید. دو مشتق که با هم موافقند، قوی ترین شواهد این درس تولید می کنند.
- وقتی ابزار دیگری نصب شده است، محصول آن را با دستور دقیق ضبط کنید و مقایسه کنید. جایی که شما موافق هستید شما سه مشتق دارید. جایی که متفاوت است شما یک فهرست خاص و یک دستورالعمل خاص برای نگاه کردن دارید، و این یک یافته برای درس 35 است.
آزمایشگاه تعاملی
لابراتوار A: یک دستورالعمل، سه اثر
ازcodeدایرکتوری، پیتون باز:
bashcd phases/13-tools-and-protocols/38-calling-conventions-and-stack-frames/code
python3 -qراه رفتن:
pythonfrom main import *
effect(Instruction(0, "48 8d 04 0a", "leaq", "(%rdx,%rcx), %rax"), SYSV)
effect(Instruction(0, "f2 0f 2a d7", "cvtsi2sd", "%edi, %xmm2"), SYSV)
effect(Instruction(0, "a9bd7bfd", "stp", "x29, x30, [sp, #-0x30]!"), AAPCS64)اطلاعات و اطلاعات مربوط به هر تماس را بنویسید و بعد تغییر کنید[sp, #-0x30]!به[sp], #0x30باldpو نگاه کنيد که دلتا از کجا حرکت ميکنهsp_deltaبهpost_sp_delta. .
آزمایشگاه B: قاب نگهبان
pythoninfo, listing = load_fixture("convention-aarch64-linux-O2")
keeps = analyze_function("keeps", listing["keeps"], info.abi)
keeps.saved
keeps.frame_pointer
[c.to_dict() for c in frame_cells(keeps)]با رمزگشایی دست بالا مقایسه کنید و بعدش بارگذاری کنیدconvention-arm64-macos-O2و سه خط مشابه را اجرا کنید، رکورد به -16 حرکت می کند و چهار رکورد زیر آن قرار می گیرد.convention-x86_64-linux-O2-fpو بخونsavedبرایkeeps: نشانگر قاب برگشت و همینطور یکpushq %raxکه تنها کارش اينه که کارش رو انجام بده(rsp + 8)ضرب 16 در تماس
آزمایشگاه C: خواندن قبل از نوشتن در مخلوط
pythoninfo, listing = load_fixture("convention-x86_64-linux-O2")
mixed = analyze_function("mixed", listing["mixed"], info.abi)
mixed.param_registers
mixed.return_registers
expected_locations(SYSV, "mixed")["parameters"]
expected_locations(WIN64, "mixed")["parameters"]لیست سیستم V اینهrdi, xmm0, rsi, xmm1و لیست مایکروسافتrcx, xmm1, r8, xmm3حالا آبجیکت ویندوز رو بارگذاری کن و سه خط اول رو دوباره اجرا کن. بعد رادار2 رو برای آبجیکت لینوکس باز کن و پیدا کن[afv mixed]: سه بار دو برابر. دستور رو پيدا کن که سوم رو توضیح بده.
آزمایشگاه D: نظر دوم دستگاه کشنده
pythonfor row in seh_cross_check():
print(row["function"], row["sizeOfProlog"], row["unwindPushes"], row["unwindAllocBytes"], row["agree"])
for row in eh_frame_cross_check("convention-x86_64-linux-O2-eh"):
print(row["function"], row["cfiSaved"], row["cfiMaxOffset"], row["deepestStack"], row["agree"])پیدا کنpushq %raxازsum_varargsدر جدول SEH و توضیح دهید که چرا کد unwind آن را به عنوان یک تخصیص ثبت می کند.call8در.eh_frameميز رو رو بيان کنين
آزمایشگاه تمرین
يه هدف چهارم و يه قانون چهارم اضافه کن
الزامات:
- جمع آوری کنید
convention.cبا-target x86_64-apple-macos -O2و فهرستش رو ضبط کنdescribe_object()براي خواندن " ماچ او "cputype0x01000007 و نقشه آن را به سیستم V psABI که اپل در x86-64 دنبال می کند، با_علامت پیشگویی - چک کنید که هر تابع با چک های سیستم V مطابقت دارد. تنها تفاوت ای که در پیشگام ها پیدا می کنید را ثبت کنید: داروین نشانگر فریم را در هر سطح بهینه سازی نگه می دارد.
- اضافه کنید
-fstack-protector-strongساخت لنوکس x86-64 رو گسترش بده تا کاناری از%fs:0x28و فروشگاه زیر مردم محلی به عنوان یک ثبت شده استcanaryسلول و مقایسه قبلretمثل چک که حمايت از پيالوگ ميکنه - يه آزمون اضافه کن که وقتي که يه فروشگاه کانري به عنوان بحثي که ميخوره شکست خورده باشه
- چارچوب رو بنویس
with_canaryقبل از اينکه اين تحليلگر رو اجرا کني، مدل رو دستي به دست بگير و نقشه رو کنار تست نگه دار
موفقیت به معنیpython3 code/main.pyگزارشات این شی جدید با هر چک موافقت می کند و سلول های فریم تابع محافظت شده، بین مردم محلی و سوابق ذخیره شده، کاناری را نشان می دهد.
درس هنرپیشه
این درس شاملoutputs/skill-calling-conventions-and-stack-frames.mdاز آن برای تبدیل یک شی که شما ساخته اید، لیستش و امضا های C به مکان های پارامتر، یک طرح فریم، یک ثبت بازگشت و چک هر نتیجه گیری با قاعده ای که بر آن است و با داده های بازخوردن سازنده.cvtsi2sdیاxor r, rاما در مورد هدف ها به نظر می رسد و با اختلاف اول به پایان می رسد.
بررسی کنید
نمایش و مجموعه تعیین کننده را اجرا کنید:
bashcd phases/13-tools-and-protocols/38-calling-conventions-and-stack-frames
python3 code/main.py
python3 -m unittest discover -s code/tests -vبررسی باید ثابت کند:
- سرپرست های ELF، COFF و Mach-O هفت شی نام سیستم V، مایکروسافت x64, AAPCS64 و Apple arm64
- جدول نماد هر شی، فهرست 12 تابع مشابه را با Mach-O
_پیشگویی وltmp0برچسب حل شده - فهرست پارسر نگه می دارد
extبه عنوان هدف تماس و نگه داشتن AArch64 فوری مانند#-0x30سالم leaq (%rdx,%rcx), %raxدو دفتر ثبت آدرس رو میخواد و هیچ چیزی رو نمی باردxorl %eax, %eaxوcvtsi2sdفقط برای نوشتن هستند، پیش از این شاخص شده اندstpحرکت می کنهspقبل از فروشگاه و بعد از فهرستldpبعد از بارkeepsدر-O2.55 41 56 53در سیستم V با یک قاب 24 بایت و هیچ شاخص قاب،56 57 53 48 83 ec 20در مایکروسافت x64 با قاب 56 بایت وa9bd7bfdاولين بار در AArch64 با رکورد -48- ساخت اپل رکورد را در -16 بالاتر از چهار رکورد ذخیره شده قرار می دهد
- هر تابع يه اشاره دار قاب داره
-O0در لینوکس و هیچ کدام در-O2و-fno-omit-frame-pointerو با فشار تعادل آن را به عقب می آورد - .
-O0برگ 8 بایت از منطقه قرمز تحت سیستم V استفاده می کندpushq %raxدر Microsoft x64 وsub sp, sp, #0x10در این زمینه، AAPCS64:-mno-red-zoneاستفاده از منطقه قرمز را حذف می کند - هر اپيلوگ پيشگامش رو بازتاب ميده و نشانگر دسته باز هم در ورودي
eight_argsشش سجل و سلايت 8 و 16 را می خواند، چهار سجل و سلايت 40 تا 64 را می خواند، یاx0بهx7، در هر دو سطح بهینه سازیmixed.rdi, xmm0, rsi, xmm1تحت سیستم V وrcx, xmm1, r8, xmm3در Microsoft x64 باxmm0در نتیجه هر دو- ساختار 16 بایت در دو ثبت در سیستم V و AAPCS64 و با توجه به یک اشاره پنهان در Microsoft x64 حرکت می کند
- ساختار 32 بايت از طریق
rdi،rcx، یاx8 - وآره، اون کلي مختلف ميگه
%al، خانه هاrdx, r8, r9در 16، 24، 32، نجات می دهدx1بهx7وq0بهq7، یا نشان دهنده ی دسته تماس گیرنده را در اپل می خواند - تماس گیرندگان به صورت انتظارات ثبت نام ها را تنظیم می کنند، 7 و 8 را به 0 و 8 یا 5 تا 8 را به 32 تا 56 ذخیره می کنند، صفر
%alبرای تماس متغیر، و ارسال آدرس بفر نتیجه درrdi،rcx، یاx8 - همه 489 چک با قوانینشون موافقند
- شش
UNWIND_INFOنوشته ها با شروع به کار مطابقت دارند و برگ ها هیچ کدام ندارند - 24 FDE با تعادل ذخیره شده از ثبت و عمیق ترین شاخص استاک مطابقت دارد
- ابزار رادار2 رو ضبط ميکنه
amd64وms، رزينamd64در مورد کاوف، گمشدهrcx، سه دوگانه و نمونه اولیه آنگر - داده های ارقام در ماژول سایت برابر با خروجی تحلیلگر است
روش های شکست تولید
| Failure | What the weak tool reports | What the analysis must prove |
|---|---|---|
| COFF object read as System V | rdi and rsi as arguments that the function never reads | The header says 0x8664; the convention is Microsoft x64 |
Register read only inside a lea | Seven arguments for an eight-argument function | Base and index registers are reads |
cvtsi2sd destination counted as a read | A third double argument in xmm2 | The first write to xmm2 is a write; mixed has two SSE arguments |
| Positional slots read as sequences | xmm0 named as the double argument on Windows | Slot 1 is XMM1, slot 3 is XMM3 |
push rbp taken as a frame pointer | A frame pointer in an -O2 function that uses rbp as an accumulator | Only mov %rsp, %rbp after the push creates one |
| Red zone measured from the entry stack pointer | 216 bytes "below the stack pointer" | 128 bytes below the current stack pointer after an 88-byte sub |
| Shadow store treated as locals | Stack arguments at 8 to 32 | Microsoft stack arguments start at 40 |
lea treated as a load | A stack argument at 0x60(%rsp) in a variadic callee | lea computes overflow_arg_area; it loads nothing |
| Hidden pointer read as a normal argument | big_ret(void *, long long) | The pointer is stored through and copied to rax, rax, or stays in x8 |
| Deepest CFA compared with the prologue frame | A mismatch on a caller that pushes outgoing arguments | Compare with the deepest stack pointer the body reaches |
| Convention asserted from the ISA | amd64 for a COFF object | The format picks the rulebook, then the ISA picks the registers |
| Prototype trusted from one tool | Three doubles, or sixteen variadic parameters | The source signature or a second derivation must agree |
قاعده عملیاتی
پیش از اولین دستورالعمل، سر را بخوانید و نام کتاب قوانین را نام دهید. هر سجل ذخیره شده و هر استدلال را در یک تعویض از اشاره کننده ستاک ورود قرار دهید و آن را با قانون که آن را در آنجا قرار داد و با داده های غیر قابل پیشگیری که سازنده برای همان چارچوب نوشت، بررسی کنید. نمونه اولیه یک ابزار را به عنوان ادعای تا زمانی که بایت ها یا منبع آن را تأیید کند، رفتار کنید.
خواندن بیشتر
- System V Application Binary Interface, AMD64 Architecture Processor Supplement, Version 1.0 (sections 3.2.1 to 3.2.3, 4.2.4)
- Microsoft x64 calling convention
- Microsoft x64 stack usage
- Microsoft x64 prolog and epilog
- Microsoft x64 exception handling: RUNTIME_FUNCTION, UNWIND_INFO, UNWIND_CODE
- Arm Procedure Call Standard for the Arm 64-bit Architecture (AAPCS64), release 2025Q4
- Apple: Writing ARM64 code for Apple platforms
- DWARF Debugging Information Format Version 5, section 6.4 Call Frame Information
- Clang driver frame-pointer defaults,
useFramePointerForTargetByDefaultinCommonArgs.cpp - Clang command line reference:
-fomit-frame-pointer,-momit-leaf-frame-pointer - Fedora 38 change: frame pointers by default
- Ubuntu 24.04: performance engineering with frame pointers by default
- Ghidra compiler specification:
x86-64-gcc.cspec - Ghidra compiler specification:
x86-64-win.cspec - Ghidra compiler specification:
AARCH64.cspec - Hex-Rays: SetType and the
__usercallconvention - Hex-Rays: Decompile as call
- Binary Ninja API 6.0:
callingconventionmodule - Binary Ninja API 6.0:
platformmodule - Binary Ninja user documentation: platform types
- The Official Radare2 Book: calling conventions
- The Official Radare2 Book: code analysis
- angr documentation: decompiler analysis passes, including calling convention recovery
- radare2 6.2.4 release
- rizin 0.9.1 release
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.