ReverseEngineering
1.32K subscribers
50 photos
11 videos
106 files
888 links
Download Telegram
Modern iOS Security Features – A Deep Dive into SPTM, TXM, and Exclaves

https://arxiv.org/pdf/2510.09272

@reverseengine
این مدیوم منه اگه اونجا هم منو فالو کنید خوشحال میشم اونجا هم همین چیزای کانال رو میزارم و ی سری چیزای اضافه🖤

This is my Medium. I would be happy if you followed me there too. I will post the same things from the channel there and a few extra things🩶

https://medium.com/@addcss012
❤8
Dead Code و Junk Code
کدی که هست ولی قرار نیست کاری انجام بده

یکی از روش‌ های رایج Obfuscation اینه که داخل برنامه مقدار زیادی کد اضافه قرار بدن که یا اصلا اجرا نمیشه یا اجرا میشه ولی هیچ تاثیری روی نتیجه نهایی برنامه نداره

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

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

int result = a + b;

int x = 50;
x = x * 2;
x = x - 30;

return result;
اینجا محاسبات مربوط به x هیچ تاثیری روی result نداره پس از نظر منطق برنامه این بخش Dead Code محسوب میشه

حالا یک مثال در اسمبلی ببینیم:

mov eax, 10
add eax, 20

mov ecx, 500
xor ecx, ecx
add ecx, 100

ret



اگر مقدار ecx هیچ جا بعدا استفاده نشه بخش مربوط به ecx عملا تاثیری روی خروجی تابع نداره این همون چیزیه که ما باید یاد بگیریم تشخیص بدیم
اما Junk Code همیشه به این سادگی نیست ممکنه یک Obfuscator دستورهایی اضافه کنه که ظاهرشون مهم به نظر میرسه:

push rax
xor rcx, rcx
inc rcx
dec rcx
pop rax


در ظاهر چند عملیات انجام شده
ولی در اخر وضعیت مهم برنامه تقریبا همون چیزیه که قبل از این بلاک بوده
در تحلیل واقعی یکی از بهترین سوال‌ها اینه:

این بلاک چه چیزی رو تغییر داد که بعدا واقعا استفاده میشه؟

اگر جواب هیچ‌ چیز باشه احتمال داره با Junk Code طرف باشیم یک روش خوب برای تحلیل اینه که فقط مقدار هایی رو دنبال کنید که به خروجی یا مرحله های بعدی برنامه میرسن مثلا اگر یک مقدار داخل RAX ساخته بشه ولی قبل از استفاده دوباره overwrite بشه احتمالا محاسبه قبلی اهمیت نداشته ولی اینجا باید حواستون جمع باشه هر کدی که خروجی واضحی نداره Junk Code نیست ممکنه روی Flagها تاثیر بذاره حافظه رو تغییر بده یا اثر جانبی داشته باشه پس قبل از حذف ذهنی یک بلاک رو باید بررسی کنید:

مقدارهای خروجی کجا میرن؟
حافظه تغییر کرده؟
Flag مهمی تغییر کرده؟
تابع دیگه ای صدا زده شده؟
نتیجه این عملیات بعدا استفاده میشه؟

Deobfuscation
یعنی همین کم‌ کم چیزهایی که تاثیری روی منطق اصلی ندارن کنار میرن و ساختار واقعی برنامه مشخص میشه

تمرین:

این کد رو بررسی کنید:
C++
int calculate(int a, int b)
{
int x = a + b;

int temp = 500;
temp ^= 123;
temp += 20;
temp -= 20;

return x;
}



مشخص کنید کدوم قسمت روی خروجی تابع تاثیر داره و کدوم قسمت فقط باعث شلوغ شدن تحلیل میشه بعد همین مثال رو Compile کنید و داخل Ghidra باز کنید ببینید Compiler با بخش اضافی چه کاری میکنه ممکنه حتی قبل از اینکه تو فایل خروجی رو ببینید خودش کل بخش بی‌ استفاده رو حذف کرده باشه چون کامپایلر ها هم بعضی وقتا برخلاف انتظارمون کار مفید انجام میدن

@reverseengine
❤1
ReverseEngineering
Dead Code و Junk Code کدی که هست ولی قرار نیست کاری انجام بده یکی از روش‌ های رایج Obfuscation اینه که داخل برنامه مقدار زیادی کد اضافه قرار بدن که یا اصلا اجرا نمیشه یا اجرا میشه ولی هیچ تاثیری روی نتیجه نهایی برنامه نداره هدف اینه که وقتی ما فایل رو باز…
Dead Code and Junk Code

Code that exists but is not supposed to do anything

One of the common methods of Obfuscation is to put a lot of extra code into the program that either does not run at all or runs but has no effect on the final result of the program

The goal is that when we open the file, we see a lot of extra instructions and it becomes harder to find the real logic

For example, look at this simple code:

int result = a + b;

int x = 50;
x = x * 2;
x = x - 30;

return result;


