Exploit Writting Tutorial From Basic To Intermediate
http://x9090.blogspot.com/2010/03/tutorial-exploit-writting-tutorial-from.html
@reverseengine
http://x9090.blogspot.com/2010/03/tutorial-exploit-writting-tutorial-from.html
@reverseengine
Blogspot
[TUTORIAL] Exploit Writting Tutorial From Basic To Intermediate
Malware analysis, vulnerability analysis, exploit analysis, exploit development, WIndows Kernel, Mac OS X. Anything about computer security
❤1
❤1
Reverse Engineering WhatsApp Encryption for Chat Manipulation
https://www.youtube.com/watch?v=N0Ne623fKWc
@reverseengine
https://www.youtube.com/watch?v=N0Ne623fKWc
@reverseengine
YouTube
Reverse Engineering WhatsApp Encryption for Chat Manipulation and More
We managed to reverse engineer WhatsApp web source code and successfully decrypted WhatsApp traffic. During the process we translated all WhatsApp web functions to python and created Burpsuit extension that you can use to investigate WhatsApp traffic and…
❤1
Pointers, References and Dynamic Memory Allocation
https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp4_PointerReference.html
@reverseengine
https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp4_PointerReference.html
@reverseengine
❤1
Local Variables روی استک
وقتی تابع متغیر محلی داره کامپایلر اون رو روی استک میزاره
ساختار فریم استک کامل
بعد از اجرای prologue:
ساختار میشه:
مثال:
اسمبلی:
نکات مهم:
متغیر t روی استک قرار میگیره آدرسش rbp-4
چون int هست سایز 4 بایت
eax خروجی تابع
Local Variables on the Stack
When a function has a local variable, the compiler pushes it onto the stack
Complete stack frame structure
After executing the prologue:
The structure becomes:
Example:
Assembly:
Important notes:
The variable t is placed on the stack, its address is rbp-4
Because it is an int, its size is 4 bytes
eax is the output of the function
@reverseengine
وقتی تابع متغیر محلی داره کامپایلر اون رو روی استک میزاره
ساختار فریم استک کامل
بعد از اجرای prologue:
push rbp
mov rbp, rsp
sub rsp, X ; ایجاد فضا برای متغیرهای محلی
ساختار میشه:
[ rbp+16 ] آرگومان سوم
[ rbp+8 ] آدرس برگشت
[ rbp+0 ] RBP قبلی
[ rbp-8 ] متغیر محلی 1
[ rbp-16 ] متغیر محلی 2
مثال:
int foo(int x) {
int t = x + 3;
return t * 2;
}
اسمبلی:
foo:
push rbp
mov rbp, rsp
sub rsp, 16 ; فضای متغیر محلی
mov DWORD PTR [rbp-4], edi ; t = x
add DWORD PTR [rbp-4], 3 ; t = x + 3
mov eax, DWORD PTR [rbp-4]
add eax, eax ; eax = t * 2
leave
ret
نکات مهم:
متغیر t روی استک قرار میگیره آدرسش rbp-4
چون int هست سایز 4 بایت
eax خروجی تابع
Local Variables on the Stack
When a function has a local variable, the compiler pushes it onto the stack
Complete stack frame structure
After executing the prologue:
push rbp
mov rbp, rsp
sub rsp, X ; Create space for local variables
The structure becomes:
[ rbp+16 ] Third argument
[ rbp+8 ] Return address
[ rbp+0 ] Previous RBP
[ rbp-8 ] Local variable 1
[ rbp-16 ] Local variable 2
Example:
int foo(int x) {
int t = x + 3;
return t * 2;
}
Assembly:
foo:
push rbp
mov rbp, rsp
sub rsp, 16 ; Local variable space
mov DWORD PTR [rbp-4], edi ; t = x
add DWORD PTR [rbp-4], 3 ; t = x + 3
mov eax, DWORD PTR [rbp-4]
add eax, eax ; eax = t * 2
leave
ret
Important notes:
The variable t is placed on the stack, its address is rbp-4
Because it is an int, its size is 4 bytes
eax is the output of the function
@reverseengine
👍4
ReverseEngineering
🔹 Red Zone در سیستم های x86-64 بر اساس ABI لینوکس پایین RSP اشارهگر استک یک محدودهی 160 بایتی وجود داره که به اون Red Zone میگن 🔸 این فضا مخصوص برای چیه؟ کامپایلر اجازه داره بدون تغییر RSP از این 160 بایت برای ذخیره موقت متغیر ها استفاده کنه 🔸 چرا…
چرا Exploit Dev به Red Zone حساسه؟
اگر روی استک payload میزارید shellcode/ROP ممکنه داخل Red Zone باشه
کامپایلر RSP رو تغییر نداده ولی دادهای که تزریق کرد داخل همون محدوده است
پس:
اگر تابع دیگه ای صدا زده بشه داده پاک میشه
اگر interrupt بشه کرش میکنه
چند تا payloadها با stomp شدن Red Zone از کار میوفتن
خیلی از فراخوانی های داخلی libc اولین کاری که میکنن اینه که از Red Zone استفاده بکنن
اگر ROP Chain شما داخل این محدوده باشه overwrite میشه کرش
Stack Alignment
وابسته به Red Zone
اگر اشتباهی فکر کنید فضای زیر RSP امن نیست ممکنه SUB/ADD اشتباه بزنی و استک misalign میشه
Misalignment:
سیستم کال کرش کنه
libc کرش کنه
ROP Chain درست اجرا نشه
مثال عملی
کد C
آدرس buffer پایین RSP است
اما RSP کم نشده!
این یعنی buffer داخل Red Zone هست
نکته طلایی:
کامپایلر حتی بدون رزرو استک در Red Zone متغیر میزاره
Why is Exploit Dev sensitive to Red Zone?
If you put the shellcode/ROP payload on the stack, it may be in the Red Zone
The compiler did not change the RSP, but the data it injected is in the same range
So:
If another function is called, the data will be cleared
If it is interrupted, it will crash
Some payloads will fail when the Red Zone is stomped
Many internal libc calls do the first thing they do is use the Red Zone
If your ROP Chain is in this range, it will be overwritten and crash
Stack Alignment
Dependent on the Red Zone
If you mistakenly think that the space below the RSP is not safe, you may make a SUB/ADD mistake and the stack will be misaligned
Misalignment:
System call crashes
libc crashes
ROP Chain does not execute correctly
Practical example
C code
The buffer address is below RSP
But RSP is not decreased!
This means the buffer is in the Red Zone
Golden tip:
The compiler places variables in the Red Zone even without stack reservation
@reverseengine
اگر روی استک payload میزارید shellcode/ROP ممکنه داخل Red Zone باشه
کامپایلر RSP رو تغییر نداده ولی دادهای که تزریق کرد داخل همون محدوده است
پس:
اگر تابع دیگه ای صدا زده بشه داده پاک میشه
اگر interrupt بشه کرش میکنه
چند تا payloadها با stomp شدن Red Zone از کار میوفتن
خیلی از فراخوانی های داخلی libc اولین کاری که میکنن اینه که از Red Zone استفاده بکنن
اگر ROP Chain شما داخل این محدوده باشه overwrite میشه کرش
Stack Alignment
وابسته به Red Zone
اگر اشتباهی فکر کنید فضای زیر RSP امن نیست ممکنه SUB/ADD اشتباه بزنی و استک misalign میشه
Misalignment:
سیستم کال کرش کنه
libc کرش کنه
ROP Chain درست اجرا نشه
مثال عملی
کد C
#include <stdio.h>
void test() {
char *p = (char *)__builtin_frame_address(0);
printf("RSP: %p\n", p);
char buffer[32];
buffer[0] = 'A';
printf("buffer: %p\n", buffer);
}
int main() {
test();
return 0;
}
آدرس buffer پایین RSP است
اما RSP کم نشده!
این یعنی buffer داخل Red Zone هست
نکته طلایی:
کامپایلر حتی بدون رزرو استک در Red Zone متغیر میزاره
Why is Exploit Dev sensitive to Red Zone?
If you put the shellcode/ROP payload on the stack, it may be in the Red Zone
The compiler did not change the RSP, but the data it injected is in the same range
So:
If another function is called, the data will be cleared
If it is interrupted, it will crash
Some payloads will fail when the Red Zone is stomped
Many internal libc calls do the first thing they do is use the Red Zone
If your ROP Chain is in this range, it will be overwritten and crash
Stack Alignment
Dependent on the Red Zone
If you mistakenly think that the space below the RSP is not safe, you may make a SUB/ADD mistake and the stack will be misaligned
Misalignment:
System call crashes
libc crashes
ROP Chain does not execute correctly
Practical example
C code
#include <stdio.h>
void test() {
char *p = (char *)__builtin_frame_address(0);
printf("RSP: %p\n", p);
char buffer[32];
buffer[0] = 'A';
printf("buffer: %p\n", buffer);
}
int main() {
test();
return 0;
}
The buffer address is below RSP
But RSP is not decreased!
This means the buffer is in the Red Zone
Golden tip:
The compiler places variables in the Red Zone even without stack reservation
@reverseengine
❤1👎1🔥1
چرا گجت ها یک دفعه کرش میکنن؟
خیلی وقتا ROP Chain رو درست مینویسید آفستها هم درسته ولی برنامه بعد از یکی دو گجت کرش میکنه
90 درصد مواقع دلیلش اینه:
دارید ROP رو داخل Red Zone میذارید
یعنی شما فکر میکنی RSP اینجاست ولی داده هایی که تزریق کردید تو 160 بایت پایین تره جایی که اصلا تضمین نشده سالم بمونه
یه تابع داخلی صدا زده میشه → Red Zone رو overwrite میکنه → ROP میره هوا
یه interrupt میاد → سیستم عامل اون فضا رو میگیره کرش میکنه
حتی یه printf ساده → Red Zone رو زیر پا میذاره → گجت بعدی اجرا نمیشه
سادهترین نمونه کرش در ROP
برنامه بعد از اجرای اولین گجت روی گجت دوم سیگنال میگیره و از بین میره
چون payload داخل Red Zone بوده و libc اون محدوده رو با دادههای خودش پر کرده
Why do gadgets crash all at once?
Many times you write the ROP Chain correctly, the offsets are correct, but the program crashes after one or two gadgets
90% of the time the reason is this:
You are putting the ROP in the Red Zone
That is, you think the RSP is here, but the data you injected is 160 bytes below where it is not guaranteed to be intact
An internal function is called → It overwrites the Red Zone → ROP goes to the air
An interrupt comes → The operating system takes that space and crashes
Even a simple printf → It violates the Red Zone → The next gadget does not run
The simplest example of a crash in ROP
After executing the first gadget, the program receives a signal on the second gadget and dies
Because the payload was in the Red Zone and libc filled that area with its own data
@reverseengine
خیلی وقتا ROP Chain رو درست مینویسید آفستها هم درسته ولی برنامه بعد از یکی دو گجت کرش میکنه
90 درصد مواقع دلیلش اینه:
دارید ROP رو داخل Red Zone میذارید
یعنی شما فکر میکنی RSP اینجاست ولی داده هایی که تزریق کردید تو 160 بایت پایین تره جایی که اصلا تضمین نشده سالم بمونه
یه تابع داخلی صدا زده میشه → Red Zone رو overwrite میکنه → ROP میره هوا
یه interrupt میاد → سیستم عامل اون فضا رو میگیره کرش میکنه
حتی یه printf ساده → Red Zone رو زیر پا میذاره → گجت بعدی اجرا نمیشه
سادهترین نمونه کرش در ROP
برنامه بعد از اجرای اولین گجت روی گجت دوم سیگنال میگیره و از بین میره
چون payload داخل Red Zone بوده و libc اون محدوده رو با دادههای خودش پر کرده
Why do gadgets crash all at once?
Many times you write the ROP Chain correctly, the offsets are correct, but the program crashes after one or two gadgets
90% of the time the reason is this:
You are putting the ROP in the Red Zone
That is, you think the RSP is here, but the data you injected is 160 bytes below where it is not guaranteed to be intact
An internal function is called → It overwrites the Red Zone → ROP goes to the air
An interrupt comes → The operating system takes that space and crashes
Even a simple printf → It violates the Red Zone → The next gadget does not run
The simplest example of a crash in ROP
After executing the first gadget, the program receives a signal on the second gadget and dies
Because the payload was in the Red Zone and libc filled that area with its own data
@reverseengine
❤1
خوندن آرگومان ها از استک وقتی زیاد باشن
در x86-64 SysV ABI
رجیستر های آرگومان ها به ترتیب:
اما اگر تعداد آرگومان ها بیشتر از 6 تا بشه بقیه روی استک قرار میگیره
تابع 8 آرگومانی
کد C:
ارگومانها:
محل آرگومان
فریم استک:
اسمبلی:
یعنی:
h از روی استک خونده میشه
a
در رجیستر edi هست
خروجی در eax
Reading arguments from the stack when there are many
In x86-64 SysV ABI
The argument registers are in order:
But if the number of arguments is more than 6, the rest are placed on the stack
8-argument function
C code:
Arguments:
Argument location
Stack frame:
Assembly:
That is:
h is read from the stack
a is in the edi register
output in eax
@reverseengine
در x86-64 SysV ABI
رجیستر های آرگومان ها به ترتیب:
1RDI
2 RSI
3 RDX
4 RCX
5 R8
6 R9
اما اگر تعداد آرگومان ها بیشتر از 6 تا بشه بقیه روی استک قرار میگیره
تابع 8 آرگومانی
کد C:
int f(int a, int b, int c, int d, int e, int f, int g, int h) {
return h + a;
}
ارگومانها:
محل آرگومان
a RDI
b RSI
c RDX
d RCX
e R8
f R9
g [rbp+16]
h [rbp+24]
فریم استک:
[rbp+16] → 7th argument
[rbp+24] → 8th argument
اسمبلی:
f:
push rbp
mov rbp, rsp
mov eax, DWORD PTR [rbp+24] ; h
add eax, edi ; + a
pop rbp
ret
یعنی:
h از روی استک خونده میشه
a
در رجیستر edi هست
خروجی در eax
Reading arguments from the stack when there are many
In x86-64 SysV ABI
The argument registers are in order:
1RDI
2 RSI
3 RDX
4 RCX
5 R8
6 R9
But if the number of arguments is more than 6, the rest are placed on the stack
8-argument function
C code:
int f(int a, int b, int c, int d, int e, int f, int g, int h) {
return h + a;
}
Arguments:
Argument location
a RDI
b RSI
c RDX
d RCX
e R8
f R9
g [rbp+16]
h [rbp+24]
Stack frame:
[rbp+16] → 7th argument
[rbp+24] → 8th argument
Assembly:
f:
push rbp
mov rbp, rsp
mov eax, DWORD PTR [rbp+24] ; h
add eax, edi ; + a
pop rbp
ret
That is:
h is read from the stack
a is in the edi register
output in eax
@reverseengine
👍3
بخش نهم بافر اورفلو
محافظ ها و راه های مقابله با بافر اورفلو
تو این قسمت میخوایم یاد بگیریم وقتی میخواید بافر اورفلو بزنید چه چیزایی جلوتونو میگیرن
چطور بفهمیم فعالن
و چرا اصلا کار رو سخت میکنن
این بخش خیلی مهمه چون بدون درک همین ها اصلا exploit نوشتن معنی نداره
Stack Canary
یه مقدار رندوم میاد بین بافر و return address قرار میگیره
کاری که میکنه اینه هرچی رو استک خراب بشه اول این مقدار تغییر میکنه
وقتی تابع میخواد برگرده چک میکنه کاناری خراب شده یا نه
خراب شده = برنامه میپره بیرون و نمیذاره به return address دست بزنید
چطور بفهمیم کاناری فعاله
فقط با کامپایل کردن برنامه میفهمید
gcc -fstack-protector-all file.c -o out
یا موقع آنالیز باینری
checksec ./out
اگر نوشت Canary:
Yes یعنی فعاله
NX یا DEP
NX یعنی Memory eXecute
نشه
یعنی استک و هیپ فقط برای داده ن نه برای اجرای کد
قبلا shellcode رو میذاشتید تو استک و مستقیم اجرا میکردید
الان با NX دیگه نمیذاره
چطور بفهمیم NX فعاله
checksec ./out
اگر نوشت NX:
enabled یعنی این مسیر بسته است
یعنی نمیشه shellcode رو مستقیم اجرا کرد و باید برید سمت ret2libc یا ROP
ASLR
Random کردن آدرسذهای حافظه
libc هر بار میره یه جای جدید
heap یه جای جدید
استک یه جای جدید
این باعث میشه exploit ثابت ننویسید
چون آدرس win یا system یا /bin/sh هر بار عوض میشه
چطور بفهمیم ASLR فعاله
cat /proc/sys/kernel/randomize_va_space
اگر 2 بود یعنی کاملا فعاله
PIE
Position Independent Executable
یعنی خود باینری هم هر بار تو یه جای جدید لود میشه
بدتر از ASLR
چون دیگه حتی آدرس تابع های داخل خود برنامه هم ثابت نیست
چطور بفهمیم PIE فعاله
checksec ./out
اگر نوشت PIE:
enabled یعنی برنامه آدرس ثابت نداره
CF
Control Flow Integrity
این یکی خیلی جدید تره
واقعا میگه هرجا خواستید بپرید باید از یه لیست معتبر باشه
غیر از اون اجازه نمیده
خیلی سختتره دور زدنش و تو real-world معمولا تو مرورگرها و کرنل استفاده میشه
Part 9 Buffer Overflow
Protectors and ways to deal with buffer overflow
In this part, we want to learn what things stop you when you want to overflow a buffer
How to know if they are active
And why they make it difficult at all
This part is very important because without understanding these, there is no point in writing an exploit
Stack Canary
A random value is placed between the buffer and the return address
What it does is that whenever the stack is corrupted, this value changes first
When the function wants to return, it checks if the canary is corrupted or not
Corrupted = the program exits and does not let you touch the return address
How to know if the canary is active
You can only find out by compiling the program
gcc -fstack-protector-all file.c -o out
Or during binary analysis
checksec ./out
If it says Canary:
Yes means active
NX or DEP
NX means Memory eXecute
Not possible
That means the stack and heap are only for data, not for execution Code
Previously you put the shellcode on the stack and executed it directly
Now it doesn't work with NX
How to tell if NX is enabled
checksec ./out
If it says NX:
enabled, this path is closed
That means you can't execute the shellcode directly and you have to go to ret2libc or ROP
ASLR
Randomizing memory addresses
libc goes to a new location every time
heap to a new location
stack to a new location
This prevents you from writing a fixed exploit
Because the address of win or system or /bin/sh changes every time
How to tell if ASLR is enabled
cat /proc/sys/kernel/randomize_va_space
If it was 2, it means it's fully enabled
PIE
Position Independent Executable
That means the binary itself is loaded in a new location every time
Worse than ASLR
Because even the addresses of the functions inside the program itself are no longer fixed
How to tell if PIE is enabled
checksec ./out
If it says PIE:
enabled, it means The program does not have a fixed address
CF
Control Flow Integrity
This one is much newer
It actually says that wherever you want to jump, it must be from a valid list
It does not allow anything else
It is much harder to bypass and in the real-world it is usually used in browsers and kernels
@reverseengine
❤3
🔥 آرایه روی استک یکی از مهم ترین پایه های ریورس
چرا آرایه روی استک مهمه؟
چون در باینری ها همیشه اینا رو میبینید:
باید بفهمید:
چطور آدرس دهی میشن
چطور روی استک قرار میگیرن
چطور از طریق rbp-XX بهشون دسترسی داده میشه
چطور حلقه ها روی آرایه اجرا میشن
ساختار آرایه روی استک
کد C:
نوع int = چهار بایت
4 تا int → میشه 16 بایت
در اسمبلی:
محل ذخیره آرایه:
نوشتن مقدار ها داخل آرایه
کد C:
اسمبلی:
چرا rbp-12
چون:
هر int چهار بایته = جمع هر ایندکس چهار تا چهار تا جلو میره
🔥 Arrays on the Stack
Arrays on the stack are one of the most important foundations of reverse
Why are arrays on the stack important?
Because in binaries you always see these:
You need to understand:
How are they addressed
How are they placed on the stack
How are they accessed via rbp-XX
How are loops executed on arrays
Array structure on the stack
C code:
Type int = four bytes
4 to int → becomes 16 bytes
In assembly:
Array storage location:
Writing values into an array
C code:
Assembly:
Why rbp-12
Why:
Each int is four bytes = the sum of each index goes forward by four
@reverseengine
چرا آرایه روی استک مهمه؟
چون در باینری ها همیشه اینا رو میبینید:
buff[64]
arr[10]
int nums[5]
char name[32]
باید بفهمید:
چطور آدرس دهی میشن
چطور روی استک قرار میگیرن
چطور از طریق rbp-XX بهشون دسترسی داده میشه
چطور حلقه ها روی آرایه اجرا میشن
ساختار آرایه روی استک
کد C:
void f() {
int arr[4];
}
نوع int = چهار بایت
4 تا int → میشه 16 بایت
در اسمبلی:
push rbp
mov rbp, rsp
sub rsp, 16 ; arr[4] = 16 bytes
محل ذخیره آرایه:
rbp-4 → arr[0]
rbp-8 → arr[1]
rbp-12 → arr[2]
rbp-16 → arr[3]
نوشتن مقدار ها داخل آرایه
کد C:
void f() {
int arr[4];
arr[2] = 7;
}
اسمبلی:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-12], 7 ; arr[2]
چرا rbp-12
چون:
arr[0] → rbp-4
arr[1] → rbp-8
arr[2] → rbp-12
arr[3] → rbp-16
هر int چهار بایته = جمع هر ایندکس چهار تا چهار تا جلو میره
🔥 Arrays on the Stack
Arrays on the stack are one of the most important foundations of reverse
Why are arrays on the stack important?
Because in binaries you always see these:
buff[64]
arr[10]
int nums[5]
char name[32]
You need to understand:
How are they addressed
How are they placed on the stack
How are they accessed via rbp-XX
How are loops executed on arrays
Array structure on the stack
C code:
void f() {
int arr[4];
}
Type int = four bytes
4 to int → becomes 16 bytes
In assembly:
push rbp
mov rbp, rsp
sub rsp, 16 ; arr[4] = 16 bytes
Array storage location:
rbp-4 → arr[0]
rbp-8 → arr[1]
rbp-12 → arr[2]
rbp-16 → arr[3]
Writing values into an array
C code:
void f() {
int arr[4];
arr[2] = 7;
}
Assembly:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-12], 7 ; arr[2]
Why rbp-12
Why:
arr[0] → rbp-4
arr[1] → rbp-8
arr[2] → rbp-12
arr[3] → rbp-16
Each int is four bytes = the sum of each index goes forward by four
@reverseengine
❤1
Dump Steal and Decrypt Google Chrome Passwords (Windows)
https://github.com/thatskriptkid/ChromePass
@reverseengine
https://github.com/thatskriptkid/ChromePass
@reverseengine
GitHub
GitHub - thatskriptkid/ChromePass: Dump/Steal and decrypt Google Chrome passwords (Windows)
Dump/Steal and decrypt Google Chrome passwords (Windows) - GitHub - thatskriptkid/ChromePass: Dump/Steal and decrypt Google Chrome passwords (Windows)
❤1
Malware Analysis of Sepsis Ransomware
https://www.reddit.com/r/MalwareAnalysis/comments/bgf71t/malware_analysis_of_sepsis_ransomware
@reverseengine
https://www.reddit.com/r/MalwareAnalysis/comments/bgf71t/malware_analysis_of_sepsis_ransomware
@reverseengine
Reddit
From the MalwareAnalysis community on Reddit: Malware analysis of Sepsis ransomware
Explore this post and more from the MalwareAnalysis community
🔥5❤1
Forwarded from Fuzzing ZONE (0x0F1)
Unleashing the Kraken ransomware group
https://blog.talosintelligence.com/kraken-ransomware-group/
@FUZZ0x
https://blog.talosintelligence.com/kraken-ransomware-group/
@FUZZ0x
Cisco Talos Blog
Unleashing the Kraken ransomware group
In August 2025, Cisco Talos observed big-game hunting and double extortion attacks carried out by Kraken, a Russian-speaking group that has emerged from the remnants of the HelloKitty ransomware cartel.
❤1
ARM64 Reversing And Exploitation
https://8ksec.io/arm64-reversing-and-exploitation-part-5-writing-shellcode-8ksec-blogs/
@reverseengine
https://8ksec.io/arm64-reversing-and-exploitation-part-5-writing-shellcode-8ksec-blogs/
@reverseengine
❤1
بخش دهم بافر اورفلو
پیدا کردن دقیق نقطه کرش
تا الان فهمیدیم برنامه کجا کرش میکنه ولی نمیدونیم دقیقا کدوم بخش از ورودی ما باعث میشه RIP/ EIP overwrite بشه
الان میخوایم با یک روش دقیق بفهمیم که مثلا بعد از چند کاراکتر مقدار ریجستر EIP/RIP توسط ورودی ما کنترل میشه
این مرحله خیلی مهمه چون بدونش نمیتونیم شلکد اجرا کنیم
ساختن یک الگوی خاص برای تشخیص آفست
به جای اینکه هزار تا "A" پشت هم بفرستیم یک رشته Unique میسازیم
اینکار باعث میشه وقتی برنامه کرش کرد از روی مقدار رجیستر بفهمیم که آفست دقیق چنده
Python
from pwn import *این 300 تا کاراکتر الگوی خاص میده که هیچ تکراری توش نیست
pattern = cyclic(300)
print(pattern)
اجرای برنامه با این الگو
الگو رو میریزیم داخل برنامه:
./vuln $(python3 pattern.py)
برنامه کرش میکنه
حالا مقدار RIP/EIP رو چک میکنیم:
gdb:
(gdb) run <<< $(python3 pattern.py)
(gdb) info registers
مقدار RIP:
0x6161616c
پیدا کردن آفست دقیق
حالا این مقدار رو به ابزار سایکلیک میدیم تا بهمون بگه دقیقا چندمین کاراکتر بوده:
cyclic_find(0x6161616c)
خروجی:
112
یعنی دقیقا بعد از 112 کاراکتر ما میتونیم رجیستر رو کنترل کنیم
Part 10 Buffer Overflow
Finding the Exact Offset
So far we have understood where the program crashes, but we do not know exactly which part of our input causes the RIP/EIP to be overwritten
Now we want to find out in an exact way, for example, after how many characters the value of the EIP/RIP register is controlled by our input
This step is very important because without it we cannot run the shellcode
Creating a special pattern to detect the offset
Instead of sending a thousand "A"s in a row, we create a Unique string
This will allow us to find out the exact offset from the register value when the program crashes
Python
from pwn import *
pattern = cyclic(300)
print(pattern)
These 300 characters give a special pattern that has no repetitions
Executing the program with this pattern
We put the pattern into the program:
./vuln $(python3 pattern.py)
The program crashes
Now the value of the RIP/EIP We check:
gdb:
(gdb) run <<< $(python3 pattern.py)
(gdb) info registers
RIP value:
0x6161616c
Finding the exact offset
Now we give this value to the cyclic tool to tell us exactly what character it was:
cyclic_find(0x6161616c)
Output:
112
That is, exactly after 112 characters we can check the register
@reverseengine
❤5
Calling Convention
توضیح:
قانونیه که میگه آرگومان ها چطور به تابع داده میشن و نتیجه چطور برمیگرده
وقتی دارید مهندسی معکوس میکنی اگه Convention رو نشناسید اصلا نمیفهمید تابع چی از کجا ورودی میگیره و چی رو تغییر میده
سه Convention مهم برای مهندسی معکوس
فقط همین سهتا رو باید مسلط باشید بقیه شون یا قدیمین یا کم استفاده
System V AMD64 برای لینوکس و مک
شش آرگومان اول داخل رجیسترها:
بقیه آرگومانها روی استک
اگه کد لینوکسه نگاهتون اول باید بره سراغ RDI و RSI %90 آرگومان ها اونجاست
Windows x64 Convention
چهار آرگومان اول در رجیستر ها:
ویندوز فقط چهار تا رجیستر میده بهتون بقیش میره رو استک
Stack-based (cdecl / stdcall / fastcall قدیمی تر
اینا تو x86 زیاد بودن تو x64 کمتر
ولی هنوز هستت
همه آرگومان ها روی استک
return
در RAX یا EAX
Caller یا Callee
استک رو تمیز میکنه بسته به نوع
اگر دیدید قبل از call کلی push push push انجام شد تقریبا یعنی Convention قدیمیه
چطور توی دیساسمبلی Convention رو تشخیص بدیم (Detect)
رجیستر هایی که قبل از call مقدار میگیرن
بعضی compilerها قبل از شروع تابع shadow space میذارن فقط تو ویندوز
یعنی:
اینجا ویندوزه Convention: Windows x64
Calling Convention
Explanation:
A rule that says how arguments are given to a function and how the result is returned
When you are reverse engineering, if you do not know the Convention, you will not understand at all what the function takes input from, where it comes from, and what it changes
Three important conventions for reverse engineering
You only need to master these three, the rest are either old or rarely used
System V AMD64 for Linux and Mac
The first six arguments are in the registers:
The rest of the arguments are on the stack
return value → RAX
If it is Linux code, your first look should be at RDI and RSI, 90% of the arguments are there
Windows x64 Convention
The first four arguments are in the registers:
The rest of the arguments are on the stack
return RAX
Windows only provides four registers The rest goes to the stack
Stack-based (older cdecl / stdcall / fastcall
This was more in x86, less in x64
But it's still there
All arguments on the stack
return
in RAX or EAX
Caller or Callee
Cleans the stack depending on the type
If you see a whole push push push done before the call, it almost means the Convention is old
How to detect the Convention in disassembly
Registers that get values before the call
Some compilers put a shadow space before the function starts, only in Windows
Meaning:
Here is Windows Convention: Windows x64
@reverseengine
توضیح:
قانونیه که میگه آرگومان ها چطور به تابع داده میشن و نتیجه چطور برمیگرده
وقتی دارید مهندسی معکوس میکنی اگه Convention رو نشناسید اصلا نمیفهمید تابع چی از کجا ورودی میگیره و چی رو تغییر میده
سه Convention مهم برای مهندسی معکوس
فقط همین سهتا رو باید مسلط باشید بقیه شون یا قدیمین یا کم استفاده
System V AMD64 برای لینوکس و مک
شش آرگومان اول داخل رجیسترها:
RDI, RSI, RDX, RCX, R8, R9
بقیه آرگومانها روی استک
return value → RAX
اگه کد لینوکسه نگاهتون اول باید بره سراغ RDI و RSI %90 آرگومان ها اونجاست
Windows x64 Convention
چهار آرگومان اول در رجیستر ها:
RCX, RDX, R8, R9
بقیه آرگومانها روی استک
return RAX
ویندوز فقط چهار تا رجیستر میده بهتون بقیش میره رو استک
Stack-based (cdecl / stdcall / fastcall قدیمی تر
اینا تو x86 زیاد بودن تو x64 کمتر
ولی هنوز هستت
همه آرگومان ها روی استک
return
در RAX یا EAX
Caller یا Callee
استک رو تمیز میکنه بسته به نوع
اگر دیدید قبل از call کلی push push push انجام شد تقریبا یعنی Convention قدیمیه
چطور توی دیساسمبلی Convention رو تشخیص بدیم (Detect)
رجیستر هایی که قبل از call مقدار میگیرن
RDI/RSI
قطعا System V
RCX/RDX
تقریبا همیشه Windows x64
push
پشت هم احتمالا stack-based
prologue
بعضی compilerها قبل از شروع تابع shadow space میذارن فقط تو ویندوز
sub rsp, 0x20
یعنی:
اینجا ویندوزه Convention: Windows x64
Calling Convention
Explanation:
A rule that says how arguments are given to a function and how the result is returned
When you are reverse engineering, if you do not know the Convention, you will not understand at all what the function takes input from, where it comes from, and what it changes
Three important conventions for reverse engineering
You only need to master these three, the rest are either old or rarely used
System V AMD64 for Linux and Mac
The first six arguments are in the registers:
RDI, RSI, RDX, RCX, R8, R9
The rest of the arguments are on the stack
return value → RAX
If it is Linux code, your first look should be at RDI and RSI, 90% of the arguments are there
Windows x64 Convention
The first four arguments are in the registers:
RCX, RDX, R8, R9
The rest of the arguments are on the stack
return RAX
Windows only provides four registers The rest goes to the stack
Stack-based (older cdecl / stdcall / fastcall
This was more in x86, less in x64
But it's still there
All arguments on the stack
return
in RAX or EAX
Caller or Callee
Cleans the stack depending on the type
If you see a whole push push push done before the call, it almost means the Convention is old
How to detect the Convention in disassembly
Registers that get values before the call
RDI/RSI
Definitely System V
RCX/RDX
Almost always Windows x64
push
Back to back probably stack-based
prologue
Some compilers put a shadow space before the function starts, only in Windows
sub rsp, 0x20
Meaning:
Here is Windows Convention: Windows x64
@reverseengine
❤1
ReverseEngineering
Calling Convention توضیح: قانونیه که میگه آرگومان ها چطور به تابع داده میشن و نتیجه چطور برمیگرده وقتی دارید مهندسی معکوس میکنی اگه Convention رو نشناسید اصلا نمیفهمید تابع چی از کجا ورودی میگیره و چی رو تغییر میده سه Convention مهم برای مهندسی معکوس…
مثال تشخیص Calling Convention
دیساسمبلی:
این خط داریم دو آرگومان به func میدیم چون RDI/RSI هست پس کد لینوکسه و
Convention = System V
Example of Calling Convention Detection
Disassembly:
In this line, we are giving two arguments to func because it is RDI/RSI, so it is Linux code and Convention = System V
@reverseengine
دیساسمبلی:
mov rdi, rax
mov rsi, rbx
call func
این خط داریم دو آرگومان به func میدیم چون RDI/RSI هست پس کد لینوکسه و
Convention = System V
Example of Calling Convention Detection
Disassembly:
mov rdi, rax
mov rsi, rbx
call func
In this line, we are giving two arguments to func because it is RDI/RSI, so it is Linux code and Convention = System V
@reverseengine
❤1