I Broke My Filesystem 35 Different Ways to Prove My Recovery Tool Works
https://levelup.gitconnected.com/i-broke-my-filesystem-35-different-ways-to-prove-my-recovery-tool-works-dc3d972195e1
https://levelup.gitconnected.com/i-broke-my-filesystem-35-different-ways-to-prove-my-recovery-tool-works-dc3d972195e1
Medium
I Broke My Filesystem 35 Different Ways to Prove My Recovery Tool Works
How I reverse-engineered Apple’s filesystem, built a recovery tool in C and Python, and achieved a 98.5% recovery rate
How I Recovered a Password from a Linux Binary Using Ghidra
https://revs3k.medium.com/how-i-recovered-a-password-from-a-linux-binary-using-ghidra-625b51561751
https://revs3k.medium.com/how-i-recovered-a-password-from-a-linux-binary-using-ghidra-625b51561751
Medium
How I Recovered a Password from a Linux Binary Using Ghidra
Introduction
دوستان ببخشید اگه نمیرسم پست بزارم درگیر یک پروژه هستم سعیمو میکنم از فردا دوباره بزارم خیلی عذر میخام🩶
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🖤
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 کمک میکنه بفهمید چرا این جا به جایی ها اتفاق میوفتن و چرا ترتیب اجرای کد همیشه خطی نیست
این مفهوم همچنین پایه ای برای درک مباحث پیشرفته تر مثل:
Context Switch:
ذخیره وضعیت Process فعلی در PCB
اپلود وضعیت Process بعدی از PCB
ادامه اجرای Process جدید از همون نقطه قبلی
این مکانیزم باعث میشه چندین برنامه روی یک CPU بهصورت روون اجرا بشن
@reverseengine
وقتی 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
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
داخل هر 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
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
دقیقا چیسه و چه ساختاری داره؟
در پست قبل گفتیم 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
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
Reversing A Network Protocol
https://blog.didierstevens.com/2024/05/25/reversing-a-network-protocol
@reverseengine
https://blog.didierstevens.com/2024/05/25/reversing-a-network-protocol
@reverseengine
Didier Stevens
Reversing A Network Protocol
I also recorded a video for this blog post. I recently helped a colleague and friend with the reversing of a network protocol to update an IOT device. As I can’t be more specific for the mome…
Another Exercise In Encoding Reversing
https://blog.didierstevens.com/2022/06/20/another-exercise-in-encoding-reversing
@reverseengine
https://blog.didierstevens.com/2022/06/20/another-exercise-in-encoding-reversing
@reverseengine
Didier Stevens
Another Exercise In Encoding Reversing
I also recorded a video for this blog post. In this blog post, I will show how to decode a payload encoded in a variation of hexadecimal encoding, by performing statistical analysis and guessing so…
👍1
Quickpost: Machine Code Infinite Loop
https://blog.didierstevens.com/2022/04/30/quickpost-machine-code-infinite-loop
@reverseengine
https://blog.didierstevens.com/2022/04/30/quickpost-machine-code-infinite-loop
@reverseengine
Didier Stevens
Quickpost: Machine Code Infinite Loop
Someone asked me what the byte sequence is for an infinite loop in x86 machine code (it’s something you could use while debugging, for example). That byte sequence is just 2 bytes long: EB FE…
Process API
برنامه ها چطور با سیستم عامل صحبت میکنن
تا اینجا فهمیدیم سیستم عامل میتونه Process بسازه اجرا کنه و بین اونا جا به جا بشه
اما یک سوال مهم:
برنامه ها چطور به سیستم عامل میگن که یک Process جدید بساز یا یک برنامه رو اجرا کن؟
آیا مستقیما با کرنل صحبت میکنن؟
نه
برنامهها از چیزی به نام API (Application Programming Interface) استفاده میکنند
API
رو میتونیم مثل یک واسطه بین برنامه و سیستم عامل در نظر بگیریم
API
یعنی چی؟
فرض کنید به یک رستوران رفتید
شما مستقیم وارد آشپزخانه نمیشید تا غذا درست کنید
سفارش رک به گارسون میدید گارسون اون رو به آشپز میرسونه و بعد غذا رو براتون میارن
در این مثال:
آشپز = Kernel
گارسون = API
مشتری = برنامه
برنامه هم به همین شکل درخواستش رو از طریق API به سیستم عامل میفرسته
Process API
چیه؟
Process API
مجموعهای از توابع که به برنامه اجازه میده Processها رو مدیریت کنه
مثلا:
ساختن یک Process جدید
اجرای یک برنامه
منتظر موندن تا پایان یک Process
تموم شدن به یک Process
مهمترین توابع در لینوکس
در لینوکس بیشتر با این سه تابع آشنا میشید:
وظیفهاش ساختن یک Process جدیده
وقتی
بعد از اون دو Process وجود دارند:
Parent (والد)
Child (فرزند)
هر دو از همون نقطه به اجرای خودشون ادامه میدن
بعضی وقتا نمیخایم فقط یک کپی از Process داشته باشیم میخایم برنامه دیگه ای اجرا بشه
اینجاست که
برنامه فعلی رو با یک برنامه جدید جایگزین میکنه
مثلا یک Shell بعد از گرفتن دستور کاربر با
اگر Process والد بخاد صبر کنه تا Process فرزند کارش تموم بشه از
بدون
یک مثال واقعی:
فرض کنید در ترمینال مینویسید:
پشت صحنه تقریبا این اتفاق ها میوفته:
Shell
یک Process جدید با
Process
فرزند با
Process
والد با
همه این مراحل در کسری از ثانیه انجام میشن
چرا این موضوع مهمه؟
اگر روی لینوکس برنامه ها یا بدافزار ها رو تحلیل کنید به مرتب با این توابع رو به رو میشید همچنین در ویندوز هم مفاهیم مشابه ای وجود دارن فقط اسم توابع فرق میکنه برای مثال ایجاد Process در ویندوز معمولا با توابعی مانند
انجام میشه اما ایده اصلی همونه:
درخواست از سیستم عامل برای ساخت و مدیریت یک Process
Process API
راه ارتباط برنامه با سیستم عامل برای مدیریت Process هاست
سه تابع مهم:
منتظر موندن برای تموم شدن Process فرزند
اگر این سه تابع رو خوب بفهمید درک نحوه اجرای برنامه ها داخل لینوکس و حتی مفاهیم مشابه در ویندوز براتون بسیار راحت تره
برنامه ها چطور با سیستم عامل صحبت میکنن
تا اینجا فهمیدیم سیستم عامل میتونه Process بسازه اجرا کنه و بین اونا جا به جا بشه
اما یک سوال مهم:
برنامه ها چطور به سیستم عامل میگن که یک Process جدید بساز یا یک برنامه رو اجرا کن؟
آیا مستقیما با کرنل صحبت میکنن؟
نه
برنامهها از چیزی به نام API (Application Programming Interface) استفاده میکنند
API
رو میتونیم مثل یک واسطه بین برنامه و سیستم عامل در نظر بگیریم
API
یعنی چی؟
فرض کنید به یک رستوران رفتید
شما مستقیم وارد آشپزخانه نمیشید تا غذا درست کنید
سفارش رک به گارسون میدید گارسون اون رو به آشپز میرسونه و بعد غذا رو براتون میارن
در این مثال:
آشپز = Kernel
گارسون = API
مشتری = برنامه
برنامه هم به همین شکل درخواستش رو از طریق API به سیستم عامل میفرسته
Process API
چیه؟
Process API
مجموعهای از توابع که به برنامه اجازه میده Processها رو مدیریت کنه
مثلا:
ساختن یک Process جدید
اجرای یک برنامه
منتظر موندن تا پایان یک Process
تموم شدن به یک Process
مهمترین توابع در لینوکس
در لینوکس بیشتر با این سه تابع آشنا میشید:
fork()وظیفهاش ساختن یک Process جدیده
وقتی
fork() اجرا میشه سیستمعامل از Process فعلی یک کپی میسازهبعد از اون دو Process وجود دارند:
Parent (والد)
Child (فرزند)
هر دو از همون نقطه به اجرای خودشون ادامه میدن
exec()بعضی وقتا نمیخایم فقط یک کپی از Process داشته باشیم میخایم برنامه دیگه ای اجرا بشه
اینجاست که
exec() وارد عمل میشهexec()برنامه فعلی رو با یک برنامه جدید جایگزین میکنه
مثلا یک Shell بعد از گرفتن دستور کاربر با
exec() برنامه ای مثل ls یا cat رو اجرا میکنهwait()اگر Process والد بخاد صبر کنه تا Process فرزند کارش تموم بشه از
wait() استفاده میکنهبدون
wait() ممکنه والد زودتر ادامه پیدا کنه و ترتیب اجرای برنامه به هم بخورهیک مثال واقعی:
فرض کنید در ترمینال مینویسید:
python script.py
پشت صحنه تقریبا این اتفاق ها میوفته:
Shell
یک Process جدید با
fork() ایجاد میکنهProcess
فرزند با
exec() برنامه Python رو اجرا میکنهProcess
والد با
wait() منتظر میمونه تا اجرای اسکریپت تموم بشههمه این مراحل در کسری از ثانیه انجام میشن
چرا این موضوع مهمه؟
اگر روی لینوکس برنامه ها یا بدافزار ها رو تحلیل کنید به مرتب با این توابع رو به رو میشید همچنین در ویندوز هم مفاهیم مشابه ای وجود دارن فقط اسم توابع فرق میکنه برای مثال ایجاد Process در ویندوز معمولا با توابعی مانند
CreateProcessانجام میشه اما ایده اصلی همونه:
درخواست از سیستم عامل برای ساخت و مدیریت یک Process
Process API
راه ارتباط برنامه با سیستم عامل برای مدیریت Process هاست
سه تابع مهم:
fork() → ساختن Process جدیدexec() → اجرای یک برنامه جدیدwait()منتظر موندن برای تموم شدن Process فرزند
اگر این سه تابع رو خوب بفهمید درک نحوه اجرای برنامه ها داخل لینوکس و حتی مفاهیم مشابه در ویندوز براتون بسیار راحت تره
👍1