es
Feedback
ReverseEngineering

ReverseEngineering

Ir al canal en Telegram
1 265
Suscriptores
Sin datos24 horas
-37 días
+730 días
Archivo de publicaciones
وقتی jmp به جای call میبینیم تقریبا مطمئنیم که tail recursion optimizitio انجام شده و استک فریم تکراری ساخته نمیشه When we see jmp instead of call, we are almost certain that tail recursion optimization has been performed and duplicate stack frames are not created.

Tail Recursion وقتی فراخوانی بازگشتی اخرین عملیاتیه که تابع انجام میده مثال
int fact_tail(int n, int acc){ if (n >= 1) return acc; return fact_tail(n-1, n*acc); }
مزیت Tail Recursion کامپایلر میتونه stack frame رو دوباره استفاده کنه و از overflow جلوگیری کنه در اسمبلی دیگه push/pop مکرر برای هر call لازم نیست (بهینه‌سازی میشه) اسمبلی نمونه برای Tail Recursion
fact_tail: cmp edi, 1 jle .Lbase imul esi, edi ; acc = n * acc sub edi, 1 jmp fact_tail ; tail call (jmp به جای call) .Lbase: mov eax, esi ret
تفاوت کلیدی: jmp fact_tail به جای call fact_tail → stack frame تکرار نمیشه Tail Recursion When the recursive call is the last operation performed by the function Example
int fact_tail(int n, int acc){ if (n >= 1) return acc; return fact_tail(n-1, n*acc); }
Advantage of Tail Recursion The compiler can reuse the stack frame and prevent overflow In assembly, repeated push/pop for each call is no longer necessary (optimized) Sample assembly for Tail Recursion
fact_tail: cmp edi, 1 jle .Lbase imul esi, edi ; acc = n * acc sub edi, 1 jmp fact_tail ; tail call (jmp instead of call) .Lbase: mov eax, esi ret
Key difference: jmp fact_tail instead of call fact_tail → stack frame is not repeated

Reverse Engineering flutter apps about dart VM and tools

r2ai-hackbcn2025.pdf1.69 MB

Ghidra CheatSheet
Ghidra CheatSheet

Reverse Engineering For Hackers

