Analysing Windows Malware on Apple Mac M1/M2 ( Windows 11 ARM ) - Part I
x86/x64 emulation internals on Windows 11 ARM
https://int0xcc.svbtle.com/apple-m2-or-windows-arm-for-malware-analysis
@reverseengine
x86/x64 emulation internals on Windows 11 ARM
https://int0xcc.svbtle.com/apple-m2-or-windows-arm-for-malware-analysis
@reverseengine
Raashid Bhat on Svbtle
Analysing Windows Malware on Apple Mac M1/M2 ( Windows 11 ARM )...
x86/x64 emulation internals on Windows 11 ARM # Introduction # Since the introduction of Intel processors for the MacBooks, malware analysis on Mac has become quite popular, and it has become the hardware of choice for malware analysts. With the...
❤2
Windows Kernel Exploitation Tutorial Part 1: Setting up the Environment
https://rootkits.xyz/blog/2017/06/kernel-setting-up
@reverseengine
https://rootkits.xyz/blog/2017/06/kernel-setting-up
@reverseengine
rootkit
Windows Kernel Exploitation Tutorial Part 1: Setting up the Environment - rootkit
Intro Recently, I had the pleasure to attend the training on Windows Kernel Exploitation at nullcon by the HackSysTeam. The training was well executed, and I got the intro into the world of kernel. But, as you know, nobody could teach you internals about…
❤2
io_uring Is Back, This Time as a Rootkit
https://www.armosec.io/blog/io_uring-rootkit-bypasses-linux-security
@reverseengine
https://www.armosec.io/blog/io_uring-rootkit-bypasses-linux-security
@reverseengine
ARMO
io_uring Rootkit Bypasses Linux Security Tools - ARMO
ARMO reveals how io_uring enables rootkits to bypass major Linux security tools like Falco, and Defender. Learn about the Curing rootkit and detection strategies.
❤1
KernelMode Rootkits: Part 1, SSDT Hooks
https://www.adlice.com/kernelmode-rootkits-part-1-ssdt-hooks
@reverseengine
https://www.adlice.com/kernelmode-rootkits-part-1-ssdt-hooks
@reverseengine
Adlice Software
KernelMode Rootkits, Part 1 | SSDT hooks • Adlice Software
KernelMode Rootkits explained. This is the first part of this rootkit writing tutorial and it covers SSDT/Shadow hooks.
❤3
رمزنگاری/انکدینگ رشته ها String Encryption
برنامه ها رشتههای متنی مثل پیامها، URLها، کلیدها رو توی فایل بهصورت رمز یا انکد نگه میدارن و فقط موقع اجرا بازشون میکنن تا کسی با نگاه کردن توی باینری پیداشون نکنه
توضیح:
دیدید یه باینری اصلا رشتهای نداره؟ احتمالا سازنده ش رشتهها رو قفل کرده یعنی مثلا «hello» تو فایل نیست چون یه تابع موقع اجرا میاد و بازش میکنه این کار براشون میتونه یه جور حفاظتی باشه یا تلاش برای مخفی کاری
مثال:
تو دیس اسمبلر میبینید هیچ رشته خوانایی نیست اما یه تابع هست که چند باره حافظه رو میسازه و داده ها رو تبدیل میکنه احتمالا رشتهها در runtime ساخته میشن
دیتکشن
نبودن رشتههای خوانا در بخش .rdata/.rodata
توابعی که مکررا حافظه allo/free میکنن و روی بافر ها عملیات بیت/بایت انجام میدن
بی نظمی بالای بخش داده ها
میتیگیشن (مدافع/برنامهنویس)
مدافع: monitor فراخوانی هایی که رشته ها رو در runtime میسازن و بررسی الگوهای غیرعادی
توسعهدهنده: از لاگینگ و کانفیگ امن استفاده کنید تا نیاز به رمزنگاری بی دلیل رشته ها کم بشه
String Encryption
Programs store text strings (such as messages, URLs, keys) in a file as a password or encoding and only open them at runtime so that no one can find them by looking in the binary
Explanation:
Did you see that a binary doesn't have a string at all? The creator probably locked the strings, meaning "hello" is not in the file because a function comes in and opens it at runtime. This could be a form of protection or an attempt at hiding.
Example:
In the disassembler, you see no readable strings, but there is a function that creates memory and converts data several times. The strings are probably created at runtime.
Detection
No readable strings in the .rdata/.rodata section
Functions that repeatedly allocate/free memory and perform bit/byte operations on buffers
High entropy in the data section
Mitigation (Defender/Programmer)
Defender: Monitor calls that create strings at runtime and check for unusual patterns
Developer: Use secure logging and configuration to reduce the need for unnecessary string encryption
@reverseengine
برنامه ها رشتههای متنی مثل پیامها، URLها، کلیدها رو توی فایل بهصورت رمز یا انکد نگه میدارن و فقط موقع اجرا بازشون میکنن تا کسی با نگاه کردن توی باینری پیداشون نکنه
توضیح:
دیدید یه باینری اصلا رشتهای نداره؟ احتمالا سازنده ش رشتهها رو قفل کرده یعنی مثلا «hello» تو فایل نیست چون یه تابع موقع اجرا میاد و بازش میکنه این کار براشون میتونه یه جور حفاظتی باشه یا تلاش برای مخفی کاری
مثال:
تو دیس اسمبلر میبینید هیچ رشته خوانایی نیست اما یه تابع هست که چند باره حافظه رو میسازه و داده ها رو تبدیل میکنه احتمالا رشتهها در runtime ساخته میشن
دیتکشن
نبودن رشتههای خوانا در بخش .rdata/.rodata
توابعی که مکررا حافظه allo/free میکنن و روی بافر ها عملیات بیت/بایت انجام میدن
بی نظمی بالای بخش داده ها
میتیگیشن (مدافع/برنامهنویس)
مدافع: monitor فراخوانی هایی که رشته ها رو در runtime میسازن و بررسی الگوهای غیرعادی
توسعهدهنده: از لاگینگ و کانفیگ امن استفاده کنید تا نیاز به رمزنگاری بی دلیل رشته ها کم بشه
String Encryption
Programs store text strings (such as messages, URLs, keys) in a file as a password or encoding and only open them at runtime so that no one can find them by looking in the binary
Explanation:
Did you see that a binary doesn't have a string at all? The creator probably locked the strings, meaning "hello" is not in the file because a function comes in and opens it at runtime. This could be a form of protection or an attempt at hiding.
Example:
In the disassembler, you see no readable strings, but there is a function that creates memory and converts data several times. The strings are probably created at runtime.
Detection
No readable strings in the .rdata/.rodata section
Functions that repeatedly allocate/free memory and perform bit/byte operations on buffers
High entropy in the data section
Mitigation (Defender/Programmer)
Defender: Monitor calls that create strings at runtime and check for unusual patterns
Developer: Use secure logging and configuration to reduce the need for unnecessary string encryption
@reverseengine
❤3
Control-flow flattening و Junk Code
توضیح:
کد ساده رو طوری مینویسن یا تبدیل میکنن که ترتیب منطقیش معلوم نباشه با جدول پریدن ها و کلی شاخه بی ربط یا کلی کد بی فایده junk میزنن تا تشخیص الگوریتم سخت شه
یادتونه یه if ساده چقدر خوندنش راحته؟ بعضیها اون if رو میکوبن توی یه جدول پریدن و چند تا case اضافه میکنن دیگه شبیه لابیرنت میشه همین کار باعث میشه خوندن جریان برنامه سخت شه
مثال:
در CFG میبینید به جای چند شاخه ساده کلی بلاک کوچک و پرش بین جدول هاست این یعنی control-flow flattening یا اضافه کردن کد بی ربط
دیتکشن
گراف کنترل جریان خیلی تودرتو و شاخه های زیاد
توابع خیلی طولانی پر از jumps و switch-like tables
کدهایی که ظاهرا کاری نمیکنن ولی اجرا میشن
میتیگیشن
آنالیزور: ترکیب static و dynamic analysis یعنی هم disasm ببینید هم اجرا کن تا بفهمید کد واقعی کدیه که در runtime فعال میشه
توسعهدهنده: مستند سازی و unit test تا اگر مجبور به obfuscation شدید حداقل تیمتون بتونه نگهش داره
Control-flow flattening and Junk Code
Explanation:
They write or transform simple code in such a way that its logical order is not clear, with jump tables and a lot of irrelevant branches or a lot of useless code, making it difficult to understand the algorithm
Remember how easy a simple if is to read? Some people throw that if in a table, jump and add a few cases, and it becomes like a labyrinth, which makes it difficult to read the program flow.
Example:
In CFG, instead of a few simple branches, you see a whole bunch of small blocks and jumps between tables. This means control-flow flattening or adding irrelevant code.
Detection
The control flow graph is very nested and has many branches.
Very long functions full of jumps and switch-like tables.
Code that doesn't seem to do anything but is executed.
Mitigation
Analyzer: A combination of static and dynamic analysis, meaning you can see both disasm and execute it to understand that the real code is the code that will be activated at runtime.
Developer: Documentation and unit testing so that if you have to obfuscate, at least your team can maintain it.
@reverseengine
توضیح:
کد ساده رو طوری مینویسن یا تبدیل میکنن که ترتیب منطقیش معلوم نباشه با جدول پریدن ها و کلی شاخه بی ربط یا کلی کد بی فایده junk میزنن تا تشخیص الگوریتم سخت شه
یادتونه یه if ساده چقدر خوندنش راحته؟ بعضیها اون if رو میکوبن توی یه جدول پریدن و چند تا case اضافه میکنن دیگه شبیه لابیرنت میشه همین کار باعث میشه خوندن جریان برنامه سخت شه
مثال:
در CFG میبینید به جای چند شاخه ساده کلی بلاک کوچک و پرش بین جدول هاست این یعنی control-flow flattening یا اضافه کردن کد بی ربط
دیتکشن
گراف کنترل جریان خیلی تودرتو و شاخه های زیاد
توابع خیلی طولانی پر از jumps و switch-like tables
کدهایی که ظاهرا کاری نمیکنن ولی اجرا میشن
میتیگیشن
آنالیزور: ترکیب static و dynamic analysis یعنی هم disasm ببینید هم اجرا کن تا بفهمید کد واقعی کدیه که در runtime فعال میشه
توسعهدهنده: مستند سازی و unit test تا اگر مجبور به obfuscation شدید حداقل تیمتون بتونه نگهش داره
Control-flow flattening and Junk Code
Explanation:
They write or transform simple code in such a way that its logical order is not clear, with jump tables and a lot of irrelevant branches or a lot of useless code, making it difficult to understand the algorithm
Remember how easy a simple if is to read? Some people throw that if in a table, jump and add a few cases, and it becomes like a labyrinth, which makes it difficult to read the program flow.
Example:
In CFG, instead of a few simple branches, you see a whole bunch of small blocks and jumps between tables. This means control-flow flattening or adding irrelevant code.
Detection
The control flow graph is very nested and has many branches.
Very long functions full of jumps and switch-like tables.
Code that doesn't seem to do anything but is executed.
Mitigation
Analyzer: A combination of static and dynamic analysis, meaning you can see both disasm and execute it to understand that the real code is the code that will be activated at runtime.
Developer: Documentation and unit testing so that if you have to obfuscate, at least your team can maintain it.
@reverseengine
❤3
Roadmap Malware Analysis
C
C++
Reverse engineering for beginners book and other corses
Assembly
Windows Internals
Win32 Api
Python
Malware analysis professional course
Zero2automated course
Sans for 610
practical malware analysis book
Malware analysis cookbook book
Mastering malware analysis packtpub book
این رودمپ رو خیلی وقت پیش خودم نوشتم برای دوستانی که میخان تحلیل بدافزار انجام بدن استفاده کنن
I wrote this roadmap a long time ago for my friends who want to do malware analysis to use
@reverseengine
C
C++
Reverse engineering for beginners book and other corses
Assembly
Windows Internals
Win32 Api
Python
Malware analysis professional course
Zero2automated course
Sans for 610
practical malware analysis book
Malware analysis cookbook book
Mastering malware analysis packtpub book
این رودمپ رو خیلی وقت پیش خودم نوشتم برای دوستانی که میخان تحلیل بدافزار انجام بدن استفاده کنن
I wrote this roadmap a long time ago for my friends who want to do malware analysis to use
@reverseengine
❤4
Windows Heap Exploitation - From Heap Overflow to Arbitrary R/W
https://mrt4ntr4.github.io/Windows-Heap-Exploitation-dadadb
@reverseengine
https://mrt4ntr4.github.io/Windows-Heap-Exploitation-dadadb
@reverseengine
mrT4ntr4's Blog
Windows Heap Exploitation - From Heap Overflow to Arbitrary R/W
TLDR I was unable to find some good writeups/blogposts on Windows user mode heap exploitation which inspired me to write an introductory but practical post on Windows heap internals and exploitati
❤5
UPX
و نمونه های پیچیده تر
فایل اصلی فشرده یا رمز میشه و Loader موقع اجرا محتوا رو آنپک میکنه پس static analysis اغلب بی فایده ست تا وقتی که unpack شدن انجام بشه
یه فایل ممکنه کوچیک باشه ولی وقتی اجرا میکنی ناگهان یه قسمت بزرگ از کد تو حافظه ظاهر میشه یعنی packed بوده مثل اینکه یه جعبه بسته رو باز کنی و داخلش یه چیز دیگه باشه
مثال:
تو header یا با نگاه کردن به اندازه امضا میتونید بفهمید packed هست در اجرای برنامه میبینید بخش ههای جدیدی توی حافظه ساخته میشه علامت unpacking
دیتکشن
امضا های packer شناخته شده توی header
افزایش ناگهانی بخشهای اجرایی در حافظه بعد از لانچ
رفتار loader در runtime که حافظه رو مینویسه و بعد jump به بخش جدید میزنه
میتیگیشن
اجرا در sandbox/VM با مانیتورینگ کامل (فایل شبکه پروسس) تا رفتار after-unpack دیده بشه
برای سازمان ها: امضای فایل ها و بررسی integrity قبل از اجرا و quarantine کردن فایل های مشکوک
UPX and more complex examples
The original file is compressed or encrypted and the Loader unpacks the content at runtime, so static analysis is often useless until unpacking is done
A file may be small, but when you run it, a large chunk of code suddenly appears in memory, meaning it was packed, like opening a closed box and there's something else inside
Example:
You can tell it's packed in the header or by looking at the size of the signature. When running the program, you'll see new sections being created in memory, a sign of unpacking
Detection
Known packer signatures in the header
Sudden increase in executable sections in memory after launch
Loader behavior at runtime that writes memory and then jumps to a new section
Mitigation
Run in a sandbox/VM with full monitoring (process network file) to see after-unpack behavior
For organizations: file signing and integrity checking before execution and quarantining suspicious files
@reverseengine
و نمونه های پیچیده تر
فایل اصلی فشرده یا رمز میشه و Loader موقع اجرا محتوا رو آنپک میکنه پس static analysis اغلب بی فایده ست تا وقتی که unpack شدن انجام بشه
یه فایل ممکنه کوچیک باشه ولی وقتی اجرا میکنی ناگهان یه قسمت بزرگ از کد تو حافظه ظاهر میشه یعنی packed بوده مثل اینکه یه جعبه بسته رو باز کنی و داخلش یه چیز دیگه باشه
مثال:
تو header یا با نگاه کردن به اندازه امضا میتونید بفهمید packed هست در اجرای برنامه میبینید بخش ههای جدیدی توی حافظه ساخته میشه علامت unpacking
دیتکشن
امضا های packer شناخته شده توی header
افزایش ناگهانی بخشهای اجرایی در حافظه بعد از لانچ
رفتار loader در runtime که حافظه رو مینویسه و بعد jump به بخش جدید میزنه
میتیگیشن
اجرا در sandbox/VM با مانیتورینگ کامل (فایل شبکه پروسس) تا رفتار after-unpack دیده بشه
برای سازمان ها: امضای فایل ها و بررسی integrity قبل از اجرا و quarantine کردن فایل های مشکوک
UPX and more complex examples
The original file is compressed or encrypted and the Loader unpacks the content at runtime, so static analysis is often useless until unpacking is done
A file may be small, but when you run it, a large chunk of code suddenly appears in memory, meaning it was packed, like opening a closed box and there's something else inside
Example:
You can tell it's packed in the header or by looking at the size of the signature. When running the program, you'll see new sections being created in memory, a sign of unpacking
Detection
Known packer signatures in the header
Sudden increase in executable sections in memory after launch
Loader behavior at runtime that writes memory and then jumps to a new section
Mitigation
Run in a sandbox/VM with full monitoring (process network file) to see after-unpack behavior
For organizations: file signing and integrity checking before execution and quarantining suspicious files
@reverseengine
❤4
تابعهایی که از stack frame استفاده نمیکنن (Leaf بدون Prologue)
پس این قسمت کلیدی هست
مثال C:
اسمبلی بهینه کامپایلر (O2):
چرا اینجا push rbp و mov rbp, rsp نداریم؟
چون:
تابع هیچ متغیر محلی نداره
تابع تابع دیگری رو فرانمیخونه (leaf)
مقدار برگشتی(return address) فقط در رجیسترها محاسبه میشه
نتیجه: کامپایلر stack frame نمیسازه
Functions that do not use stack frame (Leaf without Prologue)
So this is the key part
C example:
Compiler optimized assembly (O2):
Why don't we have push rbp and mov rbp, rsp here?
Because:
The function has no local variables
The function does not call another function (leaf)
The return value (return address) is calculated only in registers
Result: The compiler does not create a stack frame
@reverseengine
پس این قسمت کلیدی هست
مثال C:
int add5(int x) {
return x + 5;
}
اسمبلی بهینه کامپایلر (O2):
add5:
lea eax, [rdi + 5]
ret
چرا اینجا push rbp و mov rbp, rsp نداریم؟
چون:
تابع هیچ متغیر محلی نداره
تابع تابع دیگری رو فرانمیخونه (leaf)
مقدار برگشتی(return address) فقط در رجیسترها محاسبه میشه
نتیجه: کامپایلر stack frame نمیسازه
Functions that do not use stack frame (Leaf without Prologue)
So this is the key part
C example:
int add5(int x) {
return x + 5;
}
Compiler optimized assembly (O2):
add5:
lea eax, [rdi + 5]
ret
Why don't we have push rbp and mov rbp, rsp here?
Because:
The function has no local variables
The function does not call another function (leaf)
The return value (return address) is calculated only in registers
Result: The compiler does not create a stack frame
@reverseengine
❤4
نشونه ها داخل دیس اسمبلی
push rbp + mov rbp, rsp
فریم ساخته شده
sub rsp, x متغیر محلی وجود داره
دسترسی به [rbp - offset]
استفاده از متغیر محلی روی استک
call
معمولا Non-leaf (به جز Tail-call)
نبودن RBP و کار فقط با RSP
خروجی کامپایلر بهینه سازی شده است
Symbols inside the disassembly
@reverseengine
push rbp + mov rbp, rsp
فریم ساخته شده
sub rsp, x متغیر محلی وجود داره
دسترسی به [rbp - offset]
استفاده از متغیر محلی روی استک
call
معمولا Non-leaf (به جز Tail-call)
نبودن RBP و کار فقط با RSP
خروجی کامپایلر بهینه سازی شده است
Symbols inside the disassembly
push rbp + mov rbp, rsp Frame created
sub rsp, x Local variable exists
Access to [rbp - offset]
Use local variable on stack
Call is usually Non-leaf (except Tail-call)
No RBP and only works with RSP
Compiler output is optimized
@reverseengine
❤5
Virtualization-based Obfuscation Devirtualization و Kernel RE
(فقط نرمافزار)
Virtualization-based Obfuscation VMProtect / Themida
یه لایه مجازی ساز داخل باینری میذارن: کد اصلی تبدیل میشه به دستورالعمل های مخصوص VM و یه انجین در زمان اجرا اونا رو اجرا میکنه سخت میشه بفهمید اصل منطق چیه
مثال:
نمونه open-source که با ابزار obfuscator ساده بسته بندی شده رو باز کنید و ببینید بخش dispatcher چطور بین بلاک ها سوئیچ میکنه فقط ببینید و ساختار جدول پرش رو تحلیل کنید نه حذف حفاظ
دیتکشن (چی باید نگاه کنید)
وجود یک حلقه dispatcher که با جدول ایندکس ها بلاک ها رو اجرا میکنه
الگو های ثابت decode/dispatch در چند تا تابع
کاهش شدید خوانایی pseudocode اما افزایش پیچیدگی CFG
میتیگیشن (مدافع/توسعهدهنده)
برای توسعهدهندگان: از Obfuscation فقط وقتی لازم باشه استفاده کنید و مستندات داخلی رو نگه دارید
آنالیزور/مدافع: ترکیب آنالیز ایستا و دینامیک لاگ گیری runtime و trace گرفتن از dispatcher کمک میکنه تا بفهمید VM چه دستورات منطقی ای اجرا میکنه
Virtualization-based Obfuscation Devirtualization and Kernel RE
(software only)
Virtualization-based Obfuscation VMProtect / Themida
Puts a virtualization layer inside the binary: the original code is converted to VM-specific instructions and an engine executes them at runtime. It is difficult to understand the logic behind it.
Example:
Open the open-source example packaged with a simple obfuscator tool and see how the dispatcher section switches between blocks. Just look and analyze the jump table structure, not remove the protection.
Detection (what to look for)
Presence of a dispatcher loop that executes blocks with index tables.
Constant decode/dispatch patterns in several functions.
Severely reduces pseudocode readability but increases CFG complexity.
Mitigation (Defender/Developer)
For developers: Use Obfuscation only when necessary and keep internal documentation.
Analyzer/Defender: Analysis combination Static and dynamic runtime logging and dispatcher tracing help you understand what logical commands the VM is executing.
@reverseengine
(فقط نرمافزار)
Virtualization-based Obfuscation VMProtect / Themida
یه لایه مجازی ساز داخل باینری میذارن: کد اصلی تبدیل میشه به دستورالعمل های مخصوص VM و یه انجین در زمان اجرا اونا رو اجرا میکنه سخت میشه بفهمید اصل منطق چیه
مثال:
نمونه open-source که با ابزار obfuscator ساده بسته بندی شده رو باز کنید و ببینید بخش dispatcher چطور بین بلاک ها سوئیچ میکنه فقط ببینید و ساختار جدول پرش رو تحلیل کنید نه حذف حفاظ
دیتکشن (چی باید نگاه کنید)
وجود یک حلقه dispatcher که با جدول ایندکس ها بلاک ها رو اجرا میکنه
الگو های ثابت decode/dispatch در چند تا تابع
کاهش شدید خوانایی pseudocode اما افزایش پیچیدگی CFG
میتیگیشن (مدافع/توسعهدهنده)
برای توسعهدهندگان: از Obfuscation فقط وقتی لازم باشه استفاده کنید و مستندات داخلی رو نگه دارید
آنالیزور/مدافع: ترکیب آنالیز ایستا و دینامیک لاگ گیری runtime و trace گرفتن از dispatcher کمک میکنه تا بفهمید VM چه دستورات منطقی ای اجرا میکنه
Virtualization-based Obfuscation Devirtualization and Kernel RE
(software only)
Virtualization-based Obfuscation VMProtect / Themida
Puts a virtualization layer inside the binary: the original code is converted to VM-specific instructions and an engine executes them at runtime. It is difficult to understand the logic behind it.
Example:
Open the open-source example packaged with a simple obfuscator tool and see how the dispatcher section switches between blocks. Just look and analyze the jump table structure, not remove the protection.
Detection (what to look for)
Presence of a dispatcher loop that executes blocks with index tables.
Constant decode/dispatch patterns in several functions.
Severely reduces pseudocode readability but increases CFG complexity.
Mitigation (Defender/Developer)
For developers: Use Obfuscation only when necessary and keep internal documentation.
Analyzer/Defender: Analysis combination Static and dynamic runtime logging and dispatcher tracing help you understand what logical commands the VM is executing.
@reverseengine
❤5