Updated: 2021-01-BambooFox/better-than-asm

This commit is contained in:
Hadi Mottale 2025-07-23 11:25:16 +03:30
parent e96f201575
commit 28685bdd02
1 changed files with 50 additions and 10 deletions

View File

@ -119,6 +119,9 @@ flag: Hi
😠😡😠😡😠😡 You are not the chosen one! 😡😠😡😠😡😠
```
نکته: پسوند .out معمولاً به معنای یک فایل خروجی (output file) است و به طور خاص در سیستم‌های یونیکس‌مانند (مانند لینوکس) برای نام‌گذاری فایل‌های اجرایی (executables) که توسط کامپایلرها (مانند GCC) تولید می‌شوند، کاربرد دارد. به عنوان مثال، وقتی یک فایل سورس کد C را بدون تعیین نام خروجی کامپایل می‌کنید، کامپایلر به صورت پیش‌فرض یک فایل اجرایی با نام a.out ایجاد می‌کند. این پسوند همچنین می‌تواند برای فایل‌های خروجی عمومی دیگر (مانند لاگ‌ها یا نتایج پردازش) استفاده شود، اما رایج‌ترین کاربرد آن در CTFها و محیط‌های توسعه، اشاره به یک باینری کامپایل شده است که اغلب برای تحلیل و مهندسی معکوس مورد استفاده قرار می‌گیرد.
## گام چهارم: تحلیل باینری
### ابزار Cutter
@ -690,6 +693,7 @@ label_0:
همانطور که می‌بینید، این (کد) با خروجی برنامه هنگام اجرا مطابقت دارد. برنامه یک رشته (حداکثر 64 کاراکتر) را می‌خواند؛ اگر طول آن با طول رشته‌ای که سپس برنامه بررسی می‌کند یکسان باشد و رشته مورد نظر از بررسی عبور کند، آن را با secret (مقدار سری) XOR می‌کند. در غیر این صورت، یک رشته دیگر (فلگ) را با secret XOR می‌کند.
سپس من به سراغ پیدا کردن مقادیر برای متغیرهای مختلف رفتم:
what = b"\x17/'\x17\x1DJy\x03,\x11\x1E&\x0AexjONacA-&\x01LANH'.&\x12>#'Z\x0FO\x0B%:(&HI\x0CJylL'\x1EmtdC\x00\x00\x00\x00\x00\x00\x00\x00"
secret = b'B\x0A|_\x22\x06\x1Bg7#\x5CF\x0A)\x090Q8_{Y\x13\x18\x0DP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
@ -792,6 +796,7 @@ ___7h15_15_4_f4k3_f14g_y0u_w1ll_f41l_1f_y0u_subm17_17___
خروجی ___7h15_15_4_f4k3_f14g_y0u_w1ll_f41l_1f_y0u_subm17_17___ نشان می‌دهد که این عملیات رمزگشایی با موفقیت انجام شده است. با این حال، همانطور که از متن خروجی پیداست، این یک فلگ "جعلی" (fake flag) است که برای گمراه کردن شرکت‌کنندگان چالش طراحی شده است. این بدان معنی است که شاید راه حل واقعی چالش، یافتن ورودی صحیح برای تابع check() باشد که منجر به شاخه "True" در کد اصلی می‌شود و یک فلگ متفاوت را تولید می‌کند.
نکته: اگر A ^ B = C باشد، آنگاه A ^ C = B و B ^ C = A. این یک خاصیت بنیادی است که برای معکوس کردن عملیات XOR در هر دو مسیر (فلگ واقعی و جعلی) استفاده می‌شود.
### اسکریپت دوم:
@ -903,6 +908,7 @@ __int64 __fastcall check(__int64 a1) // 1. تعریف تابع check: یک آر
### اسکریپت سوم:
```python
what = b"\x17/'\x17\x1DJy\x03,\x11\x1E&\x0AexjONacA-&\x01LANH'.&\x12>#'Z\x0FO\x0B%:(&HI\x0CJylL'\x1EmtdC\x00\x00\x00\x00\x00\x00\x00\x00"
# متغیر `what` را تعریف می‌کند که حاوی بایت‌های رشته ثابت `what` است.
@ -967,10 +973,16 @@ for i in range(30, 127):
این قطعه کد پایتون یک رویکرد بروت فورس (Brute-Force) و معکوس‌سازی الگوریتم تابع check() را برای پیدا کردن فلگ اصلی پیاده‌سازی می‌کند. هدف این کد، تولید کاندیداهای فلگ است تا یکی از آن‌ها فلگ صحیح باشد.
نکته: بروت‌فورس در علوم کامپیوتر و امنیت سایبری به معنای یک روش حل مسئله است که در آن تمام ترکیب‌های ممکن برای یافتن راه‌حل امتحان می‌شوند تا زمانی که راه‌حل صحیح پیدا شود. این روش معمولاً شامل امتحان کردن هر گزینه موجود به صورت منظم و خسته‌کننده است تا زمانی که مورد درست کشف شود.
دید کلی درباره این قطعه کد 🧩
این قطعه کد پایتون یک حمله رمزی معکوس (Cryptographic Reverse Engineering) برای یافتن فلگ اصلی است. به جای اینکه سعی کند تابع check() را با ورودی‌های تصادفی دور بزند (که ناکارآمد است)، این کد منطق check() را معکوس می‌کند.
نکته: مهندسی معکوس رمزنگاری که گاهی اوقات به آن رمزنگاری معکوس نیز گفته می‌شود، فرایند تحلیل و بازسازی الگوریتم‌ها و مکانیزم‌های رمزنگاری پنهان شده در یک برنامه یا سیستم است. هدف از این کار کشف نحوه رمزنگاری و رمزگشایی داده‌ها بدون دسترسی به سورس کد اصلی یا مستندات طراحی است.
فرایند کار آن به شرح زیر است:
استخراج داده‌ها: فرض بر این است که مقادیر what و secret قبلاً از باینری برنامه استخراج شده‌اند.
@ -984,8 +996,6 @@ for i in range(30, 127):
این رویکرد بسیار کارآمدتر از حدس زدن کل فلگ به صورت تصادفی است، زیرا از دانش بدست‌آمده از تحلیل تابع check() برای محدود کردن فضای جستجو و بازسازی هوشمندانه فلگ استفاده می‌کند.
### اسکریپت چهارم:
```python
what = b"\x17/'\x17\x1DJy\x03,\x11\x1E&\x0AexjONacA-&\x01LANH'.&\x12>#'Z\x0FO\x0B%:(&HI\x0CJylL'\x1EmtdC\x00\x00\x00\x00\x00\x00\x00\x00"
@ -1077,16 +1087,46 @@ for i in range(30, 127):
---
## نکته‌های تکمیلی:
### درباره‌ی "Artifacts" (ماده دست‌ساز/باقیمانده) در خروجی دی‌کامپایلر.
در خروجی‌های کد C شبه‌کدی که از دی‌کامپایلرهایی مانند IDA Pro یا Cutter به دست می‌آید، گاهی اوقات می‌بینید که دی‌کامپایلر نمی‌تواند به طور کامل دستورالعمل‌های اسمبلی را به کد C معنی‌دار تبدیل کند. این موارد را Artifacts یا باقیمانده‌های تحلیل نادرست می‌نامیم.
در خروجی jsdec از تابع main، این خطوط را داشتیم:
edi = "B\n|_"; // این رشته یک artifact از دی‌کامپایلر است و مربوط به کد واقعی نیست.
// ...
edi = "B\n|_"; // artifact دی‌کامپایلر
این خطوط زمانی ظاهر می‌شوند که دی‌کامپایلر سعی می‌کند یک رجیستر (مانند EDI) را که در واقع برای عملیات روی آدرس‌های حافظه یا مقادیر عددی استفاده می‌شود، به صورت یک رشته ثابت تفسیر کند. دلیلش این است که شاید در آن لحظه، یک مقدار بایت خاص در رجیستر وجود داشته که شباهت نزدیکی به ابتدای یک رشته (مثل B\n|_) دارد و دی‌کامپایلر آن را به اشتباه به عنوان آدرس یک رشته تفسیر کرده است.
چرا این مهم است؟ ⚠️
گمراه کننده هستند: اگر به این Artifactsها توجه نکنید، ممکن است فکر کنید این رشته‌ها واقعاً در کد استفاده می‌شوند، در حالی که اینطور نیست. این می‌تواند شما را در تحلیل و تلاش برای بازسازی منطق برنامه گمراه کند.
نیاز به تفکیک: باید بتوانید بین کد منطقی واقعی برنامه و تفسیرهای اشتباه دی‌کامپایلر تمایز قائل شوید.
تأکید بر دانش اسمبلی: این Artifactsها نشان می‌دهند که اگرچه دی‌کامپایلرها بسیار مفیدند، اما همیشه کامل نیستند و گاهی نیاز است برای درک کامل، به کد اسمبلی خام نیز نگاهی بیندازید تا ببینید رجیسترها واقعاً چه مقداری را نگه می‌دارند.
چگونه این Artifacts را شناسایی و نادیده بگیریم؟
ناهمخوانی با منطق کلی: اگر یک رشته یا عملیات خاص به نظر می‌رسد که در منطق کلی برنامه جا نمی‌گیرد یا بی‌معنی است (مثلاً یک رشته عجیب که هرگز استفاده نمی‌شود)، مشکوک شوید.
بررسی Xrefs: اگر روی رشته مشکوک (مثلاً B\n|_) در Cutter کلیک راست کنید و "Xrefs to" را بزنید، احتمالاً می‌بینید که هیچ ارجاع معناداری به آن در بخش‌های مهم کد (مانند حلقه‌های اصلی یا فراخوانی‌های توابع) وجود ندارد.
مشاهده اسمبلی: بهترین راه، بررسی کد اسمبلی مربوطه است. در اسمبلی، می‌بینید که رجیستر EDI ممکن است یک آدرس حافظه یا یک مقدار عددی را بارگذاری کند، نه یک رشته ثابت.
در این چالش، با شناخت این Artifacts می‌توانستیم مطمئن شویم که رشته‌هایی مانند B\n|_ جزو داده‌های secret یا what نیستند، بلکه صرفاً محصول جانبی فرآیند دی‌کامپایل هستند. این کمک می‌کند تا روی داده‌های واقعی و مهم تمرکز کنید.
### ابزار strip
یک ابزار خط فرمان است که در سیستم‌عامل‌های یونیکس-مانند (مانند لینوکس و macOS) و همچنین در ابزارهای توسعه ویندوز (مانثل MinGW/MSYS2) موجود است. وظیفه اصلی آن حذف نمادهای اشکال‌زدایی (debugging symbols) و متادیتای غیرضروری از فایل‌های اجرایی (باینری‌ها) و کتابخانه‌ها است. وقتی یک برنامه کامپایل می‌شود، کامپایلر اغلب اطلاعاتی مانند نام توابع، نام متغیرها، و مسیرهای فایل‌های سورس را برای کمک به اشکال‌زدایی (Debugging) در فایل باینری قرار می‌دهد. ابزار strip این اطلاعات را حذف می‌کند. این کار باعث کاهش حجم فایل نهایی و همچنین دشوارتر شدن مهندسی معکوس می‌شود، زیرا تحلیلگر دیگر به این اطلاعات کمکی دسترسی ندارد و باید بیشتر روی کد اسمبلی خام تمرکز کند. به همین دلیل، strip معمولاً در مرحله نهایی بیلد برای تولید نسخه‌های Release و نهایی محصولات استفاده می‌شود.
URL: https://www.man7.org/linux/man-pages/man1/strip.1.html
### ابزارهای دیگر؛
objdump
### چرکنویس؛
better_than_asm_huh
Bamboofox{b3tt3r_th4n_4_d3c0mp1l3r_huh}
7h15_v3ry_l0ng_4nd_1_h0p3_th3r3_4r3_n0_7yp0