Here, the calculations related to x have no effect on the result, so from the logic of the program this section is considered Dead Code

Now let's see an example in assembly:

mov eax, 10
add eax, 20

mov ecx, 500
xor ecx, ecx
add ecx, 100

ret


If the value of ecx is not used anywhere later, the part related to ecx has practically no effect on the output of the function. This is what we need to learn to recognize.

But Junk Code is not always this simple. An Obfuscator may add instructions that appear to be important:

push rax
xor rcx, rcx
inc rcx
dec rcx
pop rax


In appearance, several operations have been performed

But at the end, the important state of the program is almost the same as before this block.

In real analysis, one of the best questions is:

What did this block change that will actually be used later?

If the answer is nothing, we are probably dealing with Junk Code. A good way to analyze is to only follow the values ​​that reach the output or subsequent stages of the program.

For example, if a value is created in RAX but is overwritten before being used again, the previous calculation probably does not matter. But you have to be careful here. Any code that does not have a clear output is not Junk Code. It may affect flags, change memory, or have side effects. So before mentally deleting a block, you should check:

Where do the output values ​​go?

Has memory changed?

Has an important flag changed?

Has another function been called?

Will the result of this operation be used later?

Deobfuscation
That is, gradually things that do not affect the main logic are removed and the real structure of the program is revealed.

Exercise:

Examine this code:

C++
int calculate(int a, int b)
{
int x = a + b;

int temp = 500;

temp ^= 123;

temp += 20;
temp -= 20;

return x;
}


Determine which part affects the output of the function and which part just makes the analysis busy. Then compile this example and open it in Ghidra and see what the compiler does with the extra part. It may have removed the entire useless part even before you see it in the output file, because compilers sometimes do useful things against our expectations.

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


libFuzzer و Coverage Guided


Fuzzing
تا اینجا فهمیدیم Fuzzing یعنی دادن تعداد زیادی ورودی مختلف به برنامه و منتظر موندن تا یک جایی خرابکاری کنه😁
ولی Fuzzer های جدید فقط ورودی رندوم تولید نمیکنن بعضی از اونها بررسی میکنن هر ورودی برنامه رو از چه مسیر هایی عبور داده و همین باعث میشه کم کم ورودی‌ های جالب‌ تر تولید کنه

Coverage Guided یعنی چی

فرض کن یک برنامه این شکلیه

Input
↓
Check 1
↓
Check 2
↓
Hidden Function
اگر ورودی اول فقط به Check 1 برسه

سعی میکنه ورودی مسیر رو تغییر بده تا Fuzzer جدیدی باز بشه
مثلا به Check 2 برسه
بعد دوباره از همون ورودی استفاده میکنه و تغییرات بیشتری میده

هدف اینه که قسمت‌ های بیشتری از برنامه اجرا بشن چون خب ظاهرا ما تصمیم گرفتیم برای پیدا کردن باگ باید به همه جای برنامه سرک بکشیم 😅

libFuzzer
چیکار میکنه
libFuzzer
یک موتور Fuzzing برای برنامه‌های C و ++C است که با LLVM و Clang کار میکنه ما یک تابع مشخص به اون میدیم
بعد خودش بار ها و بار ها اون تابع رو با ورودی‌ های مختلف اجرا میکنه
هر ورودی که باعث رسیدن به مسیر جدیدی بشه ارزشمند تر میشه

تابع اصلی Fuzzing

معمولا چیزی شبیه این داریم:
C
#include <stdint.h>
#include <stddef.h>

int LLVMFuzzerTestOneInput(
const uint8_t *data,
size_t size
)
{
return 0;
}



توضیح کد زیر
این تابع هدف Fuzzer هست
هر بار libFuzzer یک ورودی جدید تولید میکنه محتوای ورودی داخل data قرار میگیره و اندازه اون داخل size قرار میگیره

یک مثال ساده:
C
#include <stdint.h>
#include <stddef.h>
#include <string.h>

int LLVMFuzzerTestOneInput(
const uint8_t *data,
size_t size
)
{
if (size >= 5)
{
if (memcmp(data, "HELLO", 5) == 0)
{
volatile int x = 1;
(void)x;
}
}

return 0;
}




اینجا چه اتفاقی میوفته
Fuzzer
ورودی‌ های مختلف رو امتحان میکنه

مثلا

AAAAA


بعد

HELAA


بعد شاید

HELLO


وقتی ورودی به HELLO برسه
یک مسیر جدید از برنامه اجرا میشه
Coverage Guided Fuzzing
این مسیر جدید رو تشخیص میده
و اون ورودی رو نگه میداره تا از اون برای پیدا کردن مسیرهای بعدی استفاده کنه

کامپایل با Clang
shell
clang -g -fsanitize=fuzzer,address file23_fuzz.c -o file23_fuzz



اینجا دو چیز با هم فعال شده

libFuzzer
+
AddressSanitizer


libFuzzer
ورودی تولید میکنه
ASan
مراقب خطا های حافظه هست
این ترکیب برای پیدا کردن Memory Bug خیلی قدرتمنده

