ReverseEngineering
1.32K subscribers
50 photos
11 videos
106 files
888 links
Download Telegram
Opcode Encoding

چرا Opcode ها اینقدر عجیب به نظر میرسن؟

تا اینجا فرض کردیم Opcode ها خیلی ساده هستن

مثلا:
01 = LOAD
02 = ADD
03 = JMP

ولی توی ماشین‌های مجازی واقعی تقریبا هیچ‌ وقت اوضاع اینقدر ساده نیست
سازنده محافظ نمیخواد تحلیلگر با چند دقیقه نگاه کردن معنی Opcode ها رو بفهمه
به همین خاطر Opcode ها رو به شکل‌ های مختلف مخفی میکنه
مثلا ممکنه Opcode واقعی این باشه:
0x8F

ولی قبل از اجرا این عملیات روی اون انجام بشه:
Opcode ^= 0xA5

بعد از XOR شدن تازه مقدار واقعی به دست میاد
یا ممکنه Opcode اصلا مستقیم داخل بایت‌ کد ذخیره نشده باشه
مثلا قبل از استفاده از روی یک جدول ترجمه عبور کنه
0x3C  →  LOAD
0x91 → ADD
0xE7 → JMP

در این حالت اگر فقط به بایت‌کد نگاه کنید هیچ معنی خاصی نمیبینید
یکی دیگه از روش‌های رایج اینه که اندازه Opcode ها ثابت نباشه
مثلا:
Opcode
Operand
Operand

یا:
Opcode
Operand

یا حتی:
Opcode
Operand
Operand
Operand

یعنی هر Opcode تعداد متفاوتی Operand داره اگر تحلیلگر این موضوع رو متوجه نشه از همون دستور اول کل بایت‌ کد رو اشتباه تفسیر میکنه بعضی ماشین‌های مجازی حتی Opcode ها رو موقع اجرا تولید میکنن یعنی مقداری که Dispatcher میبینه همون مقداری نیست که داخل فایل ذخیره شده به همین خاطر یکی از اولین کارهای تحلیلگر اینه که مسیر رسیدن Opcode به Dispatcher رو دنبال کنه اگر قبل از Dispatcher عملیاتی مثل XOR، ADD، SUB یا چرخش بیت‌ ها انجام بشه احتمال زیادی وجود داره که Opcode ها رمزگذاری شده باشن هدف از Opcode Encoding فقط سخت‌تر کردن تحلیل نیست باعث میشه ابزارهایی مثل IDA یا Ghidra هم نتونن به‌ راحتی منطق ماشین مجازی رو تشخیص بدن به همین دلیل تحلیلگرها معمولا قبل از اینکه سراغ Handler ها برن سعی میکنن بفهمن Opcode ها دقیقا چطور Decode میشن اگر این مرحله رو درست انجام بدید ادامه فرایند Devirtualization خیلی ساده‌ تر میشه

تمرین:

فرض کنید بایت‌ کد زیر رو دارید:
8F 91 E7

و میدونید قبل از اجرا هر Opcode با 0xA5 عمل XOR میشه
اول مقدار واقعی هر Opcode رو حساب کنید
بعد فرض کنید نتیجه این جدول باشه:
2A = LOAD
34 = ADD
42 = PRINT

سعی کنید مسیر اجرای ماشین مجازی رو روی کاغذ باز سازی کنید

@reverseengine
ReverseEngineering
Opcode Encoding چرا Opcode ها اینقدر عجیب به نظر میرسن؟ تا اینجا فرض کردیم Opcode ها خیلی ساده هستن مثلا: 01 = LOAD 02 = ADD 03 = JMP ولی توی ماشین‌های مجازی واقعی تقریبا هیچ‌ وقت اوضاع اینقدر ساده نیست سازنده محافظ نمیخواد تحلیلگر با چند دقیقه نگاه کردن…
Opcode Encoding

Why do Opcodes look so weird?

So far we have assumed that the Opcodes are very simple

For example:

01 = LOAD
02 = ADD
03 = JMP


But in real virtual machines things are almost never that simple
The manufacturer of the protection does not want the analyst to understand the meaning of the Opcodes by looking at them for a few minutes
That is why they hide the Opcodes in different ways

For example, the real Opcode may be:

0x8F


But before performing this operation on it:

Opcode ^= 0xA5


The real value is obtained only after XORing
Or the Opcode may not be stored directly in the bytecode at all
For example, it passes through a translation table before use

0x3C → LOAD
0x91 → ADD
0xE7 → JMP


