ReverseEngineering
1.32K subscribers
50 photos
11 videos
108 files
895 links
Download Telegram
Forwarded from Source Byte
Static Devirtualization of Themida
This article demonstrates devirtualization of CodeVirtualizer/Themida protected code, however the techniques described here apply to pretty much every virtual machine based obfuscator. Only requiring some minor modifications to support each of them. The following is a non-exhaustive list of obfuscators that can be reduced using the technique described in this article.

https://back.engineering/blog/09/05/2026/
Shared_library_hijacking.pdf
2.8 MB
Resolving the Correct Library: A Loader-Level Defense Solution Against Shared Object Hijackin
hooking_windows_named_pipes.pdf
1.5 MB
Hooking Windows Named Pipes
بخش هفدهم بافر اورفلو


چطور فقط با نگاه کردن به اسمبلی بافر اورفلو پیدا کنیم

قراره چی کار کنیم

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

نشونه اول

وجود بافر روی استک

مثال:
Asm

sub rsp, 0x40


این یعنی 64 بایت فضا روی استک رزرو شده
اگر چند خط پایین تر دیدید

Asm

lea rax, [rbp-0x40]


یا
Asm

lea rcx, [rsp+0x10]


معمولاً با یک بافر طرف هستید

نشونه دوم
ورودی کاربر وارد بافر میشه

مثال
Asm

mov rdi, rax
call gets


یا
Asm

call fgets


یا
Asm

call read


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

نشونه سوم

کپی بدون بررسی طول

مثال:
Asm

call strcpy

یا
Asm

call strcat


یا
Asm

call sprintf


اینها زنگ خطرهای کلاسیک هستن
چون طول ورودی رو چک نمیکنن

نشونه چهارم

بافر کوچک ورودی بزرگ
مثلا اینو تو دی‌ کامپایلر ببینید
C

char buf[16];
strcpy(buf,input);


یا تو اسمبلی ببینید
Asm

lea rdi,[rbp-0x10]
call strcpy


بافر فقط 16 بایته
ولی هیچ محدودیتی برای input وجود نداره
پس احتمال بافر اورفلو زیاده

نشونه پنجم

نبودن Canary
اگر اول تابع این چیزها رو ندیدید

Asm

mov rax, qword ptr fs:[0x28]
mov [rbp-0x8], rax


احتمالا Stack Canary وجود نداره
وجود این دستورات معمولا نشون میده کامپایلر محافظ استک فعال کرده

نشونه شیشم

تابع قبل از ret هیچ بررسی انجام نمیده
تابع آسیب‌پذیر معمولا آخرش این شکلیه

Asm

leave
ret


اگر قبل از ret هیچ بررسی امنیتی انجام نشه و بالاتر strcpy دیده باشید باید بیشتر دقت کنید

مثال واقعی تحلیل:

فرض کنید این اسمبلی رو دیدید

Asm

push rbp
mov rbp,rsp
sub rsp,0x20

mov rdx,rdi

lea rax,[rbp-0x10]
mov rdi,rax

call strcpy

leave
ret

سوال

آیا این مشکوکه؟

جواب

بله

چون
Asm

lea rax,[rbp-0x10]


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

و
Asm

call strcpy


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

تمرین:
یک باینری ساده رو داخل Ghidra یا IDA باز کنید

سه مورد زیر رو پیدا کنید

محل ساخت بافر
محل ورود داده
محل کپی شدن داده

اگر این سه مورد رو پیدا کردید عملا دارید مثل یک Reverse Engineer واقعی فکر میکنید


Part 17 Buffer Overflow


How to find buffer overflow just by looking at the assembly

What are we going to do

So far we have understood what dangerous functions are and how stack frames are created

Now we are going to learn how to find out if there is a buffer overflow even if we don't have the source code just from the assembly

First example

There is a buffer on the stack

Example:

Asm

sub rsp, 0x40


This means that 64 bytes of space on the stack are reserved

If you see a few lines below

Asm

lea rax, [rbp-0x40]


or

Asm

lea rcx, [rsp+0x10]


Usually you are dealing with a buffer

Second example

User input enters the buffer

Example

Asm

mov rdi, rax
call gets


or

Asm

call fgets


or

Asm

call read


This means that data has entered the program from outside

Whenever you see input, you should be sensitive Besh

Third example

Copy without length check

Example:

Asm

call strcpy


or

Asm

call strcat