اجرای Fuzzer
shell
./file23_fuzz


بعد برنامه شروع میکنه به تولید و تغییر ورودی‌ ها
اگر ورودی باعث کرش بشه معمولا همون ورودی ذخیره میشه

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

چرا برای ما مهمه؟

فرض کنید یک برنامه پیچیده دارید
ولی دقیقا نمیدونید چه ورودی باعث رسیدن به یک تابع حساس میشه

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

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

یعنی:

Fuzzing
↓
New Code Path
↓
Crash یا Behavior
↓
Ghidra / IDA
↓
Assembly Analysis


Coverage Guided Fuzzing
فقط دنبال کرش نیست
دنبال مسیر های جدید هم هست
هر مسیر جدید یعنی بخش جدیدی از برنامه که ارزش بررسی داره و وقتی libFuzzer رو با ASan ترکیب میکنیم هم میتونیم ورودی‌ های هوشمندانه‌ تر تولید کنیم هم Memory Bug ها رو سریع‌ تر تشخیص بدیم

تمرین:

تابع بالا رو کمی تغییر بدید و یک شرط جدید برای یک ورودی خاص اضافه کنید بعد فکر کنید Fuzzer چطور باید قدم به قدم ورودی رو تغییر بده تا به اون مسیر جدید برسه

@reverseengine
❤1
ReverseEngineering
بخش بیست و هفتم بافر اورفلو libFuzzer و Coverage Guided Fuzzing تا اینجا فهمیدیم Fuzzing یعنی دادن تعداد زیادی ورودی مختلف به برنامه و منتظر موندن تا یک جایی خرابکاری کنه😁 ولی Fuzzer های جدید فقط ورودی رندوم تولید نمیکنن بعضی از اونها بررسی میکنن هر ورودی…
Part 27 Buffer Overflow


libFuzzer and Coverage Guided

Fuzzing

So far, we have understood that Fuzzing means giving a lot of different inputs to the program and waiting for it to mess up somewhere😁
But new Fuzzers don't just generate random inputs. Some of them check what paths each input has taken in the program, which makes it gradually generate more interesting inputs

What does Coverage Guided mean

Suppose a program looks like this

Input
↓
Check 1
↓
Check 2
↓
Hidden Function


If the first input only reaches Check 1

It tries to change the input path so that a new Fuzzer opens

For example,

it reaches Check 2

Then it uses the same input again and makes more changes

The goal is to run more parts of the program because apparently we decided to go everywhere in the program to find the bug 😅

libFuzzer
What does libFuzzer do

A Fuzzing Engine for C Programs And it's C++ that works with LLVM and Clang. We give it a specific function.

Then it runs that function over and over again with different inputs.
Each input that leads to a new path becomes more valuable.

The main Fuzzing function

Usually we have something like this:

C
#include <stdint.h>
#include <stddef.h>

int LLVMFuzzerTestOneInput(
const uint8_t *data,
size_t size
)
{
return 0;
}


Explanation of the code below
This function is the target of the Fuzzer
Every time libFuzzer generates a new input, the content of the input is placed in data and its size is placed in size

A simple example:

C
#include <stdint.h>
#include <stddef.h>
#include <string.h>

int LLVMFuzzerTestOneInput(
const uint8_t *data,
size_t size
)
{
if (size >= 5)
{
if (memcmp(data, "HELLO", 5) == 0)
{
volatile int x = 1;
(void)x;
}
}

return 0;
}


What happens here
The Fuzzer
trys different inputs

For example

AAAA


then

HELAA


then maybe

HELLO


When the input reaches HELLO
a new path is executed from the program

Coverage Guided Fuzzing
detects this new path

and stores that input to use for finding subsequent paths

Compile with Clang:

shell
clang -g -fsanitize=fuzzer,address file23_fuzz.c -o file23_fuzz


Here two things are enabled together

libFuzzer
+
AddressSanitizer


libFuzzer
generates input

ASan
watches for memory errors

This combination is very powerful for finding memory bugs

Run Fuzzer

shell
./file23_fuzz


Then the program starts generating and modifying inputs

If the input causes a crash, usually the same input is saved

so that we can check it again later Let's do

Why is it important to us?

Suppose you have a complex program

But you don't know exactly what input will cause a critical function to be reached

Fuzzer
can find new paths by trying different inputs

Then you can examine those paths in Ghidra or IDA

That is:

Fuzzing
↓
New Code Path
↓
Crash or Behavior
↓
Ghidra / IDA
↓
Assembly Analysis


Coverage Guided Fuzzing
It doesn't just look for crashes
It also looks for new paths
Each new path is a new part of the program that is worth examining and when we combine libFuzzer with ASan we can both generate smarter inputs and detect memory bugs faster

Exercise:

Change the above function a little and add a new condition for a specific input then think about how the Fuzzer should change the input step by step to reach that new path

@reverseengine
❤1