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
Opaque Predicate
شرط هایی که ظاهرشون گمراه کننده ست
حالا یکی از تکنیک هایی رو که میخایم بررسی کنیم که معمولا کنار Obfuscation استفاده میشه
Opaque Predicate
یعنی برنامه یک شرط میسازه که از ظاهرش مشخص نیست نتیجه همیشه چی میشه ولی سازنده از قبل میدونه نتیجه چیه
مثلا از نظر منطقی ممکنه چنین چیزی داشته باشیم:
اگه مقدار
مثلا ممکنه به جای یک شرط ساده چند عملیات پشت سر هم ببینید:
محاسبه یک مقدار
Decompiler
هم ممکنه از این عملیات یک شرط خیلی پیچیده بسازه اینجاست که تحلیلگر باید فقط به ظاهر شرط اعتماد نکنه
باید بفهمه آیا هر دو مسیر واقعا قابل اجرا هستن یا یکی از مسیرها عملا هیچوقت اتفاق نمیوفته
فرض کنید به چنین ساختاری رسیدید:
شرط:
/ \ مسیرA
/ \ مسیر B
\ / ادامه
اولین سوال این نیست که کدوم مسیر بهتر به نظر میرسه
سوال اینه:
مسیر B اصلا قابل رسیدنه؟
اگر جواب نه باشه احتمالا با یک Opaque Predicate یا یک شرط غیرقابل وقوع طرف هستیم
یکی از کاربردهای این تکنیک شلوغ کردن Control Flow Graph هست
تحلیلگر وقتی نمودار رو باز میکنه تعداد زیادی مسیر میبینه
اما بخشی از این مسیرها فقط برای گمراه کردن تحلیل ایجاد شدن
نکته مهم اینه که Opaque Predicate همیشه به معنی یک شرط ثابت مثل true یا false نیست
بعضی وقتا نتیجه شرط به یک invariant وابسته ست
یعنی مقداری که با وجود تغییرات مختلف برنامه یک ویژگی مشخص رو حفظ میکنه
برای همین شما باید منطق ریاضی و رفتار داده ها رو هم بررسی کنید
تمرین
این شرط رو بررسی کنید:
بدون اجرای برنامه مشخص کنید کدوم مسیر میتونه اجرا بشه بعد همین ایده رو با یک شرط پیچیده تر امتحان کنید و ببینید میتونید از روی منطق ریاضی تشخیص بدید کدوم شاخه عملا غیرقابلاجراست
این دقیقا همون ذهنیتی هست که برای تحلیل Obfuscation لازم داریم
@reverseengine
شرط هایی که ظاهرشون گمراه کننده ست
حالا یکی از تکنیک هایی رو که میخایم بررسی کنیم که معمولا کنار Obfuscation استفاده میشه
Opaque Predicate
یعنی برنامه یک شرط میسازه که از ظاهرش مشخص نیست نتیجه همیشه چی میشه ولی سازنده از قبل میدونه نتیجه چیه
مثلا از نظر منطقی ممکنه چنین چیزی داشته باشیم:
int x = 10;
if ((x * x) % 2 == 0)
{
A();
}
else
{
B();
}
اگه مقدار
x همیشه 10 باشه شرط همیشه درست میشه ولی وقتی همین منطق به اسمبلی تبدیل و با محاسبات اضافه قاطی بشه تشخیصش سخت تر میشهمثلا ممکنه به جای یک شرط ساده چند عملیات پشت سر هم ببینید:
محاسبه یک مقدار
XOR
ADD
CMP
JZ
Decompiler
هم ممکنه از این عملیات یک شرط خیلی پیچیده بسازه اینجاست که تحلیلگر باید فقط به ظاهر شرط اعتماد نکنه
باید بفهمه آیا هر دو مسیر واقعا قابل اجرا هستن یا یکی از مسیرها عملا هیچوقت اتفاق نمیوفته
فرض کنید به چنین ساختاری رسیدید:
شرط:
/ \ مسیرA
/ \ مسیر B
\ / ادامه
اولین سوال این نیست که کدوم مسیر بهتر به نظر میرسه
سوال اینه:
مسیر B اصلا قابل رسیدنه؟
اگر جواب نه باشه احتمالا با یک Opaque Predicate یا یک شرط غیرقابل وقوع طرف هستیم
یکی از کاربردهای این تکنیک شلوغ کردن Control Flow Graph هست
تحلیلگر وقتی نمودار رو باز میکنه تعداد زیادی مسیر میبینه
اما بخشی از این مسیرها فقط برای گمراه کردن تحلیل ایجاد شدن
نکته مهم اینه که Opaque Predicate همیشه به معنی یک شرط ثابت مثل true یا false نیست
بعضی وقتا نتیجه شرط به یک invariant وابسته ست
یعنی مقداری که با وجود تغییرات مختلف برنامه یک ویژگی مشخص رو حفظ میکنه
برای همین شما باید منطق ریاضی و رفتار داده ها رو هم بررسی کنید
تمرین
این شرط رو بررسی کنید:
int x = 10;
if ((x * 2) % 2 == 0)
{
printf("A");
}
else
{
printf("B");
}
بدون اجرای برنامه مشخص کنید کدوم مسیر میتونه اجرا بشه بعد همین ایده رو با یک شرط پیچیده تر امتحان کنید و ببینید میتونید از روی منطق ریاضی تشخیص بدید کدوم شاخه عملا غیرقابلاجراست
این دقیقا همون ذهنیتی هست که برای تحلیل Obfuscation لازم داریم
@reverseengine
ReverseEngineering
Opaque Predicate شرط هایی که ظاهرشون گمراه کننده ست حالا یکی از تکنیک هایی رو که میخایم بررسی کنیم که معمولا کنار Obfuscation استفاده میشه Opaque Predicate یعنی برنامه یک شرط میسازه که از ظاهرش مشخص نیست نتیجه همیشه چی میشه ولی سازنده از قبل میدونه نتیجه…
Opaque Predicate
Conditions that are deceptive in appearance
Now we will examine one of the techniques that is usually used alongside Obfuscation
Opaque Predicate
That is, the program creates a condition that is not always clear from its appearance what the result will be, but the constructor already knows what the result will be
For example, logically we might have something like this:
If the value of x is always 10, the condition will always be true, but when this logic is converted to assembly and mixed with additional calculations, it becomes more difficult to detect. For example, instead of a simple condition, you may see several operations in a row:
Calculate a value
Decompiler
may also make a very complex condition out of this operation. This is where the analyst should not just trust the appearance of the condition
He should understand whether both paths are actually feasible or whether one of the paths has never actually happened.
Suppose you get this structure:
Condition:
/ \ PathA
/ \ PathB
\ / continue
The first question is not which path looks better
The question is:
Is path B even feasible?
If the answer is no, we are probably dealing with an Opaque Predicate or an unfulfilled condition
One of the uses of this technique is to clutter the Control Flow Graph
When the analyst opens the graph, he sees a lot of paths
But some of these paths are created just to mislead the analysis
The important point is that Opaque Predicate does not always mean a fixed condition such as true or false
Sometimes the result of the condition depends on an invariant
That is, a value that maintains a certain property despite various program changes
For this reason, you should also examine the mathematical logic and data behavior
Exercise:
Examine this condition:
Determine which path can be executed without executing the program. Then try the same idea with a more complex condition and see if you can mathematically determine which branch is practically infeasible.
This is exactly the mindset we need for Obfuscation Analysis.
@reverseengine
Conditions that are deceptive in appearance
Now we will examine one of the techniques that is usually used alongside Obfuscation
Opaque Predicate
That is, the program creates a condition that is not always clear from its appearance what the result will be, but the constructor already knows what the result will be
For example, logically we might have something like this:
int x = 10;
if ((x * x) % 2 == 0)
{
A();
}
else
{
B();
}
If the value of x is always 10, the condition will always be true, but when this logic is converted to assembly and mixed with additional calculations, it becomes more difficult to detect. For example, instead of a simple condition, you may see several operations in a row:
Calculate a value
XOR
ADD
CMP
JZ
Decompiler
may also make a very complex condition out of this operation. This is where the analyst should not just trust the appearance of the condition
He should understand whether both paths are actually feasible or whether one of the paths has never actually happened.
Suppose you get this structure:
Condition:
/ \ PathA
/ \ PathB
\ / continue
The first question is not which path looks better
The question is:
Is path B even feasible?
If the answer is no, we are probably dealing with an Opaque Predicate or an unfulfilled condition
One of the uses of this technique is to clutter the Control Flow Graph
When the analyst opens the graph, he sees a lot of paths
But some of these paths are created just to mislead the analysis
The important point is that Opaque Predicate does not always mean a fixed condition such as true or false
Sometimes the result of the condition depends on an invariant
That is, a value that maintains a certain property despite various program changes
For this reason, you should also examine the mathematical logic and data behavior
Exercise:
Examine this condition:
int x = 10;
if ((x * 2) % 2 == 0)
{
printf("A");
}
else
{
printf("B");
}
Determine which path can be executed without executing the program. Then try the same idea with a more complex condition and see if you can mathematically determine which branch is practically infeasible.
This is exactly the mindset we need for Obfuscation Analysis.
@reverseengine
Tcache
در پست قبل گفتیم که glibc برای مدیریت Chunk های آزاد از ساختار های مختلفی مثل Bin ها استفاده میکنه اما یک ساختار مهم وجود داره که باید جداگانه بشناسیم:
Tcache
اصلا چرا ساخته شد؟
برای پیدا کردن و استفاده مجدد از Chunk های آزاد Allocator بیشتر به ساختار های عمومی Heap متکی بود
مشکل اینجا بود که در برنامههای چند نخی چند Thread میتونستن همزمان بخوان از همین ساختار ها استفاده کنن
پس:
glibc
برای سریع تر کردن تخصیص حافظه Thread Cache یا همون Tcache رو معرفی کرد
اسم Tcache از کجا میاد؟
Tcache Thread Local Cache
هست
یعنی هر Thread یک Cache مخصوص خودش داره
در نتیجه وقتی یک Thread حافظه ای رو آزاد میکنه در بسیاری از موارد میتونه اون Chunk رو در Cache خودش نگه داره
بعد اگر همون
دوباره حافظه ای با اندازه مناسب بخواد Allocator میتونه خیلی سریع از Tcache استفاده کنه
ساختارش چطوریه؟
اگر خیلی ساده تصورش کنیم:
Thread
│
└── Tcache
├── Chunk
├── Chunk
├── Chunk
Tcache
برای اندازههای مختلف مجموعه ای از لیستهای آزاد داره
مثلا میتونید ذهنی تصور کنید:
size A → chunk → chunk → chunk
size B → chunk → chunk
size C → chunk → chunk → chunk
یعنی Chunk ها بر اساس اندازه در دسته های مختلف قرار میگیرن
وقتی malloc اجرا میشه چه اتفاقی میوفته؟
فرض کنید برنامه درخواست حافظه میکنه:
malloc(size);
Allocator
اول بررسی میکنه آیا Chunk مناسبی در مسیر های سریع خودش وجود داره یا نه
اگر Chunk مناسب در Tcache موجود باشه میتونه همون رو در اختیار برنامه قرار بده در این حالت لازم نیست هر بار سراغ ساختار های پیچیدهتر Heap بره
نتیجه؟
سرعت بیشتر
وقتی free اجرا میشه چی؟
برعکس همین اتفاق هم ممکنه رخ بده
وقتی برنامه مینویسه:
free(ptr);
Chunk
آزاد شده میتونه در Tcache قرار بگیره تا بعدا دوباره مورد استفاده قرار بگیره
پس:
malloc()
↓
استفاده از Chunk
↓
free()
↓
Tcache
↓
malloc()
↓
استفاده مجدد
این چرخه یکی از پایههای مهم رفتار Heap در glibc محسوب میشه
چرا Tcache برای ما در Binary Exploitation مهمه؟
اینجا قضیه جالب میشه
هر چیزی که حافظه رو سریع تر مدیریت کنه در صورت وجود یک Memory Corruption Bug میتونه رفتار متفاوتی نسبت به ساختارهای قدیمی تر Heap داشته باشه
به همین دلیل وقتی یک Heap Bug رو بررسی میکنیم باید بدونیم:
ممکنه:
داخل Tcache باشه
داخل یکی از Binهای دیگه باشه
هنوز در اختیار برنامه باشه
یا بخشی از Heap بزرگتر شده باشه
پس بدون شناخت Tcache تحلیل Heap مدرن ناقص میمونه
یک نکته مهم
Tcache
خودش یک آسیبپذیری نیست
اتفاقا برای بهبود عملکرد Allocator طراحی شده
اما وقتی یک برنامه دچار باگهایی مثل:
Use-After-Free
یا
Double Free
میشه رفتار Tcache میتونه روی نحوه ی بروز و تحلیل مشکل تاثیر بذاره به همین دلیل در مباحث Heap Exploitation اسم Tcache رو زیاد میبینیم
در پست قبل گفتیم که glibc برای مدیریت Chunk های آزاد از ساختار های مختلفی مثل Bin ها استفاده میکنه اما یک ساختار مهم وجود داره که باید جداگانه بشناسیم:
Tcache
اصلا چرا ساخته شد؟
برای پیدا کردن و استفاده مجدد از Chunk های آزاد Allocator بیشتر به ساختار های عمومی Heap متکی بود
مشکل اینجا بود که در برنامههای چند نخی چند Thread میتونستن همزمان بخوان از همین ساختار ها استفاده کنن
پس:
مدیریت حافظه میتونست هزینه و پیچیدگی بیشتری داشته باشه
glibc
برای سریع تر کردن تخصیص حافظه Thread Cache یا همون Tcache رو معرفی کرد
اسم Tcache از کجا میاد؟
Tcache Thread Local Cache
هست
یعنی هر Thread یک Cache مخصوص خودش داره
در نتیجه وقتی یک Thread حافظه ای رو آزاد میکنه در بسیاری از موارد میتونه اون Chunk رو در Cache خودش نگه داره
بعد اگر همون
Thread
دوباره حافظه ای با اندازه مناسب بخواد Allocator میتونه خیلی سریع از Tcache استفاده کنه
ساختارش چطوریه؟
اگر خیلی ساده تصورش کنیم:
Thread
│
└── Tcache
├── Chunk
├── Chunk
├── Chunk
Tcache
برای اندازههای مختلف مجموعه ای از لیستهای آزاد داره
مثلا میتونید ذهنی تصور کنید:
size A → chunk → chunk → chunk
size B → chunk → chunk
size C → chunk → chunk → chunk
یعنی Chunk ها بر اساس اندازه در دسته های مختلف قرار میگیرن
وقتی malloc اجرا میشه چه اتفاقی میوفته؟
فرض کنید برنامه درخواست حافظه میکنه:
malloc(size);
Allocator
اول بررسی میکنه آیا Chunk مناسبی در مسیر های سریع خودش وجود داره یا نه
اگر Chunk مناسب در Tcache موجود باشه میتونه همون رو در اختیار برنامه قرار بده در این حالت لازم نیست هر بار سراغ ساختار های پیچیدهتر Heap بره
نتیجه؟
سرعت بیشتر
وقتی free اجرا میشه چی؟
برعکس همین اتفاق هم ممکنه رخ بده
وقتی برنامه مینویسه:
free(ptr);
Chunk
آزاد شده میتونه در Tcache قرار بگیره تا بعدا دوباره مورد استفاده قرار بگیره
پس:
malloc()
↓
استفاده از Chunk
↓
free()
↓
Tcache
↓
malloc()
↓
استفاده مجدد
این چرخه یکی از پایههای مهم رفتار Heap در glibc محسوب میشه
چرا Tcache برای ما در Binary Exploitation مهمه؟
اینجا قضیه جالب میشه
هر چیزی که حافظه رو سریع تر مدیریت کنه در صورت وجود یک Memory Corruption Bug میتونه رفتار متفاوتی نسبت به ساختارهای قدیمی تر Heap داشته باشه
به همین دلیل وقتی یک Heap Bug رو بررسی میکنیم باید بدونیم:
Chunk
موردنظر الان کجاست؟
ممکنه:
داخل Tcache باشه
داخل یکی از Binهای دیگه باشه
هنوز در اختیار برنامه باشه
یا بخشی از Heap بزرگتر شده باشه
پس بدون شناخت Tcache تحلیل Heap مدرن ناقص میمونه
یک نکته مهم
Tcache
خودش یک آسیبپذیری نیست
اتفاقا برای بهبود عملکرد Allocator طراحی شده
اما وقتی یک برنامه دچار باگهایی مثل:
Use-After-Free
یا
Double Free
میشه رفتار Tcache میتونه روی نحوه ی بروز و تحلیل مشکل تاثیر بذاره به همین دلیل در مباحث Heap Exploitation اسم Tcache رو زیاد میبینیم
Tcache@reverseengine
یک Thread Local Cache در glibc که برای سریع تر کردن مدیریت Chunk های کوچیک طراحی شده هر Thread میتونه Chunk های آزاد شده رو داخل Cache خودش نگه داره و در درخواست های بعدی دوباره از اونها استفاده کنه
برای فهم Heap مدرن شناخت Tcache خیلی مهمه چون رفتار malloc() و free() در حضور Tcache با مدل های قدیمی تر Heap تفاوت هایی داره
ReverseEngineering
Tcache در پست قبل گفتیم که glibc برای مدیریت Chunk های آزاد از ساختار های مختلفی مثل Bin ها استفاده میکنه اما یک ساختار مهم وجود داره که باید جداگانه بشناسیم: Tcache اصلا چرا ساخته شد؟ برای پیدا کردن و استفاده مجدد از Chunk های آزاد Allocator بیشتر به…
Tcache In the previous post, we said that glibc uses various structures such as Bins to manage free Chunks, but there is an important structure that we need to know separately:
Why was Tcache created at all?
Allocator relied more on general Heap structures to find and reuse free Chunks
The problem was that in multi-threaded programs, multiple threads could read from the same structures at the same time
So:
Memory management could be more expensive and complex
glibc introduced Thread Cache, or Tcache, to speed up memory allocation
Where does the name Tcache come from?
Tcache is Thread Local Cache
That is, each Thread has its own Cache
As a result, when a Thread frees memory, in many cases it can keep that Chunk in its Cache
Then, if the same
Thread
requests memory of the appropriate size again, the Allocator can use Tcache very quickly
What is its structure?
If we imagine it very simply:
Thread
│
└── Tcache
├── Chunk
├── Chunk
├── Chunk
Tcache
has a set of free lists for different sizes
For example, you can imagine:
size A → chunk → chunk → chunk
size B → chunk → chunk
size C → chunk → chunk → chunk → chunk
That is, the Chunks are placed in different categories based on size
What happens when malloc is executed?
Suppose the program requests memory:
Allocator
First, it checks whether there is a suitable Chunk in its fast paths or not. If a suitable Chunk is available in Tcache, it can make it available to the program. In this case, it does not need to resort to more complex Heap structures every time.
Result?
Higher speed
What happens when free is executed?
The opposite can also happen
When the program writes:
free(ptr);
The freed chunk can be placed in Tcache to be reused later
Then:
This cycle is one of the important foundations of the Heap behavior in glibc
Why is Tcache important to us in Binary Exploitation?
Here's where it gets interesting
Anything that manages memory faster can behave differently than older Heap structures if there is a Memory Corruption Bug
That's why when we investigate a Heap Bug we need to know:
Where is the Chunk
in question now?
It may be:
Inside Tcache
Inside one of the other bins
Still in the hands of the program
Or part of the Heap has grown bigger
So without knowing Tcache, the analysis of the modern Heap remains incomplete
An important point
Tcache
Itself is not a vulnerability
It is designed to improve the performance of the Allocator
However, when a program has bugs such as:
Use-After-Free
Or
Double Free
The behavior of Tcache can affect the way the problem occurs and is analyzed, which is why we often see the name Tcache in Heap Exploitation discussions
Tcache
A Thread Local Cache in glibc that is designed to speed up the management of small Chunks. Each Thread can keep the freed Chunks in its own Cache and reuse them in subsequent requests
To understand the modern Heap, it is very important to understand Tcache because the behavior of malloc() and free() in the presence of Tcache is different from older models of Heap
@reverseengine
Why was Tcache created at all?
Allocator relied more on general Heap structures to find and reuse free Chunks
The problem was that in multi-threaded programs, multiple threads could read from the same structures at the same time
So:
Memory management could be more expensive and complex
glibc introduced Thread Cache, or Tcache, to speed up memory allocation
Where does the name Tcache come from?
Tcache is Thread Local Cache
That is, each Thread has its own Cache
As a result, when a Thread frees memory, in many cases it can keep that Chunk in its Cache
Then, if the same
Thread
requests memory of the appropriate size again, the Allocator can use Tcache very quickly
What is its structure?
If we imagine it very simply:
Thread
│
└── Tcache
├── Chunk
├── Chunk
├── Chunk
Tcache
has a set of free lists for different sizes
For example, you can imagine:
size A → chunk → chunk → chunk
size B → chunk → chunk
size C → chunk → chunk → chunk → chunk
That is, the Chunks are placed in different categories based on size
What happens when malloc is executed?
Suppose the program requests memory:
malloc(size);
Allocator
First, it checks whether there is a suitable Chunk in its fast paths or not. If a suitable Chunk is available in Tcache, it can make it available to the program. In this case, it does not need to resort to more complex Heap structures every time.
Result?
Higher speed
What happens when free is executed?
The opposite can also happen
When the program writes:
free(ptr);
The freed chunk can be placed in Tcache to be reused later
Then:
malloc()
↓
Using Chunk
↓
free()
↓
Tcache
↓
malloc()
↓
Reuse
This cycle is one of the important foundations of the Heap behavior in glibc
Why is Tcache important to us in Binary Exploitation?
Here's where it gets interesting
Anything that manages memory faster can behave differently than older Heap structures if there is a Memory Corruption Bug
That's why when we investigate a Heap Bug we need to know:
Where is the Chunk
in question now?
It may be:
Inside Tcache
Inside one of the other bins
Still in the hands of the program
Or part of the Heap has grown bigger
So without knowing Tcache, the analysis of the modern Heap remains incomplete
An important point
Tcache
Itself is not a vulnerability
It is designed to improve the performance of the Allocator
However, when a program has bugs such as:
Use-After-Free
Or
Double Free
The behavior of Tcache can affect the way the problem occurs and is analyzed, which is why we often see the name Tcache in Heap Exploitation discussions
Tcache
A Thread Local Cache in glibc that is designed to speed up the management of small Chunks. Each Thread can keep the freed Chunks in its own Cache and reuse them in subsequent requests
To understand the modern Heap, it is very important to understand Tcache because the behavior of malloc() and free() in the presence of Tcache is different from older models of Heap
@reverseengine
بخش بیست و پنجم بافر اورفلو
Address Sanitizer
یا ASan شکار باگ های حافظه
تا اینجا یاد گرفتیم با Fuzzing میشه ورودی های زیادی به برنامه داد و کرش ها رو پیدا کرد
نکته مهم
وقتی برنامه کرش کرد از کجا بفهمیم دقیقا چه اتفاقی افتاده
اینجاست که AddressSanitizer یا ASan وارد میشه
ASan
یک ابزار برای پیدا کردن خطا های مربوط به حافظه در زمان اجرای برنامه است
ASan
چیکار میکنه
برنامه رو با یک سری بررسی های اضافه اجرا میکنه
مثلا میتونه مواردی مثل اینا رو پیدا کنه:
Stack Buffer Overflow
Heap Buffer Overflow
Use After Free
Out of Bounds Access
یعنی به جای اینکه فقط بگی برنامه کرش کرد میتونید بفهمید مشکل تقریبا کجای برنامه اتفاق افتاده
یک مثال ساده:
فایل
C
اینجا بافر فقط 8 بایت جا داره
ولی رشته خیلی بزرگ تره
کامپایل با ASan
shell
حالا اجراش میکنیم
shell
./file21_demo
ASan
متوجه میشه که برنامه خارج از محدوده
و یک گزارش خطا نمایش میده
نکته مهم گزارش ASan
یکی از جذاب ترین قسمت های ASan اینه که معمولا اطلاعات مفیدی درباره خطا میده
مثلا مشخص میکنه
ERROR: AddressSanitizer
stack-buffer-overflow
بعد پایین تر معمولا Stack Trace رو هم میبینید یعنی میفهمید خطا از چه تابعی و در چه خطی ایجاد شده
چرا برای Reverse Engineering مهمه؟
فرض کنید سورس کد ندارید یا برنامه خیلی پیچیده است اگر نسخهای از برنامه رو با Instrumentation مناسب داشته باشید
ASan
میتونه بهتون کمک کنه بفهمید یک ورودی خاص دقیقا چه نوع Memory Bug ایجاد کرده
بعد همون نقطه رو میبرید داخل Ghidra یا IDA و از روی Assembly بررسیش کنید
یعنی مسیرمون میشه
Fuzzing
↓
Crash
↓
ASan
↓
محل خطا
↓
Ghidra / IDA
↓
تحلیل Assembly
این ترکیب برای پیدا کردن و تحلیل Memory Bug خیلی قدرتمنده
یک نکته مهم
ASan
خودش جلوی همه آسیبپذیری ها رو نمیگیره کار اصلیش اینه که در محیط توسعه و تست
خطا های حافظه رو سریع تر پیدا کنیم
برای همین معمولا کنار Fuzzing استفاده میشه
Fuzzer
برنامه با این ورودی خراب شد
ASan
کمک میکنه بفهمید
دقیقا چه نوع خطای حافظه ای اتفاق افتاده و کجا
بعد Reverse Engineer میاد همون
قسمت رو با Ghidra یا IDA بررسی میکنه
تمرین این قسمت:
همین
بعد گزارش ASan رو نگاه کنید و سه چیز رو پیدا کنید
نوع خطا
تابعی که خطا داخلش اتفاق افتاده
خط کدی که باعث خطا شده
@reverseengine
Address Sanitizer
یا ASan شکار باگ های حافظه
تا اینجا یاد گرفتیم با Fuzzing میشه ورودی های زیادی به برنامه داد و کرش ها رو پیدا کرد
نکته مهم
وقتی برنامه کرش کرد از کجا بفهمیم دقیقا چه اتفاقی افتاده
اینجاست که AddressSanitizer یا ASan وارد میشه
ASan
یک ابزار برای پیدا کردن خطا های مربوط به حافظه در زمان اجرای برنامه است
ASan
چیکار میکنه
برنامه رو با یک سری بررسی های اضافه اجرا میکنه
مثلا میتونه مواردی مثل اینا رو پیدا کنه:
Stack Buffer Overflow
Heap Buffer Overflow
Use After Free
Out of Bounds Access
یعنی به جای اینکه فقط بگی برنامه کرش کرد میتونید بفهمید مشکل تقریبا کجای برنامه اتفاق افتاده
یک مثال ساده:
فایل
C
#include <stdio.h>
#include <string.h>
int main()
{
char buf[8];
strcpy(buf,"AAAAAAAAAAAAAAAA");
printf("%s\n",buf);
return 0;
}
اینجا بافر فقط 8 بایت جا داره
ولی رشته خیلی بزرگ تره
کامپایل با ASan
shell
gcc -g -fsanitize=address file21_demo.c -o file21_demo
حالا اجراش میکنیم
shell
./file21_demo
ASan
متوجه میشه که برنامه خارج از محدوده
buf نوشتهو یک گزارش خطا نمایش میده
نکته مهم گزارش ASan
یکی از جذاب ترین قسمت های ASan اینه که معمولا اطلاعات مفیدی درباره خطا میده
مثلا مشخص میکنه
ERROR: AddressSanitizer
stack-buffer-overflow
بعد پایین تر معمولا Stack Trace رو هم میبینید یعنی میفهمید خطا از چه تابعی و در چه خطی ایجاد شده
چرا برای Reverse Engineering مهمه؟
فرض کنید سورس کد ندارید یا برنامه خیلی پیچیده است اگر نسخهای از برنامه رو با Instrumentation مناسب داشته باشید
ASan
میتونه بهتون کمک کنه بفهمید یک ورودی خاص دقیقا چه نوع Memory Bug ایجاد کرده
بعد همون نقطه رو میبرید داخل Ghidra یا IDA و از روی Assembly بررسیش کنید
یعنی مسیرمون میشه
Fuzzing
↓
Crash
↓
ASan
↓
محل خطا
↓
Ghidra / IDA
↓
تحلیل Assembly
این ترکیب برای پیدا کردن و تحلیل Memory Bug خیلی قدرتمنده
یک نکته مهم
ASan
خودش جلوی همه آسیبپذیری ها رو نمیگیره کار اصلیش اینه که در محیط توسعه و تست
خطا های حافظه رو سریع تر پیدا کنیم
برای همین معمولا کنار Fuzzing استفاده میشه
Fuzzer
برنامه با این ورودی خراب شد
ASan
کمک میکنه بفهمید
دقیقا چه نوع خطای حافظه ای اتفاق افتاده و کجا
بعد Reverse Engineer میاد همون
قسمت رو با Ghidra یا IDA بررسی میکنه
تمرین این قسمت:
همین
file21_demo.c رو با ASan کامپایل کنیدبعد گزارش ASan رو نگاه کنید و سه چیز رو پیدا کنید
نوع خطا
تابعی که خطا داخلش اتفاق افتاده
خط کدی که باعث خطا شده
@reverseengine
ReverseEngineering
بخش بیست و پنجم بافر اورفلو Address Sanitizer یا ASan شکار باگ های حافظه تا اینجا یاد گرفتیم با Fuzzing میشه ورودی های زیادی به برنامه داد و کرش ها رو پیدا کرد نکته مهم وقتی برنامه کرش کرد از کجا بفهمیم دقیقا چه اتفاقی افتاده اینجاست که AddressSanitizer…
Part 25 Buffer Overflow
Address Sanitizer
or ASan Hunting for Memory Bugs
So far, we have learned that with Fuzzing, you can give a lot of input to the program and find crashes
Important point
When the program crashes, how do we find out exactly what happened
This is where AddressSanitizer or ASan comes in
ASan
is a tool for finding memory-related errors during program execution
What ASan does
It runs the program with a series of additional checks
For example, it can find things like:
Stack Buffer Overflow
Heap Buffer Overflow
Use After Free
Out of Bounds Access
That is, instead of just saying that the program crashed, you can find out where in the program the problem occurred
A simple example:
C
#include <stdio.h>
#include <string.h>
int main()
{
char buf[8];
strcpy(buf,"AAAAAAAAAAAAAA");
printf("%s\n",buf);
return 0;
}
Here the buffer is only 8 bytes
But the string is much larger
Compile with ASan
shell
gcc -g -fsanitize=address file21_demo.c -o file21_demo
Now we run it
shell
./file21_demo
ASan
notices that the program wrote outside the buf range
And displays an error report
Important point of ASan report
One of the most interesting parts of ASan is that it usually gives useful information about the error
For example, it specifies
ERROR: AddressSanitizer
stack-buffer-overflow
Then below you usually see the Stack Trace, which means you understand which function and line the error occurred
Why is it important for Reverse Engineering?
Suppose you don't have the source code or the program is very complex. If you have a version of the program with proper instrumentation,
ASan
can help you find out exactly what kind of memory bug a particular input caused.
Then you take that point into Ghidra or IDA and examine it from the assembly.
That is, our path will be
Fuzzing
↓
Crash
↓
ASan
↓
Error location
↓
Ghidra / IDA
↓
Assembly analysis
This combination is very powerful for finding and analyzing memory bugs.
An important point
ASan
itself does not prevent all vulnerabilities. Its main job is to find memory errors faster in the development and test environment.
That is why it is usually used together with Fuzzing.
Fuzzer
The program crashed with this input.
ASan
helps you find out exactly what kind of memory error occurred and where.
Then the reverse engineer comes and examines the same part with Ghidra or IDA.
Exercise of this part:
This is Compile file21_demo.c with ASan
Then look at the ASan report and find three things
Type of error
Function where the error occurred
Line of code that caused the error
@reverseengine
Bypassing Administrator Protection by Abusing UI Access
https://projectzero.google/2026/02/windows-administrator-protection.html
@reverseengine
https://projectzero.google/2026/02/windows-administrator-protection.html
@reverseengine
projectzero.google
Bypassing Administrator Protection by Abusing UI Access
In my last blog post I introduced the new Windows feature, Administrator Protection and how it ai...
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.
Hex-Rays is Heading to Hacker Summer Camp 2026
https://hex-rays.com/blog/hex-rays-hacker-summer-camp-2026
@reverseengine
https://hex-rays.com/blog/hex-rays-hacker-summer-camp-2026
@reverseengine
Hex-Rays
Hex-Rays is Heading to Hacker Summer Camp 2026
Join Hex-Rays at Hacker Summer Camp 2026 for demos, workshops, and recruitment. Explore the latest IDA features and hang with us.
How Trail of Bits helps verify the integrity of your Signal chats
https://blog.trailofbits.com/2026/08/11/how-trail-of-bits-helps-verify-the-integrity-of-your-signal-chats
@reverseengine
https://blog.trailofbits.com/2026/08/11/how-trail-of-bits-helps-verify-the-integrity-of-your-signal-chats
@reverseengine
The Trail of Bits Blog
How Trail of Bits helps verify the integrity of your Signal chats
Signal recently launched Automatic Key Verification, a feature that helps validate that your chats are secure without requiring direct safety number comparison. Trail of Bits built and operates one of the three auditors that make this system trustworthy.
Make it Blink: Remotely compromising the Philips Hue bridge
https://www.synacktiv.com/publications/make-it-blink-compromission-a-distance-du-bridge-philips-hue
@reverseengine
https://www.synacktiv.com/publications/make-it-blink-compromission-a-distance-du-bridge-philips-hue
@reverseengine
Synacktiv
Make it Blink : Compromission à distance du bridge Philips Hue