Data Structures در اسمبلی اینجاست که مهندسی معکوس تازه رنگ و بوی واقعی میگیره چون اکثر برنامه‌ها فقط جمع و تفریق عدد نیستن با ساختار داده‌ها کار میکنن 📌 چرا مهمه؟ وقتی دارید به یه باینری نگاه میکنید به ندرت می‌بینید فقط با متغیر ساده سروکار داشته باشه معمولا یه Struct یا Array پشت قضیه هست باید بلد باشید از روی دسترسی‌های حافظه حدس بزنید ساختار داده چی بوده 1 Array توی اسمبلی فقط یه بلوک پشت سر هم از حافظه‌ست هر عنصر طبق اندازه نوع داده آدرس‌دهی میشه 📖 مثال:
int arr[5] = {1,2,3,4,5};
اسمبلی معادل تقریبی:
mov eax, [ebp-10h] ; arr[0] mov eax, [ebp-0Ch] ; arr[1] mov eax, [ebp-08h] ; arr[2]
یا اگر با Index:
mov eax, [ebx+ecx*4] ; arr[ecx]
2 Struct Struct در اسمبلی فقط یه سری داده پشت سر همه تفاوتش با Array اینه که هر فیلد اندازه و نوع متفاوت داره 📖 مثال:
struct user { int age; char name[20]; };
اسمبلی معادل:
mov eax, [ebx] ; age movzx ecx, byte ptr [ebx+4] ; name[0] movzx edx, byte ptr [ebx+5] ; name[1]
👉 اینجا ebx همون آدرس پایه Struct هست بعد با Offset میریم سراغ فیلدها 3 Nested Structures یه Struct داخل Struct دیگه → همون ایده ولی Offset بزرگ‌تر 4 Pointers به Struct یا Array وقتی دیدید یه متغیر بارها مثل [eax+4] یا [eax+8] خونده میشه خیلی وقتا یعنی اون متغیر در واقع Pointer به یه Struct یا Array هست 🌟 نکته کاربردی در RE تو IDA و ابزارهای دیگه می‌تونید خودتون Struct تعریف کنی و روی حافظه Map کنی اینطوری بجای [ebx+8] می‌بینید user.age. هم فهمش راحت‌تر میشه هم بعدا سریعتر تحلیل میکنید 🔹 تمرین پیشنهادی: یه Struct ساده توی C تعریف کنید مثلا id و salary برای کارمند یه Array از اون Struct بسازید توی باینری ببینید چطور بهشون دسترسی پیدا میکنه 🧩 Data Structures in Assembly This is where reverse engineering really gets interesting—because most real programs aren’t just adding and subtracting numbers They’re working with data structures 📌 Why does it matter? When you’re looking at a binary you rarely see only simple variables Most of the time there’s an array or a struct hidden behind the memory accesses You need to learn how to guess the original structure just by watching how memory is accessed 1️⃣ Arrays In assembly, an array is just a continuous block of memory. Each element is accessed by offset = base + index * element_size 📖 Example in C: int arr[5] = {1,2,3,4,5}; Assembly (rough idea):
mov eax, [ebp-10h] ; arr[0] mov eax, [ebp-0Ch] ; arr[1] mov eax, [ebp-08h] ; arr[2]
Or with an index register:
mov eax, [ebx+ecx*4] ; arr[ecx]
2️⃣ Structs A struct in assembly is just a block of memory with different fields at fixed offsets The difference from arrays: fields can have different sizes/types 📖 Example in C:
struct user { int age; char name[20]; };
Assembly (approximate):
mov eax, [ebx] ; user.age movzx ecx, byte ptr [ebx+4] ; user.name[0] movzx edx, byte ptr [ebx+5] ; user.name[1]
👉 Here ebx is the base address of the struct, and each field is accessed by offset 3️⃣ Nested Structures You can have a struct inside another struct Same idea—but the offsets get larger as fields accumulate 4️⃣ Pointers to Arrays/Structs If you see the same base register accessed multiple times with different small offsets: mov eax, [eax+4] mov ecx, [eax+8] …it’s a strong hint that the variable is actually a pointer to a struct or array 🌟 Practical RE Tip In IDA (or Ghidra), you can define your own struct types and map them onto memory So instead of: [ebx+8] you’ll see something like: user.age This makes analysis faster and much more readable 🔹 Suggested Exercise 1Write a C struct, e.g.:
struct employee { int id; int salary; };
2 Create an array of employees 3 Compile it, then in IDA/x64dbg watch how the compiler generates memory accesses