In this case, if you only look at the bytecode, you will not see any special meaning
Another common method is to make the Opcodes not have a fixed size

For example:

Opcode
Operand
Operand

Or:

Opcode
Operand

Or Even:

Opcode
Operand
Operand
Operand


That is, each Opcode has a different number of Operands. If the analyst does not understand this, he will misinterpret the entire bytecode from the very first instruction. Some virtual machines even generate Opcodes at runtime, meaning that the value that the Dispatcher sees is not the same value that is stored in the file. Therefore, one of the first tasks of the analyst is to follow the path of the Opcode to the Dispatcher. If an operation such as XOR, ADD, SUB, or bit rotation is performed before the Dispatcher, there is a high probability that the Opcodes are encrypted. The purpose of Opcode Encoding is not just to make the analysis more difficult. It also makes tools such as IDA or Ghidra unable to easily recognize the logic of the virtual machine. Therefore, analysts usually try to understand exactly how the Opcodes are decoded before moving on to the Handlers. If you do this step correctly, the rest of the Devirtualization process will be much easier.

Exercise:

Suppose you have the following bytecode:

8F 91 E7


And you know that before Each Opcode can be XORed with 0xA5
First calculate the actual value of each Opcode
Then assume the result is this table:

2A = LOAD
34 = ADD
42 = PRINT


Try to reconstruct the path of the virtual machine execution on paper

@reverseengine
PCB (Process Control Block)
شناسنامه هر Process

تا اینجا یاد گرفتیم Process ساخته میشوه اجرا میشه و بین حالت‌ های مختلف جا به جا میشه

اما یک سؤال مهم:

سیستم‌عامل از کجا میفهه هر Process چه وضعیتی داره؟

مثلا از کجا میدونه:
الان در حال اجراست؟
چقدر حافظه گرفته؟
چند Thread داره؟
چه فایل‌هایی رو باز کرده؟
جواب همه این سؤال‌ها یک چیزه:

PCB (Process Control Block)

PCB
رو میتونیم مثل پرونده یا شناسنامه یک Process تصور کنیم
هر Process که ساخته میشه سیستم‌ عامل یک PCB هم برای اون ایجاد میکنه
داخل این ساختار تمام اطلاعات لازم برای مدیریت اون Process نگهداری میشه

داخل PCB چه اطلاعاتی وجود داره؟

شناسه پردازه (PID)

هر Process یک شماره منحصر به‌ فرد داره

مثلا:
Process A → PID = 1200
Process B → PID = 2456


سیستم‌ عامل از این شناسه برای تشخیص Process ها استفاده میکنه

وضعیت Process

همان State هایی که پست قبل یاد گرفتیم:

New
Ready
Running
Waiting
Terminated
وضعیت فعلی Process داخل PCB ذخیره میشه

اطلاعات CPU
وقتی سیستم‌ عامل اجرای یک Process رو متوقف میکنه باید بدونه بعدا از کجا ادامه بده

برای همین اطلاعاتی مثل:

مقدار Register ها
Program Counter
Stack Pointer
داخل PCB ذخیره میشن

اطلاعات حافظه

سیستم‌عامل باید بدونه:

حافظه Process کجاست؟
Heap کجاست؟

Stack کجاست؟

Page Table
مربوط به این Process چیه؟

همه این اطلاعات داخل PCB ثبت میشن

اطلاعات فایل‌ ها
اگر Process چند فایل رو باز کرده باشه سیستم‌ عامل باید اونها رو مدیریت کنه

مثلا:

فایل متنی
سوکت شبکه
پرینتر
این اطلاعات هم در PCB نگهداری میشن

چرا PCB مهمه؟

فرض کنید CPU در حال اجرای Chrome هست
یهو سیستم‌ عامل تصمیم میگیره به Telegram زمان اجرا بده
قبل از این جا به‌ جایی باید وضعیت Chrome ذخیره بشه تا بعدا دقیقا از همون نقطه ادامه بده

این اطلاعات داخل PCB ذخیره میشن
به این کار Context Switch میگن

یک مثال ساده:

فرض کنید داری یک بازی انجام میدید
اگر بازی رو Pause کنید انتظار دارید بعد از Resume دقیقا از همون لحظه ادامه پیدا کنه

سیستم‌ عامل هم برای Process ها همین کار رو انجام میده
قبل از اینکه اجرای یک Process متوقف بشه وضعیت اون رو داخل PCB ذخیره میکنه تا بعدا بدون مشکل ادامه پیدا کنه

