AMSI یا Antimalware Scan Interface یک رابط امنیتی در ویندوز است که مایکروسافت برای مقابله با اجرای کدهای مخرب در زمان اجرا طراحی کرده. این فناوری به برنامهها و آنتیویروسها اجازه میده تا کدهای اسکریپتی در حافظه رو قبل از اجرا بررسی کرده و تهدیدات رو شناسایی کنن.
با توجه به این مکانیزم امنیتی، بازیگران تهدید و افرادی که کار RedTeam انجام میدن، موقع اجرای اسکریپتهای مثلا پاورشلی، با مشکل روبرو میشن و اسکریپتشون اجرا نمیشه. بنابراین برای اجرای این نوع اسکریپتها، نیاز هستش که این مکانیزم امنیتی رو دور بزنن. روش های مختلفی برای دور زدن AMSI وجود داره، اما کدوم روش در سال 2025 میتونه موثر باشه؟
این قضیه رو آقای Fabian Mosch (S3cur3Th1sSh1t) در مقاله اخیرشون بررسی کرده که در این پست با هم بررسیش میکنیم.
این مقاله به شش بخش تقسیم شده:
- چه زمانی نیاز به دور زدن AMSI داریم؟
- AMSI چطوری کار میکنه و چطوری میشه دورش زد؟
- معایب استفاده از مبهم کننده های (obfuscator) عمومی
- کدوم روش دور زدن AMSI رو استفاده کنیم؟
- آیا پچ کردن AmsiScanBuffer واقعاً دیگه کار نمیکنه؟
- نتیجه گیری
1- چه زمانی نیاز به دور زدن AMSI داریم:
اگرچه AMSI در بسیاری از مقالات و ابزارها، آنالیز و توصیف شده، اما هنوز هم شگفت زده میشم که این همه سردرگمی و سوءتفاهم در جامعه وجود داره. برای مثال، تعداد زیادی لودر شلکد در GitHub منتشر شدن که هیچ کاری جز اجرای شلکد انجام نمیدن. اما در README اونا ذکر شده که شامل دور زدن AMSI هم هستن و به همین دلیل هرگز شناسایی نمیشن. بنابراین، سوءتفاهم های زیادی، حداقل در GitHub یا شبکههای اجتماعی، وجود داره که ممکنِ افراد بیشتری رو گیج کنه.
چه زمانی واقعاً لازمه از دور زدن AMSI استفاده کنیم؟ حداقل برای اجرای شلکد، نیازی به اون نداریم.
AMSI، همونطور که بیش از چهار سال پیش در وبلاگم نوشتم (Bypass AMSI by manual modification و Powershell and the NET AMSI Interface )، عمدتاً برای تحلیل زبانهای اسکریپتنویسی و کد مدیریتشده NET. در زمان اجرا استفاده میشه، مانند:
- Powershell
- VBS
- Javascript
- ماکروهای VBA
- اسمبلی های سی شارپ
بنابراین، اگه از پیلود (payload) یک فریمورک Command & Control استفاده میکنید و عمدتاً BOFها یا COFFها رو از اونجا اجرا میکنید، هیچ وقت نیازی به دور زدن AMSI نخواهید داشت. اگه در لودرتون یک دور زدن پیاده سازی کنید، فقط شاخصهای شناسایی (IoCها) رو افزایش میدید و احتمال شناسایی شدن به دلیل تلاش برای دور زدن، بیشتر میشه. همیشه بهتره دور زدنها رو حذف کنید، مگه اینکه واقعاً بهشون نیاز داشته باشید!
از طرف دیگه، اگه بخواید:
- ابزارهای مخرب شناخته شده و مبهم نشده عمومی رو اجرا کنید، مثلاً از GitHub در هر یک از زبانهای بالا، یا کد اونارو در ابزارهای خودتون دوباره استفاده کنید، برای اجراشون نیاز به دور زدن AMSI دارید.
- اگه بخوایید اسکریپتهای GitHub رو از طریق Invoke-Expression در Powershell اجرا کنید
- یک اسمبلی NET. رو از طریق ()assembly::load لود کنید
- ماکروهای مخرب آفیس بسازید
- اسکریپتها رو از طریق mshta.exe، cscript.exe یا wscript.exe در حافظه لوود کنید
به احتمال زیاد به دور زدن AMSI نیاز خواهید داشت.
2- AMSI چطوری کار میکنه و چطوری میشه دورش زد:
AMSI عمدتاً مبتنی بر تشخیص امضاهاست. تفاوت اصلی که با تشخیصهای مبتنی بر امضای کلاسیک داره اینه که این امضاها در زمان اجرا (runtime) جستجو میشن، یعنی هر وقت چیزی که ممکنه مخرب باشه، از حافظه لوود میشه. همونطور که اخیراً توسط IBM X-Force Red اشاره شده، از نظر معماری، AMSI در برخی نقاط خاص وقتی چیزی از دیسک به حافظه لوود میشه، اصلاً اسکن رو فعال نمیکنه.
امضاهای AMSI، چه شکلی دارن؟ اونا میتونن رشتههای سادهای مثل “Invoke mimic set” باشن یا آرایههای بایتی مثل بایتهایی که برای پچ کلاسیک AmsiScanBuffer استفاده میشن:
1 |
[byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3) |
برای اسمبلی های #C، اینا میتونن بایتهای HEX خاصی باشن، اما بر اساس تجربهام، AMSI همچنین از نوعی قوانین Yara – یا حداقل عبارات منظم (regular expressions) – استفاده میکنه. اما اگه AMSI مبتنی بر امضاست، این یعنی اینکه همیشه میشه با تغییر کد، اونو دور زد. اگه کد رو طوری تغییر بدید که امضا دیگه اعمال نشه، میتونید AMSI رو دور بزنید. به همین “سادگی”، هرچند گاهی پیدا کردن امضاها دشواره.
جایگزین دور زدن تشخیص AMSI اینه که به نحوی عملکرد درون amsi.dll یا سایر کتابخانه های درگیر در فرآیند اسکن رو مختل کنید، یا کلاً جلوی لوود DLL رو بگیرید. این همون چیزی است که تقریباً همه ی دور زدنهای مستند شده عمومی به اون مربوط میشن. این روشها عمدتاً در تکنیک مورد استفاده برای مختل کردن، متفاوت هستن، مانند:
- پچ کردن منطقه ای از حافظه (که از نظر من شامل هوکها هم میشه)
- استفاده از Vectored Exception Handlers و مثلاً نقاط توقف سختافزاری (Hardware Breakpoints) برای دستکاری جریان کار. (Vectored Exception Handlers که بهش به اختصار VEH هم میگن، یک مکانیزم پیشرفته در ویندوزه که به برنامهها اجازه میده یک تابع خاص رو ثبت کنن. این تابع میتونه همه استثناها در برنامه رو زیر نظر داشته باشه یا مدیریت کنه. این مکانیزم یک جور توسعه در Structured Exception Handling (SEH) هستش، ولی یه تفاوت بزرگ داره: برخلاف SEH که به فریمهای فراخوانی (call frameها) وابسته هستش، VEH به این فریمها وابسته نیست. یعنی فرقی نمیکنه کد برنامهات تو کدوم قسمت از زنجیره فراخوانی (call stack) باشه، اگه یه استثنا پیش بیاد، این هندلر فراخوانی میشه.برای این کار میتونیم از توابع AddVectoredExceptionHandler و RemoveVectoredExceptionHandler استفاده کنیم.)
- ایجاد یک پروسس جدید و جلوگیری از لوود یکی از DLLهای مربوط به روشهای مختلف
- جلوگیری از لوود یکی از DLLهای مرتبط قبل از شروع CLR و/یا اجرای اولیه AMSI
این کارها معمولاً در زمان اجرا انجام میشه. IoCها و در نتیجه تشخیص این دور زدنها به موارد زیر وابسته است:
- وجود امضا برای کدی که عمل دور زدن رو انجام میده، یا
- تشخیصهای زمان اجرا مثل هوکهای سطح کاربر (userland hooks)، ETWti یا اسکنهای حافظه.
3- معایب استفاده از مبهم کننده های (obfuscator) عمومی:
وقتی اولین وبلاگم رو درباره دور زدن AMSI نوشتم، استفاده از ابزارهای عمومی مبهمسازی برای فرار از تشخیص، هنوز ممکن بود. آیا الان هم همین طوره؟
برای سرگرمی، بیایم یه آزمایش ساده انجام بدیم. برای این کار، من از ChatGPT خواستم یه اسکریپت تصادفی Powershell تولید کنه. این اسکریپت بدلیل اینکه مخرب نیست، در VirusTotal، بعنوان مخرب شناسایی نشد.
بعد از اینکه این اسکریپت رو با Invoke-Obfuscation مبهمسازی کردم و دوباره در VirusTotal آپلودش کردم، بجای 0 قبلی، 1 تشخیص گرفتم. پس در نگاه اول به نظر میرسه فقط یک فروشنده یک قانون کلی برای تشخیص مبهمسازی Invoke-Obfuscation داره. همونطور که مشاهده میکنید یک قانون Sigma فعال شده، چون یک تطابق پیدا کرده برای استفاده از Invoke-Obfuscation همراه با TOKEN OBFUSCATION:
مبهم کردن چطوری در برابر ابزارهای مخرب شناخته شده GitHub کار میکنه؟ بیایم دو مثال رو بررسی کنیم:
نسخه های مبهم نشده ابزارهای موجود در گیتهاب:
- Invoke-Rubeus از PowersharpPack : در زمان نگارش این مقاله، 29 تشخیص
- WinPwn : در زمان نگارش این مقاله 19 تشخیص
نسخه ی مبهم شده با Invoke-Obfuscation :
- Invoke-Rubeus از PowersharpPack : در زمان نگارش این مقاله، 10 تشخیص
- WinPwn : در آپلود اول، 2 تشخیص
همونطور که می بینیم، تقریباً پنج سال بعد هنوز هم میشه با همون ابزارهای عمومی مبهمسازی، از تشخیص مبتنی بر امضا فرار کرد. راستش انتظارش رو نداشتم، فکر میکردم تا الان تشخیصهای خاص بیشتری برای Invoke-Obfuscation وجود داشته باشه.
نکته: بعد از اینکه این پست وبلاگ رو تموم کردم، با چند EDR و اسکریپتهای بالا بازی کردم، معلوم شد که بعضیهاشون امضاهای اختصاصی AMSI برای Invoke-Obfuscation دارن! حتی اسکریپت اول که مخرب نبود هم بعنوان مخرب علامت گذاری شد. این یعنی VirusTotal تشخیصهای مبتنی بر AMSI رو نشون نمیده، بلکه فقط تشخیص های مبتنی بر امضاهای خود فایل رو نمایش میده. این موضوع باعث میشه Invoke-Obfuscation در برابر اون فروشندهها کاملاً بیفایده بشه.
WinPwn در چند جا خراب شد، بنابراین بعضی از قابلیتهاش مثله دور زدن AMSI، دیگه کار نمیکنه:
البته منو هنوز نمایش داده میشد و توابع اصلی Powershell بصورت عادی قابل استفاده بودن.
نسخه مبهمشده Invoke-Rubeus هم اولش به مشکل خورد، بخاطر مبهمسازی، چون نوع [dreIKOpFhund.pROGRam] قبل از تابع و بعنوان متغیر قرار داده شده بود و اسامی فضای نام (Namespace) و کلاسها در این مرحله بدرستی نمیتونستن ازش استفاده کنن. برای درست کردنش، من بصورت دستی این قسمت رو بعد از خط مبهمشده [assembly::load] در خود تابع قرار دادم:

