8 countries. 8 critical sectors. One APT
Everyone talks about killing two birds with one stone
Operation Olalampo proved that Charming Kitten (Iranian APT) could hit 8 birds with one stone.
Egypt, Saudi Arabia, UAE, Turkey, Hungary, Turkmenistan, Israel, and South America.
Government, Healthcare, Financial Services, Energy, Education, Telecommunications, Defense, and Industrial.
GitHub Repository:
https://github.com/S3N4T0R-0X0/APTs-Adversary-Simulation/tree/main/Iranian%20APT/Charming%20Kitten
@reverseengine
Everyone talks about killing two birds with one stone
Operation Olalampo proved that Charming Kitten (Iranian APT) could hit 8 birds with one stone.
Egypt, Saudi Arabia, UAE, Turkey, Hungary, Turkmenistan, Israel, and South America.
Government, Healthcare, Financial Services, Energy, Education, Telecommunications, Defense, and Industrial.
GitHub Repository:
https://github.com/S3N4T0R-0X0/APTs-Adversary-Simulation/tree/main/Iranian%20APT/Charming%20Kitten
@reverseengine
GitHub
APTs-Adversary-Simulation/Iranian APT/Charming Kitten at main · S3N4T0R-0X0/APTs-Adversary-Simulation
This repository contains detailed adversary simulation APT campaigns targeting various critical sectors. Each simulation includes custom tools, C2 servers, backdoors, exploitation techniques, stage...
Forwarded from Malware, Cats and Cryptography
My first presentation in DEFCON Las Vegas. Happy to share my knowledge with the community ❤️
X/twitter
#hacking #malware #offensive #defensive #redteam #blueteam #threatintel #threathunting #research #programming #malwareanalysis
X/twitter
#hacking #malware #offensive #defensive #redteam #blueteam #threatintel #threathunting #research #programming #malwareanalysis
این یکی از مهمترین بخش های Heap هست اگر این مفهوم رو خوب یاد بگیرید خیلی از رفتارهای malloc() و free() براتون قابل پیش بینی میشه
Bin چیه و Allocator حافظههای آزاد
رو چطور مدیریت میکنه؟
در پست قبل گفتیم وقتی free() رو صدا میزنیم معمولا حافظه فورا به سیستم عامل برنمیگرده
سوال اینجاست:
پس این حافظه کجا میره؟
اینجاست که مفهوم Bin وارد میشه
Bin یعنی چی؟
به زبان ساده Bin مثل یک انبار یا لیست انتظار برای Chunk های آزاده
وقتی یک Chunk آزاد میشه Allocator اون رو دور نمیندازه بلکه داخل یکی از Bin ها قرار میده تا اگر بعدا برنامه دوباره به حافظه ای با اندازه مشابه نیاز داشت همون Chunk رو دوباره استفاده کنه
این کار باعث میشه:
سرعت malloc() بیشتر بشه
تعداد درخواست ها از سیستم عامل کمتر بشه
مصرف حافظه بهینه تر بشه
چرا چند نوع Bin وجود داره؟
همهی Chunk ها اندازه یکسانی ندارن
مثلا ممکنه یک برنامه هم 32 بایت حافظه بخاد هم 512 بایت و هم چند کیلوبایت
اگر همهی Chunk ها داخل یک لیست قرار بگیرن پیدا کردن Chunk مناسب زمان زیادی میبره به همین دلیل Allocator اونا رو بر اساس اندازه دسته بندی میکنه
انواع Bin در glibc
در نسخههای امروزی glibc معمولاً با این Binها رو به رو میشیم:
🔹 Tcache
جدیدترین و سریعترین بخش
هر Thread یک Tcache مخصوص خودش داره وقتی Chunkهای کوچیک آزاد میشن معمولا اول وارد Tcache میشن تا اگر دوباره همون اندازه نیاز شد خیلی سریع استفاده بشن
هدف اصلی Tcache افزایش سرعت برنامه هست
🔹 Fast Bin
برای Chunkهای کوچیک استفاده میشه
ویژگی مهم Fast Bin اینه که هنگام آزاد شدن Chunkها عملیات ادغام (Coalescing) بلافاصله انجام نمیشه
این موضوع سرعت رو بالا میبره اما مدیریت حافظه رو کمی پیچیده تر میکنه
🔹 Unsorted Bin
وقتی بعضی Chunk ها آزاد میشن اول وارد Unsorted Bin میشن
بعدا Allocator تصمیم میگیره اونها رو به Bin مناسب منتقل کنه
میشه گفت Unsorted Bin یک محل موقت برای Chunk های آزاده
🔹 Small Bin
برای Chunk هایی با اندازه مشخص و نسبتا کوچیک استفاده میشه
چون اندازه ها مشخصن پیدا کردن Chunk مناسب سریع انجام میشه
🔹 Large Bin
برای Chunk های بزرگ تر استفاده میشه
اینجا Allocator باید دقت بیشتری داشته باشه تا بهترین Chunk رو برای درخواست جدید انتخاب کنه
چرا شناخت Bin ها مهمه؟
چون رفتار malloc() و free() کاملا به همین ساختارها وابسته ست
وقتی یک برنامه حافظه درخواست میکنه Allocator اول بررسی میکنه که آیا داخل Bin ها Chunk مناسبی وجود داره یا نه
اگر پیدا بشه همون رو برمیگردونه
اگر پیدا نشه از Heap یا در بعضی شرایط از سیستم عامل حافظه جدید میگیره
آیا همیشه از سیستم عامل حافظه جدید گرفته میشه؟ خیر
در بیشتر مواقع Allocator سعی میکنه از حافظه هایی که قبلا آزاد شدن استفاده کنه
به همین دلیل ممکن است دو بار malloc() پشت سر هم همون آدرسی رو برگردونه که قبلا با free() آزاد شده بود این رفتار کاملا طبیعیه و برای افزایش کارایی انجام میشه
Bin
ها محل نگهداری Chunk های آزادن Allocator با استفاده از اونها تلاش میکنه بدون درخواست مداوم حافظه از سیستم عامل حافظه های آزاد شده رو دوباره استفاده کنه همین طراحی باعث شده Heap هم سریع تر باشد و هم پیچیده تر از Stack
@reverseengine
Bin چیه و Allocator حافظههای آزاد
رو چطور مدیریت میکنه؟
در پست قبل گفتیم وقتی free() رو صدا میزنیم معمولا حافظه فورا به سیستم عامل برنمیگرده
سوال اینجاست:
پس این حافظه کجا میره؟
اینجاست که مفهوم Bin وارد میشه
Bin یعنی چی؟
به زبان ساده Bin مثل یک انبار یا لیست انتظار برای Chunk های آزاده
وقتی یک Chunk آزاد میشه Allocator اون رو دور نمیندازه بلکه داخل یکی از Bin ها قرار میده تا اگر بعدا برنامه دوباره به حافظه ای با اندازه مشابه نیاز داشت همون Chunk رو دوباره استفاده کنه
این کار باعث میشه:
سرعت malloc() بیشتر بشه
تعداد درخواست ها از سیستم عامل کمتر بشه
مصرف حافظه بهینه تر بشه
چرا چند نوع Bin وجود داره؟
همهی Chunk ها اندازه یکسانی ندارن
مثلا ممکنه یک برنامه هم 32 بایت حافظه بخاد هم 512 بایت و هم چند کیلوبایت
اگر همهی Chunk ها داخل یک لیست قرار بگیرن پیدا کردن Chunk مناسب زمان زیادی میبره به همین دلیل Allocator اونا رو بر اساس اندازه دسته بندی میکنه
انواع Bin در glibc
در نسخههای امروزی glibc معمولاً با این Binها رو به رو میشیم:
🔹 Tcache
جدیدترین و سریعترین بخش
هر Thread یک Tcache مخصوص خودش داره وقتی Chunkهای کوچیک آزاد میشن معمولا اول وارد Tcache میشن تا اگر دوباره همون اندازه نیاز شد خیلی سریع استفاده بشن
هدف اصلی Tcache افزایش سرعت برنامه هست
🔹 Fast Bin
برای Chunkهای کوچیک استفاده میشه
ویژگی مهم Fast Bin اینه که هنگام آزاد شدن Chunkها عملیات ادغام (Coalescing) بلافاصله انجام نمیشه
این موضوع سرعت رو بالا میبره اما مدیریت حافظه رو کمی پیچیده تر میکنه
🔹 Unsorted Bin
وقتی بعضی Chunk ها آزاد میشن اول وارد Unsorted Bin میشن
بعدا Allocator تصمیم میگیره اونها رو به Bin مناسب منتقل کنه
میشه گفت Unsorted Bin یک محل موقت برای Chunk های آزاده
🔹 Small Bin
برای Chunk هایی با اندازه مشخص و نسبتا کوچیک استفاده میشه
چون اندازه ها مشخصن پیدا کردن Chunk مناسب سریع انجام میشه
🔹 Large Bin
برای Chunk های بزرگ تر استفاده میشه
اینجا Allocator باید دقت بیشتری داشته باشه تا بهترین Chunk رو برای درخواست جدید انتخاب کنه
چرا شناخت Bin ها مهمه؟
چون رفتار malloc() و free() کاملا به همین ساختارها وابسته ست
وقتی یک برنامه حافظه درخواست میکنه Allocator اول بررسی میکنه که آیا داخل Bin ها Chunk مناسبی وجود داره یا نه
اگر پیدا بشه همون رو برمیگردونه
اگر پیدا نشه از Heap یا در بعضی شرایط از سیستم عامل حافظه جدید میگیره
آیا همیشه از سیستم عامل حافظه جدید گرفته میشه؟ خیر
در بیشتر مواقع Allocator سعی میکنه از حافظه هایی که قبلا آزاد شدن استفاده کنه
به همین دلیل ممکن است دو بار malloc() پشت سر هم همون آدرسی رو برگردونه که قبلا با free() آزاد شده بود این رفتار کاملا طبیعیه و برای افزایش کارایی انجام میشه
Bin
ها محل نگهداری Chunk های آزادن Allocator با استفاده از اونها تلاش میکنه بدون درخواست مداوم حافظه از سیستم عامل حافظه های آزاد شده رو دوباره استفاده کنه همین طراحی باعث شده Heap هم سریع تر باشد و هم پیچیده تر از Stack
@reverseengine
ReverseEngineering
این یکی از مهمترین بخش های Heap هست اگر این مفهوم رو خوب یاد بگیرید خیلی از رفتارهای malloc() و free() براتون قابل پیش بینی میشه Bin چیه و Allocator حافظههای آزاد رو چطور مدیریت میکنه؟ در پست قبل گفتیم وقتی free() رو صدا میزنیم معمولا حافظه فورا به…
This is one of the most important parts of the Heap. If you learn this concept well, many of the behaviors of malloc() and free() will be predictable for you.
What is Bin and how does Allocator manage freed memory?
In the previous post, we said that when we call free(), the memory is usually not returned to the operating system immediately.
The question is:
So where does this memory go?
This is where the concept of Bin comes in.
What does Bin mean?
In simple terms, Bin is like a warehouse or waiting list for freed Chunks.
When a Chunk is freed, the Allocator does not throw it away, but places it in one of the Bins so that if the program needs memory of the same size again later, it can reuse the same Chunk.
This will:
Increase the speed of malloc().
Reduce the number of requests from the operating system.
Optimize memory usage.
Why are there several types of Bins?
Not all chunks are the same size
For example, a program may need 32 bytes of memory, 512 bytes, or a few kilobytes
If all the chunks are in a list, finding the right chunk will take a long time, so the Allocator sorts them by size
Types of Bins in glibc
In today's versions of glibc, we usually encounter these bins:
🔹 Tcache
The newest and fastest part
Each thread has its own Tcache. When small chunks are freed, they usually enter Tcache first so that if the same size is needed again, they can be used very quickly
The main purpose of Tcache is to increase the speed of the program
🔹 Fast Bin
It is used for small chunks
The important feature of Fast Bin is that when the chunks are freed, the coalescing operation is not performed immediately
This increases speed, but makes memory management a little more complicated
🔹 Unsorted Bin
When some chunks are freed, they enter Tcache first Unsorted Bin
Later, the Allocator decides to move them to the appropriate Bin
You can say that the Unsorted Bin is a temporary place for free Chunks
🔹 Small Bin
Used for Chunks of a specific and relatively small size
Since the sizes are specific, finding the appropriate Chunk is done quickly
🔹 Large Bin
Used for larger Chunks
Here the Allocator must be more careful to choose the best Chunk for the new request
Why is it important to know the Bins?
Because the behavior of malloc() and free() is completely dependent on these structures
When a program requests memory, the Allocator first checks whether there is a suitable Chunk in the Bins or not
If it is found, it returns it
If not found, it gets new memory from the Heap or in some cases from the operating system
Is new memory always taken from the operating system? No
In most cases, the Allocator tries to use previously freed memory
That is why malloc() may return the same address twice in a row that was previously freed with free(). This behavior is completely normal and is done to increase performance
Bins are where freed chunks are stored. The Allocator uses them to try to reuse freed memory without constantly requesting memory from the operating system. This design makes the Heap both faster and more complex than the Stack
@reverseengine
What is Bin and how does Allocator manage freed memory?
In the previous post, we said that when we call free(), the memory is usually not returned to the operating system immediately.
The question is:
So where does this memory go?
This is where the concept of Bin comes in.
What does Bin mean?
In simple terms, Bin is like a warehouse or waiting list for freed Chunks.
When a Chunk is freed, the Allocator does not throw it away, but places it in one of the Bins so that if the program needs memory of the same size again later, it can reuse the same Chunk.
This will:
Increase the speed of malloc().
Reduce the number of requests from the operating system.
Optimize memory usage.
Why are there several types of Bins?
Not all chunks are the same size
For example, a program may need 32 bytes of memory, 512 bytes, or a few kilobytes
If all the chunks are in a list, finding the right chunk will take a long time, so the Allocator sorts them by size
Types of Bins in glibc
In today's versions of glibc, we usually encounter these bins:
🔹 Tcache
The newest and fastest part
Each thread has its own Tcache. When small chunks are freed, they usually enter Tcache first so that if the same size is needed again, they can be used very quickly
The main purpose of Tcache is to increase the speed of the program
🔹 Fast Bin
It is used for small chunks
The important feature of Fast Bin is that when the chunks are freed, the coalescing operation is not performed immediately
This increases speed, but makes memory management a little more complicated
🔹 Unsorted Bin
When some chunks are freed, they enter Tcache first Unsorted Bin
Later, the Allocator decides to move them to the appropriate Bin
You can say that the Unsorted Bin is a temporary place for free Chunks
🔹 Small Bin
Used for Chunks of a specific and relatively small size
Since the sizes are specific, finding the appropriate Chunk is done quickly
🔹 Large Bin
Used for larger Chunks
Here the Allocator must be more careful to choose the best Chunk for the new request
Why is it important to know the Bins?
Because the behavior of malloc() and free() is completely dependent on these structures
When a program requests memory, the Allocator first checks whether there is a suitable Chunk in the Bins or not
If it is found, it returns it
If not found, it gets new memory from the Heap or in some cases from the operating system
Is new memory always taken from the operating system? No
In most cases, the Allocator tries to use previously freed memory
That is why malloc() may return the same address twice in a row that was previously freed with free(). This behavior is completely normal and is done to increase performance
Bins are where freed chunks are stored. The Allocator uses them to try to reuse freed memory without constantly requesting memory from the operating system. This design makes the Heap both faster and more complex than the Stack
@reverseengine
LLMs Have Reshaped How We Think About Decompilation and Collaboration
https://hex-rays.com/blog/llms-have-reshaped-how-we-think-about-decompilation-and-collaboration
@reverseengine
https://hex-rays.com/blog/llms-have-reshaped-how-we-think-about-decompilation-and-collaboration
@reverseengine
Hex-Rays
LLMs Have Reshaped How We Think About Decompilation and Collaboration
How AI agents are reshaping reverse engineering, from decompiler collaboration to the way we approach hacking challenges.
A 0-click exploit chain for the Pixel 10: When a Door Closes, a Window Opens
https://projectzero.google/2026/05/pixel-10-exploit.html
@reverseengine
https://projectzero.google/2026/05/pixel-10-exploit.html
@reverseengine
projectzero.google
A 0-click exploit chain for the Pixel 10: When a Door Closes, a Window Opens
We recently published an exploit chain for the Google Pixel 9 that demonstrated it was possible t...
On the Effectiveness of Mutational Grammar Fuzzing
https://projectzero.google/2026/03/mutational-grammar-fuzzing.html
@reverseengine
https://projectzero.google/2026/03/mutational-grammar-fuzzing.html
@reverseengine
projectzero.google
On the Effectiveness of Mutational Grammar Fuzzing
Mutational grammar fuzzing is a fuzzing technique in which the fuzzer uses a predefined grammar t...
On the clock: Escaping VMware Workstation at Pwn2Own Berlin 2025
https://www.synacktiv.com/publications/on-the-clock-escaping-vmware-workstation-at-pwn2own-berlin-2025
@reverseengine
https://www.synacktiv.com/publications/on-the-clock-escaping-vmware-workstation-at-pwn2own-berlin-2025
@reverseengine
Synacktiv
On the clock: Escaping VMware Workstation at Pwn2Own Berlin 2025
Exploring GrapheneOS secure allocator: Hardened Malloc
https://www.synacktiv.com/publications/exploring-grapheneos-secure-allocator-hardened-malloc
@reverseengine
https://www.synacktiv.com/publications/exploring-grapheneos-secure-allocator-hardened-malloc
@reverseengine
Synacktiv
Exploring GrapheneOS secure allocator: Hardened Malloc
SakDriver: Reversing a Kernel Driver Rootkit
https://0xsec.gitbook.io/0xsec/malware-analysis/sakdriver-reversing-a-kernel-driver-rootkit
@reverseengine
https://0xsec.gitbook.io/0xsec/malware-analysis/sakdriver-reversing-a-kernel-driver-rootkit
@reverseengine
0xsec.gitbook.io
SakDriver: Reversing a Kernel Driver Rootkit | 0xSec
Proxmox Virtual Environment now available for 64-bit ARM
https://forum.proxmox.com/threads/proxmox-virtual-environment-now-available-for-64-bit-arm-arm64.185526
@reverseengine
https://forum.proxmox.com/threads/proxmox-virtual-environment-now-available-for-64-bit-arm-arm64.185526
@reverseengine
Proxmox Support Forum
Proxmox Virtual Environment now available for 64-bit ARM (arm64)!
We are excited to announce the first release of Proxmox Virtual Environment with official support for a second CPU architecture: 64-bit ARM (arm64/aarch64). Until now, Proxmox VE was available for...
IDA pro 9.4
Linux + Windows + Mac + ARM
download
@reverseengine
Linux + Windows + Mac + ARM
download
tree "/home/data/0x01/IDA/IDA pro 9.4/"
/home/reeves/data/soft/IDA/IDA pro 9.4/
├── ida-pro_94_armlinux.run
├── ida-pro_94_armmac.app.zip
├── ida-pro_94_armwin.exe
├── ida-pro_94_x64linux.run
├── ida-pro_94_x64mac.app.zip
├── ida-pro_94_x64win.exe
├── kg_patch
│ ├── idapro.hexlic
│ ├── keygen.js
│ ├── README
│ ├── x64linux
│ │ ├── libida32.so
│ │ └── libida.so
│ └── x64win
│ ├── ida32.dll
│ └── ida.dll
└── misc
├── hexlicsrv94_x64linux.run
├── hexvault94_x64linux.run
├── idapin94.zip
└── lumina94_x64linux.run
5 directories, 17 files
@reverseengine
🔥3
Control Flow Flattening
وقتی مسیر اجرای برنامه عمدا به هم ریخته میشه
یکی از رایجترین تکنیکهایی که هم توی محافظ های نرم افزاری و هم توی بعضی بدافزار ها دیده میشه Control Flow Flattening هست
هدفش فقط یک چیزه
اینکه نفهمید برنامه از کجا شروع شده و قراره به کجا بره
فرض کنید کد اصلی این باشه:
مسیر اجرای این کد خیلی واضحه
یا وارد A() میشه یا B() و بعد C() اجرا میشه
حالا همین منطق رو با Control Flow Flattening مبهم میکنیم
به جای اینکه اجرای برنامه مستقیم جلو بره همه چیز وارد یک حلقه بزرگ میشه
داخل اون حلقه فقط یک متغیر مشخص میکنه مرحله بعدی چیه
مثلا چیزی شبیه این:
اینجا دیگه ترتیب واقعی اجرای برنامه مشخص نیست
همه چیز داخل یک حلقه و یک switch بزرگ مخفی شده
به همین خاطر وقتی فایل رو داخل IDA یا Ghidra باز میکنید نمودار Control Flow خیلی شلوغ و عجیب به نظر میرسه
به جای اینکه چند مسیر ساده ببینید ده ها مسیر مختلف میبینید که همشون دوباره به یک نقطه برمیگردن
یکی از نشونههای Control Flow Flattening همین حلقه مرکزیه
تقریبا تمام بلوک های برنامه بعد از اجرا دوباره به همون حلقه برمیگردن و منتظر تصمیم بعدی میمونن
کاری که تحلیلگر انجام میده اینه که به جای دنبال کردن ظاهر کد تغییرات متغیر state رو دنبال میکنه
چون این متغیر مشخص میکنه بعد از هر مرحله برنامه واقعا قراره کجا بره
وقتی مسیر تغییر state رو روی کاغذ رسم کنید کم کم مسیر واقعی اجرای برنامه دوباره مشخص میشه
در واقع هدف تحلیلگر اینه که این ساختار مبهم رو دوباره به همون if و while و for های ساده اولیه تبدیل کنه
به این کار Deflattening میگن
یعنی برگردوندن مسیر اجرای برنامه به حالت طبیعی
تمرین:
یک برنامه خیلی ساده بنویسید که سه مرحله داشته باشه
ابتدا مقداردهی اولیه
بعد انجام یک محاسبه
در اخر چاپ نتیجه
حالا بدون استفاده از if یا اجرای مستقیم این سه مرحله رو فقط با یک متغیر state و یک switch اجرا کنید
بعد سعی کنید مسیر اجرای برنامه رو فقط با دنبال کردن تغییرات state روی کاغذ رسم کنید
وقتی این تمرین رو انجام بدید مفهوم Control Flow Flattening رو خیلی بهتر درک میکنید
وقتی مسیر اجرای برنامه عمدا به هم ریخته میشه
یکی از رایجترین تکنیکهایی که هم توی محافظ های نرم افزاری و هم توی بعضی بدافزار ها دیده میشه Control Flow Flattening هست
هدفش فقط یک چیزه
اینکه نفهمید برنامه از کجا شروع شده و قراره به کجا بره
فرض کنید کد اصلی این باشه:
if (x > 10)
A();
else
B();
C();
مسیر اجرای این کد خیلی واضحه
یا وارد A() میشه یا B() و بعد C() اجرا میشه
حالا همین منطق رو با Control Flow Flattening مبهم میکنیم
به جای اینکه اجرای برنامه مستقیم جلو بره همه چیز وارد یک حلقه بزرگ میشه
داخل اون حلقه فقط یک متغیر مشخص میکنه مرحله بعدی چیه
مثلا چیزی شبیه این:
while (1)
{
switch(state)
{
case 0:
...
state = 3;
break;
case 3:
...
state = 7;
break;
case 7:
...
return;
}
}
اینجا دیگه ترتیب واقعی اجرای برنامه مشخص نیست
همه چیز داخل یک حلقه و یک switch بزرگ مخفی شده
به همین خاطر وقتی فایل رو داخل IDA یا Ghidra باز میکنید نمودار Control Flow خیلی شلوغ و عجیب به نظر میرسه
به جای اینکه چند مسیر ساده ببینید ده ها مسیر مختلف میبینید که همشون دوباره به یک نقطه برمیگردن
یکی از نشونههای Control Flow Flattening همین حلقه مرکزیه
تقریبا تمام بلوک های برنامه بعد از اجرا دوباره به همون حلقه برمیگردن و منتظر تصمیم بعدی میمونن
کاری که تحلیلگر انجام میده اینه که به جای دنبال کردن ظاهر کد تغییرات متغیر state رو دنبال میکنه
چون این متغیر مشخص میکنه بعد از هر مرحله برنامه واقعا قراره کجا بره
وقتی مسیر تغییر state رو روی کاغذ رسم کنید کم کم مسیر واقعی اجرای برنامه دوباره مشخص میشه
در واقع هدف تحلیلگر اینه که این ساختار مبهم رو دوباره به همون if و while و for های ساده اولیه تبدیل کنه
به این کار Deflattening میگن
یعنی برگردوندن مسیر اجرای برنامه به حالت طبیعی
تمرین:
یک برنامه خیلی ساده بنویسید که سه مرحله داشته باشه
ابتدا مقداردهی اولیه
بعد انجام یک محاسبه
در اخر چاپ نتیجه
حالا بدون استفاده از if یا اجرای مستقیم این سه مرحله رو فقط با یک متغیر state و یک switch اجرا کنید
بعد سعی کنید مسیر اجرای برنامه رو فقط با دنبال کردن تغییرات state روی کاغذ رسم کنید
وقتی این تمرین رو انجام بدید مفهوم Control Flow Flattening رو خیلی بهتر درک میکنید
❤2
ReverseEngineering
Control Flow Flattening وقتی مسیر اجرای برنامه عمدا به هم ریخته میشه یکی از رایجترین تکنیکهایی که هم توی محافظ های نرم افزاری و هم توی بعضی بدافزار ها دیده میشه Control Flow Flattening هست هدفش فقط یک چیزه اینکه نفهمید برنامه از کجا شروع شده و قراره…
Control Flow Flattening
When the program execution path is deliberately messed up
One of the most common techniques seen in both software protectors and some malware is Control Flow Flattening
Its goal is only one thing
To make it difficult to understand where the program started and where it is going to go
Suppose the original code is this:
The execution path of this code is very clear
Either it enters A() or B() and then C() is executed
Now we obfuscate this logic with Control Flow Flattening
Instead of the program execution proceeding straight ahead, everything enters a big loop
Inside that loop, only one variable specifies what the next step is
For example, something like this:
Here the actual order of program execution is no longer clear
Everything is hidden inside a loop and a big switch
That's why when you open the file in IDA or Ghidra, the Control Flow diagram looks very busy and strange
Instead of seeing a few simple paths, you see dozens of different paths that all return to the same point
One of the signs of Control Flow Flattening is this central loop
Almost all blocks of the program return to the same loop after execution and wait for the next decision
What the analyzer does is that instead of following the appearance of the code, it follows the changes of the state variable
Because this variable determines where the program is really going to go after each step
When you draw the path of state changes on paper, the actual path of program execution gradually becomes clear again
In fact, the analyzer's goal is to convert this ambiguous structure back to the same simple if, while, and for statements
This is called Deflating
That is, returning the program execution path to the state Natural
Exercise:
Write a very simple program that has three steps
First initialize
Then perform a calculation
Finally print the result
Now, without using if or direct execution, execute these three steps with just a state variable and a switch
Then try to draw the execution path of the program on paper just by following the state changes
When you do this exercise, you will understand the concept of Control Flow Flattening much better
@reverseengine
When the program execution path is deliberately messed up
One of the most common techniques seen in both software protectors and some malware is Control Flow Flattening
Its goal is only one thing
To make it difficult to understand where the program started and where it is going to go
Suppose the original code is this:
if (x > 10)
A();
else
B();
C();
The execution path of this code is very clear
Either it enters A() or B() and then C() is executed
Now we obfuscate this logic with Control Flow Flattening
Instead of the program execution proceeding straight ahead, everything enters a big loop
Inside that loop, only one variable specifies what the next step is
For example, something like this:
while (1)
{
switch(state)
{
case 0:
...
state = 3;
break;
case 3:
...
state = 7;
break;
Case 7:
...
return;
}
}
Here the actual order of program execution is no longer clear
Everything is hidden inside a loop and a big switch
That's why when you open the file in IDA or Ghidra, the Control Flow diagram looks very busy and strange
Instead of seeing a few simple paths, you see dozens of different paths that all return to the same point
One of the signs of Control Flow Flattening is this central loop
Almost all blocks of the program return to the same loop after execution and wait for the next decision
What the analyzer does is that instead of following the appearance of the code, it follows the changes of the state variable
Because this variable determines where the program is really going to go after each step
When you draw the path of state changes on paper, the actual path of program execution gradually becomes clear again
In fact, the analyzer's goal is to convert this ambiguous structure back to the same simple if, while, and for statements
This is called Deflating
That is, returning the program execution path to the state Natural
Exercise:
Write a very simple program that has three steps
First initialize
Then perform a calculation
Finally print the result
Now, without using if or direct execution, execute these three steps with just a state variable and a switch
Then try to draw the execution path of the program on paper just by following the state changes
When you do this exercise, you will understand the concept of Control Flow Flattening much better
@reverseengine
❤3
Hook Detection
و مفهوم EDR Hooking
یکی از پایه ای ترین چیز هایی که برای فهم بایپس EDR باید بدونید Hook هست وقتی یک EDR بخواد رفتار یک برنامه رو زیر نظر بگیره یکی از مکانیزم هایی که ممکنه استفاده کنه اینه که مسیر اجرای بعضی Function ها رو تحت نظر بگیره
مثلا بهصورت مفهومی:
Application
↓
Windows API
↓
EDR Monitoring
↓
Native API
↓
Kernel
یعنی برنامه فکر میکنه یک تابع معمولی رو صدا زده ولی قبل از رسیدن به مسیر اصلی یک لایه ی مانیتورینگ میتونه فعالیت رو بررسی کنه
Inline Hook
در Inline Hook ابتدای یک Function تغییر میکنه تا اجرای برنامه به مسیر دیگه ای هدایت بشه:
Original:
Function
├── Instruction 1
├── Instruction 2
├── Instruction 3
Hooked:
Function
│
└── Jump ──────► Monitoring Code
│
▼
Original Code
به همین دلیل وقتی درباره تکنیک هایی مثل Unhooking, Direct Syscall و Indirect Syscall میخونید باید اول دقیقا بفهمید Hook چه مشکلی ایجاد میکنه
نکته مهم
Hook
شدن به معنای اینه که EDR تمام سیستم رو از طریق همین روش میبینه نیست
EDR
های مدرن فقط به یک Hook وابسته نیستن و میتونن از چندین منبع telemetry استفاده کنن
برای همین این زنجیره رو باید اینطوری ببینید:
API Hook
+
ETW
+
Kernel Telemetry
+
Process Behavior
+
Memory Analysis
+
Network Telemetry
و این دقیقا دلیل پیچیده شدن بحث AV/EDR Evasion در سال های اخیر شده
@reverseengine
Hook Detection And the Concept of EDR Hooking
One of the most basic things you need to know to understand EDR bypass is Hook. When an EDR wants to monitor the behavior of an application, one of the mechanisms it may use is to monitor the execution path of some Function
For example, conceptually:
Application
↓
Windows API
↓
EDR Monitoring
↓
Native API
↓
Kernel
That is, the application thinks it has called a normal function, but before reaching the main path, a monitoring layer can check the activity
Inline Hook
In an Inline Hook, the beginning of a Function is changed to redirect the execution of the application to another path:
Original:
Function
├── Instruction 1
├── Instruction 2
├── Instruction 3
Hooked:
Function
│
└── Jump ──────► Monitoring Code
│
▼
Original Code
That is why when you read about techniques such as Unhooking, Direct Syscall and Indirect Syscall, you should First, understand exactly what the problem is with Hooks
Important point
Being Hooked
does not mean that EDR sees the entire system in this way
Modern EDRs do not rely on just one Hook and can use multiple telemetry sources
So you should think of this chain as:
API Hook
+
ETW
+
Kernel Telemetry
+
Process Behavior
+
Memory Analysis
+
Network Telemetry
And this is exactly why the AV/EDR Evasion discussion has become so complicated in recent years
@reverseengine
و مفهوم EDR Hooking
یکی از پایه ای ترین چیز هایی که برای فهم بایپس EDR باید بدونید Hook هست وقتی یک EDR بخواد رفتار یک برنامه رو زیر نظر بگیره یکی از مکانیزم هایی که ممکنه استفاده کنه اینه که مسیر اجرای بعضی Function ها رو تحت نظر بگیره
مثلا بهصورت مفهومی:
Application
↓
Windows API
↓
EDR Monitoring
↓
Native API
↓
Kernel
یعنی برنامه فکر میکنه یک تابع معمولی رو صدا زده ولی قبل از رسیدن به مسیر اصلی یک لایه ی مانیتورینگ میتونه فعالیت رو بررسی کنه
Inline Hook
در Inline Hook ابتدای یک Function تغییر میکنه تا اجرای برنامه به مسیر دیگه ای هدایت بشه:
Original:
Function
├── Instruction 1
├── Instruction 2
├── Instruction 3
Hooked:
Function
│
└── Jump ──────► Monitoring Code
│
▼
Original Code
به همین دلیل وقتی درباره تکنیک هایی مثل Unhooking, Direct Syscall و Indirect Syscall میخونید باید اول دقیقا بفهمید Hook چه مشکلی ایجاد میکنه
نکته مهم
Hook
شدن به معنای اینه که EDR تمام سیستم رو از طریق همین روش میبینه نیست
EDR
های مدرن فقط به یک Hook وابسته نیستن و میتونن از چندین منبع telemetry استفاده کنن
برای همین این زنجیره رو باید اینطوری ببینید:
API Hook
+
ETW
+
Kernel Telemetry
+
Process Behavior
+
Memory Analysis
+
Network Telemetry
و این دقیقا دلیل پیچیده شدن بحث AV/EDR Evasion در سال های اخیر شده
@reverseengine
Hook Detection And the Concept of EDR Hooking
One of the most basic things you need to know to understand EDR bypass is Hook. When an EDR wants to monitor the behavior of an application, one of the mechanisms it may use is to monitor the execution path of some Function
For example, conceptually:
Application
↓
Windows API
↓
EDR Monitoring
↓
Native API
↓
Kernel
That is, the application thinks it has called a normal function, but before reaching the main path, a monitoring layer can check the activity
Inline Hook
In an Inline Hook, the beginning of a Function is changed to redirect the execution of the application to another path:
Original:
Function
├── Instruction 1
├── Instruction 2
├── Instruction 3
Hooked:
Function
│
└── Jump ──────► Monitoring Code
│
▼
Original Code
That is why when you read about techniques such as Unhooking, Direct Syscall and Indirect Syscall, you should First, understand exactly what the problem is with Hooks
Important point
Being Hooked
does not mean that EDR sees the entire system in this way
Modern EDRs do not rely on just one Hook and can use multiple telemetry sources
So you should think of this chain as:
API Hook
+
ETW
+
Kernel Telemetry
+
Process Behavior
+
Memory Analysis
+
Network Telemetry
And this is exactly why the AV/EDR Evasion discussion has become so complicated in recent years
@reverseengine