چرا برای مهندسی معکوس مهمه؟

در مهندسی معکوس شاید مستقیما با PCB کار نکنید اما بسیاری از مفاهیم مهم به اون وابسته ان:

Context Switch
Process Scheduling
Thread Management
Kernel Debugging
Windows Internals


اگر بدونید سیستم‌ عامل چه اطلاعاتی از هر Process نگه میداره تحلیل رفتار برنامه‌ ها براتون خیلی راحت‌ تر میشه


هر Process یک PCB داره که مثل شناسنامه اون عمل میکنه

داخل PCB اطلاعاتی مثل:
PID
وضعیت Process
Register ها
اطلاعات حافظه
فایل‌های باز
اطلاعات زمان‌بندی
ذخیره میشن

بدون PCB سیستم‌ عامل نمیتونه Process ها رو مدیریت کنه

@reverseengine
ReverseEngineering
PCB (Process Control Block) شناسنامه هر Process تا اینجا یاد گرفتیم Process ساخته میشوه اجرا میشه و بین حالت‌ های مختلف جا به جا میشه اما یک سؤال مهم: سیستم‌عامل از کجا میفهه هر Process چه وضعیتی داره؟ مثلا از کجا میدونه: الان در حال اجراست؟ چقدر حافظه…
PCB (Process Control Block) The ID of Each Process

So far we have learned that a Process is created, executed, and switched between different states

But an important question:

How does the operating system know what state each Process is in?

For example, how does it know:

Is it currently running?
How much memory does it take?
How many threads does it have?
What files has it opened?
The answer to all these questions is the same:

PCB (Process Control Block)


We can imagine the PCB as a file or ID of a Process.
For each Process that is created, the operating system also creates a PCB for it.
Inside this structure, all the information necessary to manage that Process is stored.

What information is inside the PCB?

Process ID (PID)


Each process has a unique number

For example:

Process A → PID = 1200
Process B → PID = 2456


The operating system uses this ID to identify processes

Process State

Same states as we learned in the previous post:

New
Ready
Running
Waiting
Terminated


The current state of the process is stored in the PCB

CPU Information
When the operating system stops executing a process, it needs to know where to continue next

For this reason, information such as:

Register values

Program Counter

Stack Pointer
are stored in the PCB

Memory Information


The operating system needs to know:

Where is the process memory?

Where is the heap?

Where is the stack?

Page Table
What is related to this process?

All this information is recorded in the PCB

File information
If a Process has opened several files, the operating system must manage them

For example:

Text file
Network socket
Printer
This information is also stored in the PCB


Why is the PCB important?

Suppose the CPU is running Chrome
An operating system decides to give Telegram time to run
Before this, the state of Chrome must be saved somewhere so that it can continue exactly from the same point later

This information is stored in the PCB
This is called Context Switch

A simple example:

Suppose you are playing a game
If you pause the game, you expect it to continue exactly from that moment after Resume

The operating system does the same for Processes
Before a Process is stopped, it saves its state in the PCB so that it can continue later without any problems

Why is it important for reverse engineering?

In reverse engineering, you may not work directly with the PCB, but many important concepts depend on it:

Context Switch
Process Scheduling
Thread Management
Kernel Debugging
Windows Internals


If you know what information the operating system keeps about each process, analyzing the behavior of programs will be much easier for you

Each process has a PCB that acts as its identity card

Inside the PCB, information such as:

PID
Process status
Registers
Memory information
Open files
Scheduling information


Without the PCB, the operating system cannot manage processes

@reverseengine
دوستان ببخشید اگه نمیرسم پست بزارم درگیر یک پروژه هستم سعیمو میکنم از فردا دوباره بزارم خیلی عذر میخام🩶

Sorry guys if I don't have time to post, I'm busy with a project, I'll try to post again tomorrow. I apologize🖤
❤6
Context Switch
وقتی CPU بین Process ها جا به‌ جا میشه

تا اینجا فهمیدیم هر Process یک PCB داره که تمام اطلاعات مهم داخلش ذخیره میشه

حالا سوال اصلی:

اگر CPU در حال اجرای Chrome باشه چجوری یهو می‌تونه Telegram رو اجرا کنه

دوباره از اول شروع میکنه؟

نه


سیستم‌ عامل از مکانیزمی به نام Context Switch استفاده میکنه



Context Switch

به زبان ساده:

Context Switch
یعنی ذخیره کردن وضعیت Process فعلی و اپلود وضعیت Process بعدی

