ویرگول
ورودثبت نام
عماد عابدینی
عماد عابدینیSecurity Researcher | Full Stack Developer
عماد عابدینی
عماد عابدینی
خواندن ۶ دقیقه·۴ ماه پیش

استخراج Shellcode و فایل‌های Pack شده از بدافزارها

فرایند استخراج Shellcode و فایل‌‌های Pack شده از بدافزارهایی که در زمان اجرا بخشی از کد رو Unpack می‌کنن (مثل Dropperها، Packed Malwareها یا Multi-Stageها)، نسبت به روش پیاده‌سازی و مکانیزم‌های به کار رفته، می‌تونه بسیار زمان‌بر و پیچیده باشه.

پیش‌نیاز این پست اینه که با مقدمات Reverse Engineering و Malware Analysis آشنا باشید.

وقتی با این دسته از بدافزارها سر و کار داریم، دو روش اصلی برای استخراج بخش‌ Pack شده وجود داره:

۱. اجرای بدافزار و بررسی Memory:
بدافزار رو اجرا می‌کنیم و هم‌زمان میریم سراغ Regionهایی از Memory که Execute Flag دارن. بخش‌ Unpack شده ممکنه توی همین Regionها قابل شناسایی باشه.

۲. زیر نظر گرفتن کردن APIهای مرتبط (روش دقیق‌تر):
در این روش، توابعی که کارشون تخصیص یا تغییر Permission در Memory هست رو زیر نظر می‌گیریم، تا هرجا بدافزار روی Memory چیزی نوشت یا تغییری ایجاد کرد متوجه بشیم.

تعدادی از توابع مهمی که باید حواسمون بهشون باشه، ایناست:

  • VirtualAlloc / VirtualAllocEx

  • VirtualProtect / VirtualProtectEx

  • NtAllocateVirtualMemory

  • NtProtectVirtualMemory

مثلا طبق مستندات، در تابع VirtualAlloc آرگومان اول (lpAddress) همون آدرس حافظه‌ایه که قراره فضا بهش اختصاص داده بشه. ما این آدرس رو زیر نظر می‌گیریم تا هر موقع هر بخشی از Code خواست چیزی روش بنویسه یا ازش بخونه، دیباگر همون لحظه Break کنه و اینطوری قدم‌به‌قدم به بخش Unpack شده نزدیک‌تر بشیم.

  • البته ناگفته نمونه که lpAddress می‌تونه NULL هم باشه. در واقع با این پارامتر فقط یک آدرس پیشنهادی مشخص میشه، اگه NULL بدیم یا اون آدرس قبلا گرفته شده باشه، سیستم یک آدرس دیگه اختصاص می‌ده.

  • روش دقیق‌تر اینه که بذاریم VirtualAlloc کامل اجرا بشه و Breakpoint رو روی مقدار برگشتی (Base Address) بذاریم.
    ازونجایی که این مباحث موضوع این پست نیست، وارد این جزئیات نمی‌شیم.

در هر دو روش بالا، اصل کاری که انجام میدیم اینه که بذاریم بدافزار روال طبیعی خودش رو طی کنه تا فرایند Unpack انجام بشه، بعد به یکی از این دو روش کارو ادامه بدیم:

  • از Memory دامپ می‌گیریم و در صورت نیاز ساختار فایل، OEP (Original Entry Point) و IAT رو بازسازی (Fix) می‌کنیم و در نهایت فایل ایجاد شده رو جداگونه تحلیل می‌کنیم.

  • بخش Unpack شده رو مستقیم توی دیباگر تحلیل می‌کنیم.