🎭 Code Virtualization (VM-Based Protection) اینجا دیگه سطح دفاعی میره روی مغز سیستم! 😅 پکرهایی مثل VMProtect و Themida از این تکنیک استفاده میکنن ایده‌ش اینه که: 🔹 به‌جای اینکه برنامه‌ی اصلی به زبان ماشین CPU اجرا بشه 🔹 کد به دستورالعمل‌های یک CPU مجازی Custom VM تبدیل میشه یعنی چی؟ یعنی برنامه یه Interpreter تو خودش داره که دستورالعمل‌های عجیب و غریب خودش رو اجرا میکنه هر دستورالعمل واقعی CPU مثل MOV, ADD, CALL تبدیل میشه به یه سری دستور خیالی مثل: VM_INST_01 VM_INST_A3 VM_INST_FF و فقط همون ماشین مجازی می‌فهمه که اینا یعنی چی 1️⃣ ساختار کار اول Bytecode مخصوص VM ساخته میشه بعد کد اصلی پاک یا رمزنگاری میشه VM Interpreter کد رو یکی یکی میخونه و معادلش رو روی CPU واقعی اجرا میکنه 2️⃣ چرا سخت میشه تحلیل کرد؟ چون شما به جای x86 واقعی با یک زبان عجیب و غریب طرفی هر برنامه حتی هر بخش از برنامه میتونه VM خودش رو داشته باشه دیگه دیباگرهای معمولی x64dbg، OllyDbg، IDA ساده بی‌فایده میشن 3️⃣ ترکیب با Anti-Debug خیلی وقتا VMProtect فقط VM نمیاره بلکه Anti-Debug رو هم باهاش قاطی میکنه 📌 یعنی همزمان: کد غیرقابل فهم میشه Obfuscation شدید و دیباگرها هم نمیتونن راحت attach شن 4️⃣ روش‌های Devirtualization اینجا هم هنر مهندسی معکوس میاد وسط 😎 برای شکستن VM-Based Protection باید: اول VM Handlerها رو پیدا کرد تابع‌هایی که هر دستور رو اجرا میکنن بعد معادل دستورهای VM رو Map کرد به دستورهای واقعی CPU در نهایت یک Decompiler اختصاصی نوشت تا دوباره کد اصلی برگرده این دقیقا همون چیزیه که توی تحلیلگرهای بزرگ مثل IDA با پلاگین‌های مخصوص یا ابزارهای شخصی‌سازی شده استفاده میشه 🎭 Code Virtualization (VM-Based Protection) This is where defensive techniques go straight for the brain of the system! 😅 Packers like VMProtect and Themida use this approach The idea is simple but brutal: 🔹 Instead of running the original program directly on the CPU 🔹 The code is transformed into instructions of a custom virtual CPU (VM) What does that mean? The program has an interpreter inside itself that executes strange custom instructions So instead of normal x86 opcodes like MOV, ADD, CALL, you end up with something like: VM_INST_01 VM_INST_A3 VM_INST_FF …and only the built-in VM knows what those mean 1️⃣ How it works (basic structure): 1 The original code is translated into custom VM bytecode 2 The original instructions are either removed or encrypted 3 The VM interpreter reads the bytecode one by one and executes the equivalent operation on the real CPU 2️⃣ Why is it so hard to analyze? Because you’re no longer looking at real x86 instructions—you’re dealing with an entirely made-up language Different sections of the program may even use different VMs Normal debuggers like x64dbg, OllyDbg, or vanilla IDA become useless 3️⃣ Often combined with Anti-Debugging VMProtect doesn’t just virtualize code—it usually mixes in anti-debugging tricks as well 📌 So at the same time: The code becomes unreadable heavy obfuscation Debuggers can’t easily attach or step through 4️⃣ Devirtualization the reverse-engineer’s art 😎 To break VM-based protection, the reverse engineer has to: 1 Identify the VM handlers functions that execute each custom instruction 2 Map those VM instructions back to real CPU instructions 3 Build or script a custom decompiler to reconstruct the original logic This is exactly what advanced reverse engineers do with IDA plugins or their own custom tools

📌 Calling Convention یعنی چی؟ خیلی ساده: قانونی که تعیین میکنه آرگومان‌های تابع چطوری بهش داده بشن و وقتی تابع تموم شد کی مسئول پاک کردن Stack باشه 1cdecl C Declaration رایج‌ترین حالت توی زبان C مخصوصا روی ویندوز و لینوکس آرگومان‌ها از راست به چپ روی Stack Push میشن کالِر Caller یعنی همون کسی که تابع رو صدا زده مسئول پاک کردن Stack هست 📖 مثال اسمبلی:
push 3 ; arg2 push 5 ; arg1 call add add esp, 8 ; Caller پاک می‌کنه
2 stdcall بیشتر توی Windows API دیده می‌شه آرگومان‌ها همون راست به چپ روی Stack این بار کالی Callee یعنی خود تابع بعد از برگشت Stack رو تمیز میکنه 📖 مثال اسمبلی:
push 3 push 5 call add
; تابع add خودش Stack رو درست میکنه 3 fastcall برای سرعت بعضی آرگومان‌ها توی رجیسترها گذاشته میشن مثلا توی ویندوز ECX و EDX بقیه آرگومان‌ها اگه زیاد بودن میرن توی Stack 📖 مثال اسمبلی:
mov ecx, 5 ; arg1 mov edx, 3 ; arg2 call add
4 thiscall مخصوص C++ برای توابع کلاس اشاره‌گر this معمولا توی ECX پاس داده میشه 🌟 چیزی که توی دیباگر میبینید: اگه وارد یه تابع بشید: توی cdecl معمولا بعد از ret یه دستور add esp X میبینید یعنی Caller مسئول بوده توی stdcall خود تابع با ret X برمی‌گرده یعنی خودش Stack رو پاک کرده 🔹 تمرین عملی برای شما: یه کد ساده‌ی C بنویسید (مثلا تابع جمع و ضرب با دو پارامتر) همون کد رو: 1 cdecl کامپایل کنید 2 stdcall 3 fastcall بعد بریزید توی IDA یا x64dbg و تفاوت رو ببینید مخصوصاً دنبال add esp, ... یا ret ... باشید 📌 What is a Calling Convention? In simple terms: it’s the rule that defines how function arguments are passed and who is responsible for cleaning up the stack after the function finishes 1 cdecl C Declaration The most common calling convention in C especially on Windows and Linux Arguments are pushed right to left onto the stack The caller the one calling the function is responsible for cleaning the stack 📖 Assembly Example:
push 3 ; arg2 push 5 ; arg1 call add add esp, 8 ; Caller cleans the stack
2 stdcall Mostly used in Windows API functions Arguments are also pushed right to left The callee the function itself cleans the stack before returning 📖 Assembly Example:
push 3 push 5 call add ; The add function itself restores the stack
3 fastcall For speed some arguments are passed in registers instead of the stack On Windows: ECX and EDX are used for the first two arguments Any additional arguments are passed on the stack 📖 Assembly Example:
mov ecx, 5 ; arg1 mov edx, 3 ; arg2 call add
4 thiscall Specific to C++ class methods The this pointer is usually passed in the ECX register 🌟 What you’ll see in a debugger: In cdecl after ret, you usually see add esp, X → meaning the caller cleaned the stack In stdcall the function returns with ret X → meaning the callee cleaned the stack 🔹 Practical Exercise for you: 1 Write a simple C program e.g., add and multiply functions with two parameters 2 Compile it three times using: cdecl stdcall fastcall 3 Open the binaries in IDA or x64dbg and look for the differences Watch for add esp ... vs ret ....