به این ترتیب هر Process میتونه بعدا دقیقا از همون جایی که متوقف شده بود ادامه پیدا کنه


یک مثال ساده

فرض کنید دارید یک کتاب میخونید

به صفحه 87 میرسید که تلفنتون زنگ میخوره

یک بوکمارک (Bookmark) داخل کتاب میذارید و جواب تلفن رو میدید

بعد از چند دقیقه برمیگردید و دقیقا از صفحه 87 ادامه میدید

اگر بوکمارک نمیذاشتید باید دوباره دنبال صفحه‌ ای که بودید میگشتید

PCB
دقیقا نقش همین بوکمارک رو برای Process ها داره




هنگام Context Switch چه اتفاقی میوفته؟

فرض کنید CPU در حال اجرای Process A هست

سیستم‌ عامل تصمیم میگیره حالا Process B اجرا بشه

مراحل به این صورته:

توقف Process A

اجرای Process A موقتا متوقف میشه




ذخیره وضعیت Process A

سیستم‌عامل اطلاعات مهم رو داخل PCB اون ذخیره میکنه

مثل:

مقدار Register ها

محل اجرای فعلی برنامه Program Counter

Stack Pointer

وضعیت CPU





اپلود Process B

حالا اطلاعات Process B از PCB اون خونده میشن

Register
ها Stack و بقیه اطلاعات دوباره داخل CPU قرار میگیرن




ادامه اجرای Process B

CPU
اجرای Process B را از همون نقطه‌ ای که قبلا متوقف شده ادامه میده نه از اول




چرا Context Switch لازمه؟

فرض کنید فقط یک هسته CPU داریو و این برنامه‌ ها بازن:

Chrome

Telegram

Spotify

Notepad


اگر Context Switch وجود نداشت اولین برنامه تمام فضای CPU رو میگرفت و بقیه هیچ‌ وقت اجرا نمیشدن

سیستم‌عامل با جا به‌ جایی سریع بین Process ها باعث میشه احساس کنیم همه برنامه‌ ها همزمان در حال اجرا هستن




هر بار که Context Switch انجام میشه سیستم‌ عامل باید:

اطلاعات Process قبلی رو ذخیره میکنه

اطلاعات Process جدید رو اپلود میکنه

بعضی ‌وقتا کش CPU Cache و TLB هم تحت تاثیر قرار میگیره


این کار زمان و منابع CPU رو مصرف میکنه

به همین دلیل اگر تعداد Context Switch ها خیلی زیاد بشه ممکنه عملکرد سیستم کاهش پیدا کنه



چرا برای مهندسی معکوس مهمه؟

وقتی در حال دیباگ یک برنامه هستید ممکنه اینا رو ببینید:

اجرای برنامه یهو متوقف شد

Thread
دیگه ای شروع به اجرا کرد

دوباره اجرای قبلی ادامه پیدا کرد


درک Context Switch کمک میکنه بفهمید چرا این جا به‌ جایی‌ ها اتفاق میوفتن و چرا ترتیب اجرای کد همیشه خطی نیست

این مفهوم همچنین پایه‌ ای برای درک مباحث پیشرفته‌ تر مثل:

Scheduling

Multi-threading

Race Condition

Kernel Debugging


Context Switch:

ذخیره وضعیت Process فعلی در PCB

اپلود وضعیت Process بعدی از PCB

ادامه اجرای Process جدید از همون نقطه قبلی


این مکانیزم باعث میشه چندین برنامه روی یک CPU به‌صورت روون اجرا بشن

@reverseengine
❤2
ReverseEngineering
Context Switch وقتی CPU بین Process ها جا به‌ جا میشه تا اینجا فهمیدیم هر Process یک PCB داره که تمام اطلاعات مهم داخلش ذخیره میشه حالا سوال اصلی: اگر CPU در حال اجرای Chrome باشه چجوری یهو می‌تونه Telegram رو اجرا کنه دوباره از اول شروع میکنه؟ نه …
Context Switch: When the CPU switches between processes

So far we have understood that each process has a PCB that stores all the important information

Now the main question:

If the CPU is running Chrome, how can it suddenly run Telegram

Starting from scratch again?

No

The operating system uses a mechanism called Context Switch

Context Switch

In simple terms:

Context Switch
means saving the state of the current process and uploading the state of the next process

In this way, each process can continue exactly where it left off

A simple example

Suppose you are reading a book

You reach page 87 when your phone rings