خود این مورد، نشون میده که مبهم سازها، میتونن کد ما رو خراب کنن و برای اجرای درست، نیاز هستش که ما بصورت دستی اونارو اصلاح کنیم. آیا ما میتونیم AMSI دیفندر رو دور بزنیم؟
در نگاه اول به نظر میرسه که موفق شدیم، اما فقط برای خود اسکریپت PowerShell و نه برای اسمبلی Rubeus که در زمان اجرا فراخوانی میشه. چرا این اتفاق افتاده؟ این موضوع رو قبلاً در دومین بلاگ شخصی ام توضیح دادم. بنابراین، در این حالت ابتدا باید اسمبلی رو مبهم کنیم، اونو در اسکریپت قرار بدیم و بعدش خود اسکریپت PowerShell رو مبهم کنیم. این روند باید برای هر اسمبلی و اسکریپت بصورت جداگانه انجام بشه. اما آیا سادهتر نیست که بجای این کار، از یک بایپس AMSI موجود استفاده کنیم؟
4- کدوم روش دور زدن AMSI رو استفاده کنیم:
در زمان انتشار اولین بلاگ من، مخزن Amsi Bypass Powershell شامل ۱۵ روش مختلف برای دور زدن AMSI بود. بیش از چهار سال بعد، این تعداد به ۲۳ قطعه کد مختلف افزایش یافته، یعنی ۸ مورد بیشتر. و این تنها تکنیکهایی هستن که منتشر شدن، از جمله کدهای PowerShell. من عمدا سایر بایپس های منتشرشده، مثلاً اونایی که قبل از لود CLR در زبانهای بومی اجرا میشن (مانند Ruy-Lopez خودم)، رو اضافه نکردم.
بنابراین، تعداد روشها به میزان قابل توجهی افزایش یافته. اما چه چیزی در سال ۲۰۲۵ واقعاً مؤثر خواهد بود و چه چیزی مؤثر نخواهد بود؟ چطوری میشه این موضوع رو ارزیابی کرد؟
بطور کلی، همه بایپسهای عمومی دارای امضای مشخصی هستن و توسط خود AMSI شناسایی میشن، حداقل زمانی که در یکی از زبانهای اسکریپتنویسی مانند PowerShell پیادهسازی بشن. بنابراین، برای همه اونا، لازم است که کد بصورت دستی تغییر داده بشه یا مبهم بشه تا دیگه توسط AMSI تشخیص داده نشن. این فرآیند نیازمند تلاش زیادی است و بر پایه آزمون و خطا انجام میشه.
اما مشکل این روش این است که فروشندگان مختلف، امضاهای متفاوتی دارن و حتی اگه بایپس اصلاح شده شما برای یک فروشنده کار کنه، ممکنه برای فروشندهی دیگه کار نکنه. من سالها این کار رو انجام دادم، اما در نهایت متوجه شدم که حجم کار بسیار زیاده.
انتخاب زبان مناسب:
از طرف دیگه، استفاده از زبانهای بومی (Native) این مزیت رو داره که کد شما مستقیماً توسط AMSI اسکن نمیشه. در عوض، شما باید با شناسایی مبتنی بر امضا برای فایلهای باینری یا DLL خودتون در دیسک سر و کار داشته باشید. این به معنای نیاز به استفاده از مبهمسازی/رمزگذاری رشتهها، تکنیکهای ضد شبیهسازی (Anti-Emulation)، ضد سندباکس (Anti-Sandbox) و همچنین بایپس های Hook در سطح User-mode، مشابه زبانهای اسکریپت نویسی و روش بایپس که بالا اشاره شد، داره.
علاوه بر این، CLR بطور پیشفرض در پروسس های بومی لوود نمیشه و AMSI هم مقداردهی اولیه نمیشه، که بطور کلی گزینههای بیشتری برای بایپس فراهم میکنه.
به همین دلیل، این روزها استفاده از زبانهای برنامهنویسی بومی روش ترجیحی من برای بایپس AMSI شده، اما این کار نیازمند دانش عمیق تری درباره ویندوز API و روشهای دور زدن مکانیزمهای امنیتی اون هستش.
چه چیزی هنوز مؤثره؟
چطوری میشه میزان کارایی یک روش رو ارزیابی کرد؟ همونطور که قبلاً اشاره شد، همه بایپسهای عمومی رو میشه تغییر داد تا از شناسایی مبتنی بر امضا در دیسک و همچنین AMSI عبور کنن. اما برای برخی از تکنیکها، شناسایی در زمان اجرا توسط فروشندگان مختلف بطور فزایندهای اهمیت پیدا کرده. این نوع شناسایی در زمان اجرا رو نمیشه به سادگی دور زد.
به عبارت دیگه، هرچند که روشهای سنتی بایپس AMSI همچنان قابل استفاده هستن، اما با پیشرفت مکانیزمهای امنیتی، بایپس های قدیمی نیاز به تغییرات و روشهای پیشرفتهتر، پویاتر و بومیتر خواهند بود.
پچ کردن (Patching):
اگه تصمیم به پچ کردن بگیرید، با هوکهای Userland مواجه خواهید شد که مانع از تغییر سطوح دسترسی حافظه برای amsi.dll یا نوشتن داده در حافظه اون میشن. برای عبور از این محدودیتها، باید از روشهایی مانند Unhooking، فراخوانیهای غیرمستقیم (Indirect Syscalls) یا تکنیکهای مشابه استفاده کنید.
اما حتی پس از انجام این کار، همچنان ممکنه توسط مکانیزم های شناسایی ETWti یا اسکن حافظه برای پچها (Memory Scan Detections) شناسایی بشن. یک مثال واضح، تشخیص اخیر Microsoft Defender برای پچ کلاسیک AmsiScanBuffer است. هر زمان که تابع AmsiScanBuffer (یا توابع مشابه) طوری تغییر کنه که فقط مقدار بازگشتی رو برگردونن، یک هشدار صادر شده و پردازش شما خاتمه داده میشه.
چگونه این اتفاق میافته؟ یک AV/EDR براحتی میتونه از طریق رویدادهای ETWti تشخیص بده که حفاظت از تابع AmsiScanBuffer (یا توابع دیگه) در amsi.dll تغییر کرده و دادهای در این مکان نوشته شده. شما نمیتونید این رویدادها رو از Userland دور بزنید، زیرا این رویدادها در سطح Kernel تولید میشن. بعدش، AV/EDR میتونه مکان تابع رو اسکن کنه تا بررسی کنه که آیا تغییری مخرب (از دیدگاه یک بایپس) انجام شده یا خیر.
نتیجه نهایی: این بدان معناست که نباید به این پچ خاص پایبند باشید، زیرا صرف نظر از اینکه از چه تکنیکهایی برای دور زدن Userland استفاده کنید، احتمالاً شناسایی خواهید شد.
نکته: این تشخیص برای پچ کردن EntryPoint توسط چندین فروشنده EDR در چند سال اخیر استفاده شده، اما زمانی که Defender اونو پیادهسازی کرد، توجه بیشتری به اون جلب شد، چون این بایپس بطور گستردهای استفاده میشه.
استفاده از نقاط توقف سخت افزاری (Hardware Breakpoints) :
با توجه به یافتههای ذکر شده در بخش پچ کردن، افراد در جامعه امنیت سایبری ایده استفاده از نقاط توقف سخت افزاری رو مطرح کردن. این روش چندین مزیت مهم داره:
- نیازی به دور زدن هوکهای Userland نداره.
- یکپارچگی (Integrity) DLLهای هدف، حفظ میشه.
- اسکنرهای حافظه نمیتونن این نوع تغییرات رو تشخیص بدن.
بر اساس تجربه من، تعداد بسیار کمی از AV/EDRها توانایی شناسایی استفاده از نقاط توقف سخت افزاری برای دور زدن AMSI رو در زمان اجرا دارن. اما از نظر تئوری، این کار قابل شناسایی است. برای مثال، اگه مقادیر Debug Register بررسی بشن و یکی از اونا روی آدرس AmsiScanBuffer تنظیم شده باشه، میتونه یک هشدار صادر کرد. در خصوص نقاط توقف سخت افزاری میتونید قسمت چهارم از فصل دوم دوره ی مهندسی معکوس نرم افزار رو مشاهده کنید.)
اما در عمل چطور؟ من تاکنون با چنین تشخیصی مواجه نشدم. شاید به دلیل نرخ بالای False Positive باشه؟ با این حال، برخی از فروشندگان AV/EDR اخیراً از طریق ETWti و با استفاده از SetThreadContext چنین شناساییهایی رو انجام دادن.
بطور کلی، بر اساس تجربه من، استفاده از نقاط توقف سخت افزاری هنوز از نظر امنیت عملیاتی (OpSec) در برابر اکثر AV/EDRها ایمن در نظر گرفته میشه و یک روش توصیه شده است. اما این وضعیت ممکنه هر لحظه با بروزرسانیهای جدید در مکانیزمهای تشخیص تغییر کنه. این یک بازی موش و گربه هستش!
جلوگیری از لوود DLLها:
تاکنون چندین تکنیک منتشر شده که مانع از لوود DLLهای مرتبط با AMSI میشن، بطوری که فرآیند اجرای اولیه (Initialization) و اسکن اصلاً انجام نمیشه. همانطور که در بالا ذکر شد، این روش عمدتاً برای زبانهای بومی (Native Languages) یا پروسس های جدیدی که اجرا میشن مناسبه، چون در این موارد هنوز DLL لوود و اجرای اولیه نشده. برخی از نمونههای این روشها عبارتند از:
- ایجاد یک پروسس جدید با فلگ DEBUG_PROCESS و پچ کردن Entry Point هنگام رخداد LOAD_DLL_DEBUG_EVENT با ابزار SharpBlock
- هوک کردن توابع در فرآیند بارگذاری DLL بگونهای که لوود اون با شکست مواجه بشه، مانند NtCreateSection
- هوک کردن توابع در فرآیند بارگذاری DLL برای پروسس های جدید بگونهای که لوود اونا با شکست مواجه بشه، مانند تکنیک Ruy-Lopez
هوک کردن (Hooking) معمولاً توسط EDRها قابل مشاهده است، اما تا جایی که اطلاع دارم، هیچ فروشندهای هنوز هوکهای جدید رو مستقیماً علامتگذاری (Flag) نکرده، احتمالاً بدلیل نرخ بالای False Positive. حتی اگه AV/EDRها شروع به هشداردهی در مورد هوکهای جدید کنن، میشه از نقاط توقف سخت افزاری برای رسیدن به همون هدف استفاده کرد. در نتیجه، تا این لحظه هیچ مکانیزم شناسایی مبتنی بر زمان اجرا (Runtime-Based Detection) برای این تکنیکها وجود نداره و همچنان مؤثر هستن.
جایگزین های هدفمند:
بسته به هدفی که میخوایید AMSI رو روی اون دور بزنید (مثلاً PowerShell یا اسمبلی های #C)، چندین جایگزین دیگه هم وجود داره. در بسیاری از موارد، پچ کردن همچنان گزینهای کاربردیه، اما در آفستها یا مکانهای متفاوت.
در مورد PowerShell، نمودار زیر تجربه شخصی من رو در زمان نوشتن این پست منعکس میکنه.
روش دور زدن اول، در ابتدا هم برای اسکریپتهای PowerShell و هم برای اسمبلی های NET. لود شده کار میکرد. اما بعد از انتشار، مایکروسافت تغییری در PowerShell اعمال کرد که باعث شد دیگه روی اسکریپتها تأثیری نداشته باشه و فقط روی اسمبلیهای NET. اثر بذاره. بنابراین، این روش رو میشه با یکی از بایپسهای علامتگذاری شده با رنگ نارنجی ترکیب کرد یا اگه اسکریپت شما توسط AMSI علامتگذاری نشده و اسمبلیها رو لود میکنه، مشکلی نداشته باشه.
تفاوت بین رنگهای مختلف در تکنیکهای بایپس:
- روشهای سبز رنگ: فقط نیاز به مبهمسازی یا تغییر کد منبع دارن تا از شناسایی مبتنی بر امضا (Signature-Based Detection) فرار کنن.
- روشهای قرمز رنگ: این روشها امروزه به دلیل تشخیصهای مبتنی بر پچ (Patch-Based Detections) بسیار محتمل تر به شناسایی شدن هستن.
- روشهای نارنجی رنگ: فقط روی اسکریپتهای بومی PowerShell مؤثرن، اما به محض اینکه assembly::load اجرا بشه، AMSI دیگه دور زده نمیشه. در برخی موارد، باید Add-Type رو حذف کرده و از جایگزینهای بومی PowerShell استفاده کنید.
برخی از فروشندگان AV/EDR همچنین از هوک کردن روی clr.dll استفاده میکنن، بنابراین در این موارد ممکنه بدلیل تشخیصهای مبتنی بر رفتار (Behavior-Based Detection) شکست بخورید و نیاز به Unhook کردن clr.dll داشته باشید.
در مخزن کد من دو نسخه از این پچ وجود داره:
- نسخهای که از Add-Type استفاده میکنه، فقط برای اسکریپتهای PowerShell کار میکنه.
- نسخهای که از Reflection استفاده میکنه، هم برای اسکریپتهای PowerShell و هم برای اسمبلیهای NET. کاربرد داره.
همانطور که مشاهده میکنید، بعضی از روشهای سبز/نارنجی همچنان شامل بایپسهای مبتنی بر پچ هستن، اما این روشها کمتر شناخته شدن و بنابراین معمولاً توسط اسکنهای حافظه (Memory Scans) بررسی یا شناسایی نمیشن.
در برخی موارد، EDRها دیگه برای اسکن کردن از amsi.dll استفاده نمیکنن. بنابراین، هر بایپسی که این DLL خاص رو هدف قرار بده، دیگه کار نخواهد کرد. در این موارد باید:
- از طریق رجیستری یا بررسی حافظه، DLL مربوط به ارائه دهنده AMSI رو پیدا کرده و پچ کنید.
- یا مستقیماً AMSI DLL سفارشیشدهی اونارو هدف بگیرید.
جزئیات بیشتر در این سخنرانی BlackHat 2022 توضیح داده شده.
دور زدن AMSI مخصوص اسمبلیهای #C که توسط IBM معرفی شده، نباید در زمان اجرا شناسایی بشه. این ایدهی فریب دادن CLR برای لود کردن یک اسمبلی از دیسک، جدید نیست و قبلاً در سال 2021 با یک بایپس دیگه مختص NET. منتشر شده بود.
از زمان انتشار این روش در سال 2021، رفتار Windows Defender تغییری نکرده و لود اسمبلی ها از طریق PoC SharpTransactedLoad همچنان کار میکنه.
اما برخی از EDRها، AMSI رو روی اسمبلیهایی که از دیسک لوود میشن هم اعمال میکنن، بنابراین این روش دیگه کاملاً امن از نظر OpSec محسوب نمیشن.
5- آیا پچ کردن AmsiScanBuffer واقعاً دیگه کار نمیکنه؟
پس از خوندن این پست وبلاگی که سعی داشت دور زدن تشخیصهای جدید Defender رو بررسی کنه، کنجکاو شدم که خودم این تشخیصها رو بررسی کنم. چه چیزی میتونه باعث این نوع تشخیصها بشه؟
پچهای عمومی شناختهشده معمولاً از دستور 0xC3 (RET) در نقطه ورود (Entry Point) تابع AmsiScanBuffer استفاده میکنن تا اجرای تابع رو متوقف کرده و مقدار INVALID ARG رو برگردونن، که باعث میشه فراخوانی کننده (Caller)، تصور کنه که هیچ فعالیت مخربی شناسایی نشده. بیایید برای سرگرمی کمی با این موضوع بازی کنیم.
آیا فقط نقطه ورود مهمه؟
همونطور که قبلاً گفتم، احتمال میدم که Defender از یک اسکن حافظه برای بررسی فعالیتهای مخرب قبل از اجرا استفاده میکنه. بنابراین، آیا این اسکن حافظه، فقط ابتدای تابع رو بررسی میکنه؟ نقطه ورود تابع دقیقاً چه شکلیه؟
همونطور که قابل مشاهده هستش، در ابتدا آرگومانهای ورودی در داخل پشته قرار میگیره. اگه بعد از push r15 پچ کنیم و رجیسترهای ذخیرهشده روی پشته رو pop کنیم، سپس تابع رو با مقدار INVALID ARG برگردونیم، چه اتفاقی می افته؟
کدها به این شکل هستن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$Win32 = @" using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("kernel32")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string name); [DllImport("kernel32")] public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); } "@ Add-Type $Win32 $LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll") $Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer") $p = 0 [Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p) # POP R14 # POP R15 # POP RDI $Patch = [Byte[]] (0x41, 0x5F, 0x41, 0x5E, 0x5F, 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3) $Address = [Int64]$Address + 0x14 $new = [System.Runtime.InteropServices.Marshal] $new::Copy($Patch, 0, $Address, 11) |
نتیجه: دیگه شناسایی نمیشیم و تونستیم AMSI رو دور بزنیم.
این تأیید میکنه که این تشخیص به نقطه ورودی مربوط میشه و فقط اونجا یه جور اعتبارسنجی انجام میده. اما آیا جایگزینی برای استفاده از 0xC3 وجود داره، در صورتیکه بازگشت زودهنگام (Early Return) باعث شناسایی بشه؟ بیایید دوباره آرگومانهای ورودی رو بررسی کنیم.
ورودی سوم تابع، طول بافری است که باید اسکن بشه. اگه این مقدار رو 0 تنظیم کنیم، چه اتفاقی میافته؟ این کار باید باعث بشه که هیچ بایتی اسکن نشه، درسته؟ در نتیجه، اسکریپت یا اسمبلی ما اصلاً دیده نخواهد شد.
تابع AmsiScanBuffer مقدار ورودی رو از رجیستر r8 دریافت کرده و اونو در رجیستر edi قرار میده، به این صورت:
ما میتونیم mov edi, r8d رو با sub edi edi جایگزین کنیم، تا مقدارش رو پاک کنیم:
نتیجه دوباره نشون میده که تونستیم با موفقیت AMSI رو دور بزنیم، بدون اینکه پروسس ما خاتمه داده بشه:
نکته جالب: احتمالاً به یاد دارید که Defender قبلاً رشته های amsiscanbuffer، amsi.dll و بایتهای مربوط به پچ رو بعنوان رفتار مخرب شناسایی میکرد، درسته؟ اما این دیگه اتفاق نمیافته، چون روش جدیدی که برای شناسایی و جلوگیری از تغییر تابع AmsiScanBuffer معرفی شده، جایگزین این امضاهای قدیمی شده. اکنون، اسکن حافظه روش اصلی برای شناسایی تغییرات در این تابع است.
دو روش بایپس معرفیشده در اینجا و امضاهای حافظهای مربوط به پچهای اونا پس از انتشار این بلاگ براحتی میتونن توسط آنتی ویروسها شناسایی بشن، پس انتظار نداشته باشید که این روشها برای مدت طولانی مؤثر بمونن. اما خبر خوب اینه که دهها روش جایگزین دیگه برای پچ کردن وجود داره. فقط باید خلاق باشید و آدرس آفست و بایتهای پچ رو تغییر بدید.
6- نتیجه گیری:
بسیاری از روشهایی که چندین سال پیش برای دور زدن AMSI مورد استفاده قرار میگرفتن، امروزه هم همچنان کاربرد دارن. هنوز هم بیشتر بحث بر سر امضاهای امنیتی و روشهای دور زدن اونا از طریق تغییرات دستی یا مبهمسازی است.
ابزارهای قدیمی مبهمسازی هنوز هم توسط امضاهای عمومی پوشش داده نشدن. اما برخی از EDRها، امضاهای خاصی رو برای AMSI پیادهسازی کردن که باعث میشه برخی ابزارها بدون تغییرات، بیاثر بشن. با این حال، هنوز هم با تغییرات و مبهمسازی کافی میشه بطور کامل AMSI رو دور زد، اما بدلیل وجود پایگاهدادههای مختلف در میان آنتیویروسهای مختلف، سخت است که مطمئن شد همه ی اونارو میشه دور زد.
دستکاری DLLهای درگیر در فرایند AMSI در زمان اجرا، همچنان یکی از روشهای کلی دور زدن این مکانیزم است و باعث میشه اسکریپتها یا اسمبلی های مخرب بدون مشکل بارگذاری بشن. بایپسهای منتشر شده معمولاً از پچهای حافظه یا VEH مانند نقاط توقف سخت افزاری برای تغییر فرآیند اسکن یا مقداردهی اولیه AMSI استفاده میکنن. برخی دیگه هم روی تغییر روند بارگذاری DLLها تمرکز دارن، بویژه قبل از مقداردهی اولیه AMSI یا در پروسس های جدیداً ایجاد شده.
روش های موثر دور زدن AMSI در 2025 چیه؟ به نظر من، مؤثرترین روشها بر اساس شناساییهای رفتاری سنجیده میشن، چون تمام بایپسها رو میشه براحتی تغییر داد تا از شناسایی مبتنی بر امضا (Signature-based) فرار کنن.
پچ کردن نقطه ورود (Entry Point) توابع amsi.dll دیگه امن محسوب نمیشن، چون چندین ساله که از طریق اسکنهای حافظه که توسط رویدادهای کرنل فعال میشن، شناسایی شده.
استفاده از نقاط توقف سخت افزاری در حال حاضر هنوز یک روش OpSec امن در نظر گرفته میشه، اما برخی از EDRها در حال توسعه روشهای شناسایی رفتاری برای این تکنیک هستن.
دستکاری فرایند لوود DLL یا اجرای اولیه AMSI قبل از لوود شدن، هنوز هم از نظر رفتاری شناسایی نشده، اما فقط قبل از اجرای اولیه یا برای پروسس های جدید مؤثره.
پچ کردن در نقطه ورود دیگه امن نیست، اما پچ کردن در آفستهای خاص در amsi.dll هنوز هم گزینه مناسبیه. پچ کردن clr.dll یا سایر DLLهای مرتبط با AMSI معمولاً باعث شناسایی از طریق اسکن حافظه نمیشه.
پس آیا پچ کردن مرده؟ قطعا نه! هنوز هم پچ کردن یکی از مؤثرترین روشها برای دور زدن AMSI است.