البته واقعیت اینه که این فرایند خیلی وقت‌ها ساده پیش نمیره و می‌تونه زمان زیادی از ما بگیره، مثلا:

  • بعضی بدافزارها بخش Unpack شده رو در چند مرحله (Multi-Stage) و مستقیم در Memory اجرا می‌کنن، در واقع مرحله اول فقط Stage بعدی رو لود می‌کنه.

  • ممکنه به یک Region از حافظه فلگ‌هایی مثل PAGE_GUARD یا PAGE_NOACCESS بده، تو این حالت وقتی کد میخواد به اون Region دسترسی پیدا کنه یک Exception اتفاق میفته و همون لحظه دسترسی Execute داده می‌شه.

  • ممکنه شماره‌ی Syscall رو مستقیما فراخوانی کنه و پارامترها رو در رجیسترها قرار بده.

  • ممکنه بعد از Unpack، کد خودش رو در زمان اجرا (Runtime) تغییر بده.

  • ممکنه از مکانیزم‌های پیشرفته تشخیص دیباگر (Anti-Debugging) استفاده کرده باشه.

  • و تکنیک‌های پیچیده‌ی دیگه که باعث شن تحلیل پیچیده‌تر بشه.


حالا توی این مسیر می‌شه از ابزارهایی کمک گرفت که فرایند Unpack رو خودشون انجام میدن و فایل‌ Pack‌شده رو خیلی سریع استخراج می‌کنن. 😍

البته که قطعا این ابزارها همیشه جواب نمیدن، ولی بازم تست کردنشون قبل از شروع Debug ممکنه بتونه کارمون رو کلی جلو بندازه.

یکی از ابزارهای خیلی خوب در این زمینه، mal_unpack هست که توسط Aleksandra Doniec (معروف به hasherezade) و بر پایه PE-sieve توسعه داده شده:

https://github.com/hasherezade/mal_unpack

نحوه کارش به این صورته که بدافزار رو اجرا می‌کنه و هم‌زمان یه Passive Scan روی Memory انجام میده تا بخش‌هایی که Executable Code جدید لود شده رو پیدا کنه. نکته اینجاست که از API Hooking استفاده نمی‌کنه و بنابراین مکانیزم‌های Anti-Debug و Obfuscation معمولا تاثیری روش ندارن. در واقع، mal_unpack میاد بدافزار رو اجرا می‌کنه، Stageهای جدید رو تشخیص میده، ازشون Dump می‌گیره و در نهایت پروسه رو Terminate می‌کنه.

البته بعضی وقتا نمی‌تونه کامل Terminate کنه و اینو تو خروجی گزارش میده.

نحوه کار با mal_unpack:

کار با این ابزار خیلی ساده‌ست. بعد از دانلود و نصب، به این صورت میشه ازش استفاده کرد:

mal_unpack.exe /exe <path_to_the_malware> /timeout <timeout: ms>

  • با exe/ مسیر فایل رو بهش میدیم

  • با timeout/ مشخص می‌کنیم که فایل چند میلی‌ثانیه اجرا بمونه.

mal_unpack.exe /exe C:\samples\malware.exe /timeout 10000

خروجی چیزی شبیه به این خواهد بود:

اگه دنبال این نمونه از Malwareها هستین، تو Malware Bazaar این تگ‌ها رو سرچ کنید:

tag:upx
tag:packer
tag:packed
tag:dropper
tag:loader

بعد از اجرای ابزار، یک فولدر کنار همون فایل اصلی می‌سازه با نام filename>.<extension>.out>. مثلا اگه فایل اصلی malware.exe باشه، خروجی‌ها توی فولدری با نامmalware.exe.out (همونطور که توی لاگ بالا هم مشخصه) ایجاد میشه. محتوای این فولدر چیزی شبیه به این میشه:

حالا این فایل‌هایی که ایجاد کرده، دقیقا چی هستن؟

  • فایل‌های json. در واقع خلاصه‌‌ای از کل کاری هست که انجام داده:

  • فایل‌های txt.

    لیست Importهایی هست که در Memory پیدا کرده:

  • فایل‌های exe. همون Executable Codeهای جدیدی هستن که در Memory لود شدن و ابزار تونسته شناسایی‌شون کنه و Dump بگیره.

  • فایل shc. همون Shellcodeی هست که Dumped down شده روی دیسک.