You put a bookmark in the book and see the answer to the phone

After a few minutes, you come back and continue exactly from page 87

If you had not put a bookmark, you would have to look for the page you were on again

PCB
is exactly the role of this bookmark for processes

What happens during Context Switch?

Suppose CPU is executing Process A

The operating system decides to execute Process B now

The steps are as follows:

Stop Process A

Process A execution is temporarily stopped

Save Process A state

The operating system saves important information into its PCB

For example:

Register values

Current execution location of the program Program Counter

Stack Pointer

CPU state

Upload Process B

Now Process B information is read from its PCB

Registers, Stack and other information are put back into the CPU

Continue execution of Process B

CPU resumes execution of Process B from the same point where it was stopped earlier, not from the beginning

Why is Context Switch necessary?

Suppose you have only one CPU core and these programs are open:

Chrome

Telegram

Spotify

Notepad

If there was no Context Switch, the first program would take up all the CPU space and the others would never run

The operating system makes it feel like all programs are running at the same time by quickly switching between processes

Every time a Context Switch is performed, the operating system must:

Save the previous process information

Upload the new process information

Sometimes the CPU Cache and TLB are also affected

This consumes time and CPU resources

Therefore, if the number of Context Switches becomes too large, the system performance may decrease

Why is it important for reverse engineering?

When you are debugging a program, you may see:

Program execution suddenly stops

Thread
starts running again

Previous execution continues

Understanding Context Switch helps you understand why these switchings happen and why the order of code execution is not always linear

This concept also provides a foundation for understanding more advanced topics such as:

Scheduling

Multi-threading

Race Condition

Kernel Debugging

Context Switch:

Save current process state to PCB

Upload next process state from PCB

Continue execution of new process from previous point

This mechanism allows multiple programs to run smoothly on a single CPU

@reverseengine
❤1🥰1
Instruction Handler
داخل هر Handler دقیقا چه اتفاقی میوفته؟

تا اینجا فهمیدیم هر Opcode یک Handler مخصوص خودش رو داره

اما سوال اصلی اینجاست

وقتی Dispatcher کنترل رو به یک Handler میده اون Handler دقیقا چه کاری انجام میده؟

فرض کنید Opcode مربوط به جمع باشه

در ظاهر فقط یک عدد مثل این میبینیم:

0x27

ولی پشت این عدد چندین دستور اسمبلی اجرا میشه

مثلا ممکنه Handler این کار ها رو انجام بده:

خواندن Operand اول

خواندن Operand دوم

انجام عملیات جمع

ذخیره نتیجه

برگشت به Dispatcher

همه این مراحل داخل چندین دستور اسمبلی پیاده‌ سازی میشن

برای همین وقتی Handler رو داخل IDA یا Ghidra باز میکنید معمولا فقط چند دستور نمیبینید

ممکن است ده‌ ها یا حتی صد ها دستور وجود داشته باشه

کاری که تحلیلگر انجام میده این نیست که همه دستورها رو حفظ کنه

بلکه سعی میکنه رفتار کلی Handler رو بفهمه

مثلا بعد از چند دقیقه بررسی به این نتیجه میرسه:

این Handler فقط داده رو جا به‌ جا میکنه

این یکی مقدار ها رو با هم جمع میکنه

این یکی عمل XOR رو انجام میده

این یکی پرش شرطی انجام میده

این یکی مقدار رو داخل Stack یا Virtual Register ذخیره میکنه


وقتی این دسته‌ بندی کامل بشه کم‌ کم جدول Opcode ها ساخته میشه

به این جدول معمولا Opcode Semantics میگن

یعنی مشخص میکنیم هر Opcode چه معنی و چه رفتاری داره

یکی از اشتباهات رایج افراد تازه‌ کار اینه که از اولین دستور اسمبلی شروع میکنن و خط‌ به‌ خط جلو میرن

تحلیلگر های حرفه‌ای برعکس عمل میکنن

اول ورودی Handler رو پیدا میکنن

بعد خروجی Handler رو بررسی میکنن

در آخر مسیر بین این دو رو تحلیل میکنن

این روش باعث میشه خیلی سریع‌ تر بفهمن Handler چه کاری انجام میده

تمرین:

فرض کنید بعد از بررسی یک Handler فقط این اطلاعات رو به دست آوردید:

ورودی:
V0 = 15
V1 = 8

خروجی:
V0 = 23
V1 = 8

بدون اینکه اسمبلی رو ببینید حدس بزنید این Handler چه کاری انجام داده

