mov rax, [rcx+0x10]
mov eax, [rax+0x4]
اینجا مقدار +0x10 هم به عنوان Pointer استفاده شده و بعد از Object مقصد Offset +0x4 خونده شده
پس احتمالاً +0x10 یک Pointer به یک ساختار یا Object دیگه است
در نتیجه فعلا میتونیم یک مدل اولیه داشته باشیم:
Object
|
+0x00 unknown
+0x04 integer / flag
+0x08 pointer-like
+0x10 pointer-like
ولی این هنوز Struct نهایی نیست
این فقط یک Hypothesis هست
باید با Instructionهای بیشتر Cross-Referenceها و توابع دیگه بررسیش کنیم
حالا بریم سراغ
Ghidra
وقتی Offsetهای مختلف رو پیدا کردیم میتونیم توی Ghidra یک Struct بسازیم و Field ها رو بهش اضافه کنیم
مثلا اول کار ممکنه فقط این اطلاعات رو داشته باشیم:
User
0x00 unknown
0x04 field_4
0x08 field_8
0x10 field_10
بعد از بررسی بیشتر متوجه بشیم:
User
0x00 unknown
0x04 id
0x08 name
0x10 address
یعنی چیزی که اول فقط این بود:
field_8
کم کم تبدیل میشه به:
name
و این دقیقا یکی از بخشهای جذاب Reverse Engineering هست
چون هدف فقط این نیست که بفهمیم:
mov rax, [rcx+0x8]
چه کاری انجام میده
هدف اینه که از بین همین Instruction ها دوباره یک مدل منطقی از برنامه بسازیم
یعنی از:
[rcx+0x8]
برسیم به چیزی مثل:
user->name
برای بازسازی یک Struct ناشناخته این مسیر رو توی ذهنتون داشته باشید:
Base Pointer رو پیدا کنید
Offset های دسترسی رو جمع کنید
Read و Write رو تشخیص بدید
اندازه Memory Access رو بررسی کنید
نحوه استفاده از مقدار رو بررسی کنید
Offset
های تکراری رو در توابع مختلف پیدا کنید
Pointer
ها رو از Integer ها تفکیک کنید
Nested Structure ها رو بررسی کنید
Padding و Alignment رو در نظر بگیرید
10. Arrayها و Strideها رو بررسی کن
11. یک Hypothesis بساز
12. با Cross-Reference و تحلیل بیشتر تأیید یا اصلاحش کن
در Source Code ممکنه خیلی راحت داشته باشیم:
user->name
ولی در Binary ممکنه فقط این رو ببینیم:
mov rax, [rcx+0x8]
کار Reverse Engineer اینه که از همین اطلاعات کمکم بفهمه:
RCX
↓
User Object
↓
+0x8
↓
name
یعنی از چندتا Offset و Instruction پراکنده دوباره ساختار منطقی برنامه رو سرهم کنیم
@reverseengine
Post #1845
29