نکات استفاده از Mal_unpack:

  • این ابزار به‌ صورت پیش‌ فرض فقط فایل‌هایی رو Dump می‌کنه که ساختار شبیه به PE دارن. اگه بخوایم Shellcodeهایی که مستقیم در Memory لود میشن یا روی Disk ذخیره میشن رو هم تشخیص بده، باید shellc/ هم اضافه کنیم.

  • در حالت پیشفرض mal_unpack همین که اولین فایل Pack شده رو شناسایی و Dump کنه، ادامه‌ی اجرا رو متوقف می‌کنه. اگه می‌خواید در هر صورت تا پایان مقدار timeout/ به اجرا ادامه بده، باید از trigger T/ استفاده کنید.

  • ممکنه ساختار یا هدرهای PE دستکاری شده باشن. توی این حالت، برای اینکه همچنان بتونه فایل رو شناسایی و Dump کنه، باید hooks/ رو اضافه کنید.

  • اگه فایل dll. باشه، باید به exe/ آدرس rundll32.exe رو بدین و با cmd/ مسیر فایل به همراه فانکشن Entry Pointش رو مشخص کنید.

  • به‌صورت پیش‌فرض، mal_unpack خیلی وقت‌ها نمی‌تونه پروسه رو به‌طور کامل Terminate کنه. برای رفع این مشکل و بهبود Isolation، می‌تونید mal_unpack_drv رو نصب کنید:

https://github.com/hasherezade/mal_unpack_drv

mal_unpack می‌تونه هر نوع فایلی رو Unpack کنه؟

قطعا نه. این ابزار هم مثل سایر ابزارهایی که در زمینه Malware Analysis استفاده میشن، هدفش اینه سرعت فرایندها رو بالا ببره. ولی خب همه این ابزار‌ها در کنار محدودیت‌ها و ضعف‎‌هایی که دارن، تو خیلی از موارد توسعه‌دهنده بدافزار می‌تونه (نسبت به اطلاع از نحوه کار اون ابزار)، کدشو جوری بزنه که این ابزارها کارایی مورد انتظار رو نداشته باشن. مثلا mal_unpackیک مشکل خیلی بزرگی که داشت (الان رفع شده)، این بود که نمی‌تونست Shellcodeهای Cobaltی که بایت اولشون با FC شروع میشه رو تشخیص بده! همین الانم بخش Signature و Patternهایی که داره خیلی کامل نیست.

البته Aleksandra (توسعه‌دهنده ابزار) قابلیتی اضافه کرده که بشه به صورت داینامیک، Pattern اضافه کرد. نحوه کار هم خیلی ساده‌ست، بخشی از فانکشن اصلی Shellcode مد نظرتون رو به صورت Raw Hex کپی کنید و به صورت Sig Format با پسوند sig. ذخیره‌ش کنید و در نهایت این فایل رو با پارامتر pattern/ به ابزار بدید، به این صورت:

  • ساختار دقیق SIG Format رو خود Aleksandra تو یک Repository دیگه توضیح داده:

https://github.com/hasherezade/sig_finder

  • تو حالتی که با یک بدافزار جدید روبه‌رو باشیم که ندونیم چه نوع Shellcodeی داخلش استفاده شده، طبیعتا قابلیت اضافه کردن Pattern خیلی کاربردی نیست.


اگه بخوایم یه جمع‌بندی داشته باشیم، در حال حاضر تموم ابزارهایی که برای این منظور استفاده می‌شن هر کدوم محدودیت‌های خودشون رو دارن و در بهترین حالت روی بعضی نمونه‌ها Fail می‌شن. تنها روشی که فعلا همیشه جواب میده همون Debug کردنه، درسته ممکنه زمان زیادی بگیره، ولی وقتی ابزارها نتونن کمکی کنن، آخرین و مطمئن‌ترین روش همینه.

امیدوارم این پست براتون مفید بوده باشه.
اگه سوالی داشتید می‌تونیم لینکدین در ارتباط باشیم.

شاد و موفق باشید... ❤️

تحلیل بدافزارمهندسی معکوسدیباگبدافزارامنیت
۳
۰
عماد عابدینی
عماد عابدینی
Security Researcher | Full Stack Developer
شاید از این پست‌ها خوشتان بیاید