باید بتونید فقط از روی ورودی و خروجی رفتار Handler رو تشخیص بدید

@reverseengine
❤2
ReverseEngineering
Instruction Handler داخل هر Handler دقیقا چه اتفاقی میوفته؟ تا اینجا فهمیدیم هر Opcode یک Handler مخصوص خودش رو داره اما سوال اصلی اینجاست وقتی Dispatcher کنترل رو به یک Handler میده اون Handler دقیقا چه کاری انجام میده؟ فرض کنید Opcode مربوط به جمع باشه…
Instruction Handler
What exactly happens inside each Handler?

So far we have understood that each Opcode has its own Handler

But here is the main question

When the Dispatcher gives control to a Handler, what exactly does that Handler do?

Suppose the Opcode is related to addition

At first glance, we see just one number like this:

0x27

But behind this number, several assembly instructions are executed

For example, the Handler may do the following:

Read the first Operand

Read the second Operand

Perform the addition operation

Save the result

Return to Dispatcher

All these steps are implemented in several assembly instructions

That's why when you open the Handler in IDA or Ghidra, you usually don't see just a few instructions

There may be dozens or even hundreds of instructions

What the analyst does is not to memorize all the instructions

But it tries to understand the general behavior of the Handler

For example, after a few minutes of examination, it comes to the following conclusion:

This Handler only moves data

This one adds values ​​together

This one performs an XOR operation

This one performs a conditional jump

This one stores a value in the Stack or Virtual Register

When Once this classification is complete, the Opcode table is gradually created

This table is usually called Opcode Semantics

That is, we specify what each Opcode means and what behavior it has

One of the common mistakes of beginners is that they start from the first assembly instruction and proceed line by line

Professional analyzers do the opposite

First they find the Handler input

Then they examine the Handler output

Finally, they analyze the path between the two

This method makes it much faster to understand what the Handler does

Exercise:

Suppose that after examining a Handler, you only obtained this information:

Input:
V0 = 15
V1 = 8

Output:
V0 = 23
V1 = 8

Guess what this Handler did without seeing the assembly

You should be able to recognize the Handler's behavior just from the input and output

@reverseengine
❤1
Chunk
دقیقا چیسه و چه ساختاری داره؟
در پست قبل گفتیم Heap از بخش‌ های کوچیکی به اسم Chunk تشکیل شده
هر بار که برنامه از malloc() استفاده میکنه Allocator یک Chunk در اختیارش قرار میده اما این Chunk فقط یه تیکه حافظه ساده نیست اطلاعات مهمی هم داخلش وجود داره

Chunk
فقط داده‌ ی برنامه نیست
فرض کنید از Heap 100 بایت حافظه درخواست کردید شاید فکر کنید Allocator دقیقا همون 100 بایت رو بهتون میده ولی در عمل این اتفاق نمیوفته
قبل از داده‌ ای که برنامه استفاده میکنه Allocator چند بایت برای خودش کنار میذاره این قسمت همون Metadata هست

پس ساختار یک Chunk تقریبا این شکلیه:

+------------------+
| Metadata |
+------------------+
| User Data |
| |
| |
+------------------+

برنامه فقط به بخش User Data دسترسی داره اما Allocator از Metadata برای مدیریت Heap استفاده میکنه

داخل Metadata چه اطلاعاتی وجود داره؟
بسته به نوع Allocator ممکنه فرق داشته باشه اما معمولا اطلاعاتی مثل این‌ ها نگهداری میشن:

اندازه‌ی Chunk
وضعیت آزاد یا اشغال بودن
اطلاعات لازم برای مدیریت حافظه
ارتباط با Chunk های کناری در بعضی Allocator ها
این اطلاعات باعث میشن Allocator بدونه هر قسمت از Heap چه وضعیتی داره

چرا اندازه‌ی واقعی Chunk با چیزی که درخواست کرده فرق داره؟

فرض کنی این درخواست رو نوشتید:

malloc(100);

این به این معنی نیست که دقیقا 100 بایت از Heap اشغال میشه.

چون Allocator باید:

Metadata
رو ذخیره کنه
حافظه رو تراز (Alignment) کنه
اندازه‌ ها رو به واحد های مشخص گرد کنه
برای همین ممکنه در عمل بیشتر از 100 بایت مصرف بشه
این موضوع یکی از چیزهاییه که خیلی از برنامه‌نویس‌ها در ابتدا بهش توجه نمیکنن