قبل از هر چیز وقتی یک باینری به دستت میرسه اولین کاری که باید بکنی درک ساختار فایل و بخش‌های مهمش هست هر باینری شامل بخش‌های مختلفیه مثل Header، Sections، Import Table و Export Table Header اطلاعات پایه مثل معماری اندازه و نقاط شروع برنامه رو بهتون میده Sections مثل .text، .data و .rdata بخش‌های کد و داده‌ها رو نگه میدارن Import Table لیست توابعی که برنامه از کتابخونه‌های خارجی صدا زده رو نشون میده فهمیدن این بخش‌ها اولین قدم برای تحلیل جدی هست تمرین: یه باینری ساده Windows یا Linux بگیر با ابزار PE-bear یا CFF Explorer (برای Windows) یا readelf برای Linux Header و Sections رو نگاه کن Import Table رو بررسی کن و ببین چه توابعی از کتابخونه‌ها صدا زده شدن Before anything else when you first get a binary the very first thing you should do is understand its structure and key sections Every binary consists of different parts such as the Header, Sections, Import Table, and Export Table The Header provides basic information like the architecture, size, and entry points of the program Sections such as .text, .data, and .rdata hold the code and data. The Import Table lists the functions that the program calls from external libraries Understanding these sections is the first step for serious analysis Exercise: 1 Take a simple Windows or Linux binary 2 Use tools like PE-bear or CFF Explorer for Windows or readelf (for Linux) to examine the Header and Sections 3 Inspect the Import Table and see which functions from libraries the program calls