or

Asm

call sprintf


These are classic alarms
because they don't check the length of the input

Fourth example

Small input buffer, large input
For example, see this in the decompiler

C

char buf[16];
strcpy(buf,input);


Or see in the assembly
Asm

lea rdi,[rbp-0x10]
call strcpy


The buffer is only 16 bytes
But there is no limit for input
So the probability of buffer overflow is high

Fifth example

No Canary
If you did not see these functions first

Asm

mov rax, qword ptr fs:[0x28]

mov [rbp-0x8], rax


There is probably no Stack Canary
The presence of these commands usually indicates that the compiler has enabled stack protection

Sixth example

The function does not perform any checks before ret
A vulnerable function usually ends like this

Asm

leave
ret


If no security checks are performed before ret and you have seen strcpy above, you should be more careful

Real example of analysis:

Suppose you saw this assembly

Asm

push rbp
mov rbp,rsp
sub rsp,0x20

mov rdx,rdi

lea rax,[rbp-0x10]

mov rdi,rax

call strcpy

leave
ret


Question

Is this suspicious?

Answer

Yes

Because

Asm

lea rax,[rbp-0x10]
shows that we have a 16-byte buffer

and

Asm

call strcpy


you are also pouring data into it without any limit

So the first thing we need to test is sending long input

Exercise:

Open a simple binary in Ghidra or IDA

Find the following three things

Where the buffer is created

Where the data is entered

Where the data is copied

If you can find these three things, you are actually thinking like a real Reverse Engineer


@reverseengine
سیستم عامل چجوری یک برنامه رو راه‌اندازی و اجرا میکنه؟

اولین کاری که سیستم عامل برای اجرای برنامه انجام میده آپلود کردن کد اون و هرگونه دیتای استاتیک مثل متغیرهای مقدار دهی اولیه در حافظه در فضای آدرس فراینده برنامه در ابتدا روی دیسک یا در برخی سیستم‌های مدرن ssd های مبتنی بر فلش با نوعی فرمت اجرایی قرار داره

How does an operating system launch and execute a program?

The first thing the operating system does to execute a program is to upload its code and any static data, such as initialized variables, into memory in the program's process address space, initially on disk or, in some modern systems, flash-based SSDs in some kind of executable format.

@reverseengine
توصیف گرها:
به برنامه ها اجازه میده که به راحتی ورودی رو از ترمینال بخونن و خروجی رو روی صفحه نمایش چاپ کنن

Descriptors:
allow programs to easily read input from the terminal and print output to the screen

@reverseengine
فرایند در سه حالت میتونه باشه:

در حال اجرا:
یعنی اینکه یک فرایند روی یک پردازنده در حال اجراست


آماده:
یعنی فرایند آماده اجراست ولی به دلایلی سیستم عامل تصمیم میگیره اونو در این لحظه اجرا نکنه

مسدود شده:
یک فرایند نوعی عملیات انجام داده که باعث میشه تا زمان وقوع رویداد دیگه‌ای آماده اجرا نباشه



A process can be in three states:

Running:
This means that a process is running on a processor

Ready:
This means that the process is ready to run but for some reason the operating system decides not to run it at this time

Blocked:
A process has performed some kind of operation that makes it unavailable for execution until another event occurs

@reverseengine
بلوک کنترل فرایند (PCB) چیست؟

گاهی اوقات افراد به ساختار منفردی که اطلاعات مربوط به یک فرایند رو ذخیره میکنه بلوک کنترل فرایند میگن

What is a process control block (PCB)?

Sometimes people call a single structure that stores information about a process a process control block

@reverseengine
فراخوان‌های سیستمی (System Calls) در لینوکس رابطی هستن که برنامه‌های کاربر (User Space) از طریق اونا از هسته (Kernel Space) درخواست انجام عملیات میکننن

به زبان ساده:

برنامه‌ها نمیتونن مستقیما به سخت‌افزار فایل‌ها یا حافظه سیستم دسترسی داشته باشن به همین خاطر از System Call استفاده میکنن و از کرنل میخام این کار رو براشون انجام بده

مثال:

وقتی داخل C مینویسید:

read(fd, buffer, 100);


در واقع برنامه از کرنل درخواست میکنه:

از فایل بخون
100 بایت داده برگردون

مهم‌ترین System Call های لینوکس

مدیریت فایل

open() read() write() close() lseek()


مثال:

int fd = open("test.txt", O_RDONLY); read(fd, buf, 100); close(fd);


مدیریت پردازش

fork() execve() wait() exit() kill()


مثال:

pid_t pid = fork();


یک پردازش جدید (Child Process) میسازه

مدیریت حافظه

mmap() munmap() brk() mprotect()


مثال:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
یک صفحه حافظه جدید اختصاص میده

ارتباط بین پردازش‌ها (IPC)

pipe() socket() connect() accept() send() recv()


مثال:

socket(AF_INET, SOCK_STREAM, 0);


یک سوکت TCP درست میکنه

اطلاعات سیستم

getpid() getuid() uname() time()


مثال:

printf("%d\n", getpid());

شناسه پردازش فعلی رو برمیگردونه

پشت صحنه چه اتفاقی میوفته؟

فرض کنید برنامه:

write(1, "Hello", 5);


رو اجرا میکنه

مراحل:
برنامه تابع write() رو صدا میزنه
کتابخانه libc شماره System Call مربوطه رو داخل رجیستر قرار میده
دستور syscall اجرا میشه

CPU
از User Mode به Kernel Mode میره


کرنل تابع sys_write رو اجرا میکنه
نتیجه برگردونده میشه

CPU
دوباره به User Mode برمیگرده

در معماری x86-64 معمولا رجیسترها به این شکل استفاده میشن:

RAX = syscall number RDI = arg1 RSI = arg2 RDX = arg3 R10 = arg4 R8 = arg5 R9 = arg6

بعد:
syscall

اجرا میشه

اسمبلی:

mov rax, 1 mov rdi, 1 mov rsi, message mov rdx, 5 syscall


در x86-64:

1 = syscall شماره write
rdi=1 یعنی stdout
rsi آدرس رشته
rdx=5 طول رشته
در نهایت:
Hello


روی صفحه چاپ میشه
برای مهندسی معکوس اکسپلویت‌نویسی و تحلیل بدافزار مهم‌ترین System Call هایی که باید خوب بشناسید:

open
read
write
mmap
mprotect
fork
execve
socket
connect
accept
clone
ptrace
kill

چون تقریبا در همه بدافزارها شل‌کدها و ابزارهای سطح پایین لینوکس با اینا سر و کار دارید

@reverseengine
👍1
System Calls in Linux are the interface through which user space programs request operations from the kernel space

In simple terms:

Programs cannot directly access the hardware files or system memory, so they use System Calls and ask the kernel to do this for them

Example:

When you write in C:

read(fd, buffer, 100);


In fact, the program asks the kernel:

Read from file

Return 100 bytes of data

Most important Linux System Calls

File management

open() read() write() close() lseek()



Example:

int fd = open("test.txt", O_RDONLY); read(fd, buf, 100); close(fd);


Process Management

fork() execve() wait() exit() kill()


Example:

pid_t pid = fork();


Creates a new process (Child Process)

Memory Management

mmap() munmap() brk() mprotect()


Example:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);


Allocates a new memory page

Interprocess Communication (IPC)

pipe() socket() connect() accept() send() recv()


Example:

socket(AF_INET, SOCK_STREAM, 0);


Creates a TCP socket

System Information

getpid() getuid() uname() time()


Example:

printf("%d\n", getpid());


Returns the current process ID

What happens behind the scenes?

Suppose the program:

write(1, "Hello", 5);


executes

Steps:
The program calls the write() function
The libc library places the corresponding System Call number into the register
The syscall instruction is executed

The CPU
goes from User Mode to Kernel Mode

The kernel executes the sys_write function
The result is returned

The CPU
returns to User Mode

In the x86-64 architecture, registers are usually used in this way:

RAX = syscall number RDI = arg1 RSI = arg2 RDX = arg3 R10 = arg4 R8 = arg5 R9 = arg6


Next:

syscall

is executed

Assembly:

mov rax, 1 mov rdi, 1 mov rsi, message mov rdx, 5 syscall


In x86-64:

1 = syscall number write
rdi=1 means stdout
rsi is the address of the string
rdx=5 is the length of the string


In  Finally:

Hello


Printed on the screen
For reverse engineering, exploit writing and malware analysis, the most important system calls you should know well are:

open
read
write
mmap
mprotect
fork
execve
socket
connect
accept
clone
ptrace
kill


Because in almost all malware, shellcodes and low-level Linux tools are involved

@reverseengine