Alignment
پردازنده دوست داره داده‌ ها روی مرز های مشخصی از حافظه قرار بگیرن
مثلا روی سیستم‌های 64 بیتی معمولا داده‌ ها روی مضرب‌های 8 یا 16 بایت تراز میشن این کار باعث میشه دسترسی به حافظه سریع‌ تر و بهینه‌ تر باشه
به همین دلیل Allocator بعضی وقتا اندازه‌ ی درخواستی رو کمی بزرگ‌ تر در نظر میگیره

وقتی free() صدا زده میشه چه اتفاقی میوفته؟

خیلی‌ها فکر میکنن با free() حافظه بلافاصله از بین میره
در واقع معمولا این‌طور نیست
بیشتر Allocator ها حافظه رو فقط آزاد علامت‌ گذاری میکنن تا بعدا دوباره از همون Chunk استفاده کنن
یعنی داده‌هایی که داخل اون Chunk بودن ممکنه هنوز در حافظه باقی مونده باشن فقط برنامه دیگه نباید از اونها استفاده کنه
به همین خاطر باگ‌ هایی مثل Use-After-Free به وجود میان یعنی برنامه بعد از آزاد شدن حافظه اشتباها دوباره به همون بخش دسترسی پیدا میکنه


Heap
از بخش‌هایی به نام Chunk تشکیل شده که هر کدام علاوه بر فضای مورد استفاده‌ ی برنامه اطلاعات مدیریتی هم دارن این اطلاعات به Allocator کمک میکنه تا حافظه رو مدیریت کنه همچنین حافظه‌ ای که با free() آزاد میشه معمولا بلافاصله پاک نمیشه بلکه برای استفاده‌ ی مجدد آماده نگه داشته میشه

@reverseengine
❤1
ReverseEngineering
Chunk دقیقا چیسه و چه ساختاری داره؟ در پست قبل گفتیم Heap از بخش‌ های کوچیکی به اسم Chunk تشکیل شده هر بار که برنامه از malloc() استفاده میکنه Allocator یک Chunk در اختیارش قرار میده اما این Chunk فقط یه تیکه حافظه ساده نیست اطلاعات مهمی هم داخلش وجود داره…
Chunk

What exactly is it and what is its structure?

In the previous post, we said that the Heap is made up of small sections called Chunk
Every time the program uses malloc(), the Allocator provides it with a Chunk, but this Chunk is not just a simple piece of memory, it also contains important information

Chunk
is not just the program's data
Suppose you request 100 bytes of memory from the Heap, you might think that the Allocator will give you exactly those 100 bytes, but in practice this does not happen
Before the data that the program uses, the Allocator sets aside a few bytes for itself. This part is called Metadata

So the structure of a Chunk is approximately like this:

+----+
| Metadata |
+------------------+
| User Data |
| |
| |
+------------------+

The program only has access to the User Data section, but the Allocator uses Metadata to manage the Heap

What information is inside Metadata?
It may vary depending on the type of Allocator, but usually information like this is kept:

Chunk size

Free or busy status

Information needed for memory management

Relationship with neighboring Chunks in some Allocators

This information lets the Allocator know what state each part of the Heap is in

Why is the actual Chunk size different from what it requested?

Suppose you wrote this request:

malloc(100);

This does not mean that exactly 100 bytes of the Heap will be occupied.

Because the Allocator must:

Store metadata

Align the memory

Round the sizes to specific units

This may actually use more than 100 bytes

This is something that many programmers don't pay attention to at first

Alignment

The processor likes data to be on specific memory boundaries

For example, on 64-bit systems, data is usually aligned on multiples of 8 or 16 bytes, which makes memory access faster and more efficient

For this reason, the Allocator sometimes considers the requested size to be slightly larger

What happens when free() is called?

Many people think that free() immediately destroys the memory
In fact, this is usually not the case
Most allocators only mark the memory as free so that they can use the same chunk again later
That means that the data inside that chunk may still be in memory, but the program should not use it anymore
That is why bugs like Use-After-Free occur, meaning that the program mistakenly accesses the same section again after the memory has been freed
Heap
Consists of sections called Chunks, each of which, in addition to the space used by the program, also has management information. This information helps the allocator to manage the memory. Also, the memory that is freed with free() is usually not immediately deleted, but is kept ready for reuse

@reverseengine
بخش بیست و سوم بافر اورفلو


Information Leak