1 Binary Structure Basics ساختار فایل‌های باینری و بخش های مهم اون تمرین: باز کردن یک باینری با PE-bear یا CFF Explorer بررسی Headers ، Sections و Import/Export Table 2 Intro to Disassembly دیدن دستورهای اسمبلی برنامه تمرین: باز کردن یک باینری ساده در IDA یا Ghidra شناسایی رجیسترها و دستورهای اصلی مثل mov, call, jmp 3 Static String & Function Analysis پیدا کردن String ها و توابع مهم بدون اجرا تمرین: پیدا کردن String های پسورد یا پیام‌های برنامه و شناسایی توابع کلیدی که با اونا مرتبط هستن 4 Dynamic Analysis Introduction اجرای برنامه و دنبال کردن جریان کد تمرین: اجرای یک باینری ساده در x64dbg گذاشتن Breakpoint و دنبال کردن Stack و Registers 5 Basic Patch & Modify تغییر رفتار برنامه با Patch ساده تمرین: تغییر یک شرط if یا تغییر یک MessageBox در باینری بدون Source Code 6 Understanding Simple Anti-Debugging آشنایی با تکنیک‌های ساده Anti-Debugging تمرین: بررسی IsDebuggerPresent یا Sleep/Timing Check و بایپس با Patch یا NOP کردن 7 First CrackMe Challenge تمرین واقعی با یک برنامه کوچک تمرین: گرفتن یک CrackMe ساده با پسورد هاردکد پیدا کردن تابع پسورد و تغییر باینری برای عبور از چک 1️⃣ Binary Structure Basics Understanding binary file structures and their key sections Exercise: Open a binary with PE-bear or CFF Explorer and examine the Headers Sections and Import/Export Tables 2️⃣ Intro to Disassembly Viewing the program’s assembly instructions Exercise: Open a simple binary in IDA or Ghidra and identify registers and main instructions such as mov, call, and jmp 3️⃣ Static String & Function Analysis Finding important strings and functions without executing the binary Exercise: Locate password strings or program messages and identify key functions related to them 4️⃣ Dynamic Analysis Introduction Running the program and following the code flow Exercise: Execute a simple binary in x64dbg, set breakpoints and trace the stack and registers 5️⃣ Basic Patch & Modify Changing program behavior with simple patches Exercise: Modify an if condition or change a MessageBox in the binary without the source code 6️⃣ Understanding Simple Anti-Debugging Getting familiar with basic anti-debugging techniques Exercise: Check for IsDebuggerPresent or Sleep/Timing Checks and bypass them with patches or NOP instructions 7️⃣ First CrackMe Challenge Hands-on practice with a small program Exercise: Take a simple CrackMe with a hardcoded password find the password-checking function and modify the binary to bypass the check

1 Static Analysis Workflow چطور بدون اجرا باینری را تحلیل کنیم تمرین: گرفتن یک باینری ساده بررسی Import Table String ها و ساختار کد با IDA/Ghidra 2 Dynamic Analysis Basics دیباگ کردن و دنبال کردن جریان برنامه تمرین: اجرای یک باینری در x64dbg گذاشتن Breakpoint دنبال کردن Call ها و Stack 3 Anti-Debugging Techniques شناسایی و بایپس تکنیک‌های Anti-Debugging تمرین : بررسی IsDebuggerPresent و Timing Checks بایپس اونا با Patch یا Script 4 Control Flow Obfuscation تحلیل برنامه‌هایی که جریان کد رو مخفی کردن تمرین: گرفتن یک CrackMe با Control Flow Flattening پیدا کردن مسیر واقعی با IDA/Ghidra 5 Basic Packing & Unpacking آنالیز و خارج کردن باینری‌های ساده Packed تمرین: گرفتن باینری UPX شده Unpack کردن و آماده کردن برای دیباگ 6 Intermediate Deobfuscation بازگردانی کد Obfuscated با ابزار و اسکریپت تمرین: استفاده از Python یا Radare2 برای حذف Opaque Predicates و بازسازی Control Flow 7 Function & Data Analysis شناسایی توابع کلیدی و داده‌ها در باینری تمرین: پیدا کردن توابع پسورد چک License Check و تحلیل آرایه‌ها و String های کلیدی 1️⃣ Static Analysis Workflow How to analyze a binary without executing it Exercise: Take a simple binary and examine its Import Table strings and code structure using IDA or Ghidra 2️⃣ Dynamic Analysis Basics Debugging and following the program’s flow Exercise: Run a binary in x64dbg set breakpoints and trace calls and the stack 3️⃣ Anti-Debugging Techniques Identifying and bypassing anti-debugging mechanisms Exercise: Check for IsDebuggerPresent and timing checks and bypass them using patches or scripts 4️⃣ Control Flow Obfuscation Analyzing programs that hide their execution flow Exercise: Take a CrackMe with control flow flattening and recover the real execution path using IDA or Ghidra 5️⃣ Basic Packing & Unpacking Analyzing and extracting simple packed binaries Exercise: Take a UPX-packed binary unpack it and prepare it for debugging 6️⃣ Intermediate Deobfuscation Restoring obfuscated code using tools and scripts Exercise: Use Python or Radare2 to remove opaque predicates and reconstruct the control flow 7️⃣ Function & Data Analysis Identifying key functions and data in a binary Exercise: Locate password-checking functions license checks and analyze key arrays and strings