یعنی برنامه ناخواسته اطلاعاتی از حافظه رو نمایش بده یا برگردونه که این اطلاعات میتونه شامل
آدرس‌ های حافظه
داده‌ های حساس
رشته‌ های محرمانه
محتوای متغیرها
باشه
یک مثال ساده:

#include <stdio.h>

int main() {

int numbers[5] = {1,2,3,4,5};

printf("%d\n", numbers[10]);

return 0;
}


مشکل این کجاست؟
برنامه داره مقداری خارج از آرایه رو میخونه ممکنه چیزی که چاپ میشه مربوط به یک متغیر دیگه یا بخشی از حافظه باشه
این یعنی اطلاعاتی که نباید دیده بشن نمایش داده شدن
یک مثال دیگه:

char secret[] = "password123";

printf("%s\n", secret);


اگر برنامه به اشتباه آدرس این رشته رو در اختیار کاربر قرار بده
یا مسیر اجرای برنامه طوری باشه که این داده نمایش داده بشه
یک Information Leak رخ داده

چرا برای مهندسی معکوس مهمه؟

فرض کنید یک برنامه ASLR داره
یعنی آدرس‌ های حافظه هر بار تغییر میکنن
اگر یک Information Leak پیدا کنید
ممکنه آدرس یکی از توابع یا کتابخانه‌ها رو به دست بیارید حالا میتونید تحلیل دقیق‌ تری انجام بدید و بفهمید برنامه چطور در حافظه قرار گرفته
به همین دلیل Information Leak خیلی وقت‌ها اولین قدم برای تحلیل آسیب‌پذیری‌ های پیچیده‌ تره

موقع تحلیل باینری دنبال چی بگردیم؟
اگر دیدید برنامه آدرس اشاره‌ گرها رو چاپ میکنه داده‌ ای خارج از محدوده میخونه
پیام‌ های خطای بیش از حد دقیق نمایش میده اطلاعات حافظه رو بدون بررسی برمیگردونه باید بیشتر بررسیش کنید

یک مثال اسمبلی:

lea rdi,[rip+message]
call puts


این خودش مشکلی نداره ولی اگر قبلا puts آدرس یا داده‌ ای از حافظه بدون کنترل آماده شده باشه باید بررسی کنید که آیا اطلاعات حساسی ممکنه نمایش داده بشه یا نه؟


Information Leak
برنامه اطلاعاتی رو که نباید در اختیار کاربر قرار بده نمایش میده این اطلاعات ممکنه برای تحلیل باینری یا پیدا کردن مسیرهای آسیب‌پذیر خیلی ارزشمند باشن برای یک Reverse Engineer پیدا کردن این نشت‌ های اطلاعاتی یکی از مهارت‌ های مهمه

@reverseengine
❤1
ReverseEngineering
بخش بیست و سوم بافر اورفلو Information Leak یعنی برنامه ناخواسته اطلاعاتی از حافظه رو نمایش بده یا برگردونه که این اطلاعات میتونه شامل آدرس‌ های حافظه داده‌ های حساس رشته‌ های محرمانه محتوای متغیرها باشه یک مثال ساده: #include <stdio.h> int main() { …
Part 23 Buffer Overflow


Information Leak

This means that the program unintentionally displays or returns information from memory, which can include
memory addresses
sensitive data
secret strings
variable contents
A simple example:

#include <stdio.h>

int main() {

int numbers[5] = {1,2,3,4,5};

printf("%d\n", numbers[10]);

return 0;
}


What is the problem?

The program is reading a value outside the array. What is printed may be related to another variable or part of memory.

This means that information that should not be seen is displayed.

Another example:

char secret[] = "password123";

printf("%s\n", secret);


If the program mistakenly provides the address of this string to the user
or the program execution path is such that this data is displayed
an Information Leak has occurred

Why is it important for reverse engineering?

Suppose a program has ASLR
that is, the memory addresses change every time
If you find an Information Leak
you may get the address of one of the functions or libraries. Now you can do a more detailed analysis and understand how the program is located in memory
That is why Information Leak is often the first step in analyzing more complex vulnerabilities

What should we look for when analyzing binary?

If you see that the program prints pointer addresses, reads data out of bounds, displays overly detailed error messages, returns memory information without checking, you should investigate further. Here is an assembly example: lea rdi,[rip+message] call puts This is not a problem, but if the address or data from memory has been prepared without checking, you should check whether sensitive information may be displayed. Information Leak The program displays information that should not be made available to the user. This information may be very valuable for binary analysis or finding vulnerable paths. Finding these information leaks is one of the important skills for a reverse engineer.


@reverseengine