تقييم الموضوع :
  • 9 أصوات - بمعدل 3.56
  • 1
  • 2
  • 3
  • 4
  • 5
كتابة محاكي x86 بسيط مع IDAPython اا Writing a simple x86 emulator with IDAPython
#1
كتابة محاكي x86 بسيط مع IDAPython اا Writing a simple x86 emulator with IDAPython

في كثير من الأحيان، عندما أجد سكربتات IDAPython، لاحظت أنهم يستخدمون الـ API الخاصة بـ IDAPython بطريقة غير فعالة/غير صحيحة لتفكيك-disassemble أو فك ترميز-decode التعليمات [على سبيل المثال باستخدام ()idc.GetMnem أو ()idc.GetDisasm ]. لذلك في هذه التدوينة، سأوضح كيفية استخدام دوال فك ترميز التعليمات التي توفرها اداة IDA من خلال IDAPython لكتابة محاكي x86 بسيط للغاية. الهدف من ذلك هو توضيح الاستخدام الصحيح للـ API التي تختص بفك ترميز التعليمات (او instruction decoding) من خلال IDAPython. بحلول نهاية هذه التدوينة، يجب أن تكون قادرًا على حل مشكلات مماثلة باستخدام IDAPython.
  • جدول المحتويات
  • نظرة عامة
  • عمل Disassembly للبرنامج
  • كتابة المحاكي
  • مقدمة سريعة لفك ترميز التعليمات - instruction decoding
  • تحديد نطاق دوال البرنامج
  • محاكاة التعليمات
  • نظرة عامة
دعنا نبدأ مع عينة البرنامج التالي الذي يحتوي على جدول يضم 12 دالة يتم استدعاءها في loop ويتم عرض النتيجة. هدفنا هو كتابة محاكي يمكنه حساب قيمة التحدي بشكل ستاتيكي دون استخدام محاكي طرف ثالث او محاكي خارجي.
#include <stdio.h>
#include <cstdint>
#include <time.h>
#include <stdlib.h>

typedef uint64_t (*challenge_proto_t)(uint32_t, uint32_t);

//-------------------------------------------------------------------------
uint64_t challenge_1(uint32_t c1, uint32_t c2) // 39 operation(s)
{
uint64_t result;
__asm
{
pushad
mov eax, [c1]
mov edx, [c2]
not eax
dec edx
xor edx, eax
xor edx, eax
inc eax
not eax
sub edx, 0x27c12466
inc eax
dec edx
not edx
inc eax
add eax, 0x273804ca
xor edx, 0xaa5a1584
sub eax, edx
not edx
xor eax, 0xf94f7d8c
dec edx
dec eax
sub eax, edx
not edx
dec edx
sub edx, 0xd7b41b83
xor eax, 0xa551a9c7
add eax, eax
dec eax
inc eax
not eax
add edx, 0xa551b974
inc edx
dec edx
not edx
xor eax, 0x200d519
not edx
not eax
sub edx, 0xeb15b7ef
xor eax, 0xb2558b8c
xor eax, 0xda288d90
not eax
not edx
mov dword ptr[result], eax
mov dword ptr[result + 4], edx

popad
}
return result;
}

// .
// .
// challenge_2 .. challenge_12
// .
// .

challenge_proto_t challenge_funcs = {
challenge_1,
challenge_2,
challenge_3,
challenge_4,
challenge_5,
challenge_6,
challenge_7,
challenge_8,
challenge_9,
challenge_10,
challenge_11,
challenge_12
};

//-------------------------------------------------------------------------
int main(int argc, char *argv)
{
if (argc < 4)
{
printf("challenge func[0..%d] challenge1-32 challenge2-32 -> result-64\n", _countof(challenge_funcs));
return -1;
}

uint32_t f = atol(argv[1]) % _countof(challenge_funcs);

uint32_t c1 = atol(argv[2]);
uint32_t c2 = atol(argv[3]);

printf("challenge_%d(%d, %d) -> %016I64X\n", f, c1, c2, challenge_funcs[f](c1, c2));

return 0;
}
في الحياة الواقعية، يمكن للمرء أن يجد نفسه في موقف مماثل يرغب في التعامل مع دالة كانها صندوق أسود بدلاً من عكسها مرة أخرى إلى pseudo-code. في مثل هذه الحالات، الشخص لديه العديد من الخيارات:
  • استخدم Appcall أثناء وقت التشغيل والاستعلام عن الدالة مباشرة.
  • استخدم decompiler لاستخراج الخوارزمية على شكل كود C زائف (C pseudo-code) وعمل recompile له ثم استخدمه.
  • استخراج تعليمات الاسمبلي للدالة وإعادة تجميعها-reassemble من ثم استخدامها.
  • استخدم برنامج للمحاكاة ( Unicorn engine على سبيل المثال) لعمل محاكاة للدالة.

دعنا نعمل compile لهذا البرنامج ونعمل عليه باستخدام c1 = 123 و c2 = 456:
 
C:\>for /l %a in (0, 1, 11) do @test.exe %a 123 456
challenge_0(123, 456) -> 8FDCE2E203FCAAF2
challenge_1(123, 456) -> E0317E1AB061ED8B
challenge_2(123, 456) -> A0A0E0C2279BE734
challenge_3(123, 456) -> 5D18D0A79D07D7D8
challenge_4(123, 456) -> 2583B4EEB62E6042
challenge_5(123, 456) -> D5261E0275AB9805
challenge_6(123, 456) -> F2B3282E143F7927
challenge_7(123, 456) -> 9B9B3CBB0169F4CD
challenge_8(123, 456) -> EF51086C5D1AF235
challenge_9(123, 456) -> FC8A97125C0EA232
challenge_10(123, 456) -> EEAE8BEB7996D2E7
challenge_11(123, 456) -> 4F36E6A65AB03929
 
  • عمل Disassembly للبرنامج
لنقم بعمل Disassembly للبرنامج الذي نختبرة وتحديد موقع جدول challenge_funcs و أول دالة للبرنامج:
;
; The challenge functions as referenced from main()
; (12 functions)
;
.rdata:0041749C 00 10 40 00 challenge_funcs dd offset sub_401000
.rdata:0041749C ; DATA XREF: _main+57↑r
.rdata:004174A0 90 10 40 00 dd offset sub_401090
.rdata:004174A4 30 11 40 00 dd offset sub_401130
.rdata:004174A8 D0 11 40 00 dd offset sub_4011D0
.rdata:004174AC 80 12 40 00 dd offset sub_401280
.rdata:004174B0 30 13 40 00 dd offset sub_401330
.rdata:004174B4 A0 13 40 00 dd offset sub_4013A0
.rdata:004174B8 30 14 40 00 dd offset sub_401430
.rdata:004174BC C0 14 40 00 dd offset sub_4014C0
.rdata:004174C0 30 15 40 00 dd offset sub_401530
.rdata:004174C4 E0 15 40 00 dd offset sub_4015E0
.rdata:004174C8 80 16 40 00 dd offset sub_401680

;
; The first challenge function
;
.text:00401000 ; int __cdecl sub_401000(int c1, int c2)
.text:00401000 sub_401000 proc near
.text:00401000 ; CODE XREF: _main+65↓p
.text:00401000 ; DATA XREF: .rdata:challenge_funcs↓o
.text:00401000
.text:00401000 var_8= dword ptr -8
.text:00401000 var_4= dword ptr -4
.text:00401000 c1= dword ptr 8
.text:00401000 c2= dword ptr 0Ch
.text:00401000
.text:00401000 55 push ebp
.text:00401001 8B EC mov ebp, esp
.text:00401003 83 EC 08 sub esp, 8
.text:00401006 53 push ebx
.text:00401007 56 push esi
.text:00401008 57 push edi
.text:00401009 60 pusha
.text:0040100A 8B 45 08 mov eax, [ebp+8]
.text:0040100D 8B 55 0C mov edx, [ebp+c2]
.text:00401010 F7 D0 not eax
.text:00401012 4A dec edx
.text:00401013 33 D0 xor edx, eax
.text:00401015 33 D0 xor edx, eax
.text:00401017 40 inc eax
.text:00401018 F7 D0 not eax
.text:0040101A 81 EA 66 24 C1 27 sub edx, 27C12466h
.text:00401020 40 inc eax
.text:00401021 4A dec edx
.text:00401022 F7 D2 not edx
.
.
.
.text:00401076 F7 D2 not edx
.text:00401078 89 45 F8 mov [ebp+var_8], eax
.text:0040107B 89 55 FC mov [ebp+var_4], edx
.text:0040107E 61 popa
.text:0040107F 8B 45 F8 mov eax, [ebp+var_8]
.text:00401082 8B 55 FC mov edx, [ebp+var_4]
.text:00401085 5F pop edi
.text:00401086 5E pop esi
.text:00401087 5B pop ebx
.text:00401088 8B E5 mov esp, ebp
.text:0040108A 5D pop ebp
.text:0040108B C3 retn
.text:0040108B
.text:0040108B sub_401000 endp
.text:0040108B
يمكننا تحديد موقع جدول challenge_funcs بسهولة لأنه يتم الرجوع إليه من ()main . تتميز دالة البرنامج الأولى، مثلها مثل كل الدوال الأخرى، بتنسيق/نمط متميز تمامًا والذي سنبني عليه تصميم المحاكي.
يمكننا أن نرى بوضوح تعليمة pusha (في 0x401009)، متبوعًا بتعليمتين يقومان بتحميل القيم الأولية (في 0x40100A و 0x40100D) ، ثم سلسلة من العمليات (بين 0x401010 و 0x401076) على تلك المسجلات وأخيراً نرى النتائج يتم نسخها مرة أخرى إلى المتغيرات المحلية (في 0x401078 و 0x40107B) قبل استخدام popa لاستعادة جميع المسجلات.
سوف نستخدم نمط الكود هذا لكتابة دالة صغيرة تحدد حدود التعليمات التي تقوم بالحساب-computation. سنقوم بعد ذلك بكتابة دالة أخرى تحاكي الكود البرمجي في نطاق معين وتعيد النتيجة.
 
  • كتابة المحاكي
في هذا القسم، سنقوم بعمل دالتين:
  • ()scope_challenge_function: تعثر هذه الدالة على حدود التعليمات المراد محاكاتها.
  • ()emulate_challenge_function: تحاكي هذه الدالة التعليمات ضمن نطاق معين.
قبل البدء، دعونا نحدد بعض المتغيرات العامة التي يحتاجها السكربت:
 
import idc, idautils, idaapi

challenge_funcs_tbl = 0x41749C
challenge_funcs_tbl_size = 12

RESULTS = (
0x8FDCE2E203FCAAF2,
0xE0317E1AB061ED8B,
0xA0A0E0C2279BE734,
0x5D18D0A79D07D7D8,
0x2583B4EEB62E6042,
0xD5261E0275AB9805,
0xF2B3282E143F7927,
0x9B9B3CBB0169F4CD,
0xEF51086C5D1AF235,
0xFC8A97125C0EA232,
0xEEAE8BEB7996D2E7,
0x4F36E6A65AB03929)
استنتجنا جدول دوال البرنامج وحجمه من خلال عملية الـdisassembly أعلاه. نحدد أيضًا متغير RESULTS الذي يحتوي على ناتج استدعاء كل دالة باستخدام c1 = 123 و c2 = 456. سنستخدم هذا الجدول للتحقق من عملية المحاكاة بعد الانتهاء.
لتعداد جميع دوال البرنامج في الجدول، يمكننا القيام بشيء مثل:
for i in range(0, challenge_funcs_tbl_size):
func = idc.Dword(challenge_funcs_tbl + i * 4)
print(">%x: challenge #%d" % (func, i + 1))
 
والمخرجات هي:
 
>401000: challenge #1
>401090: challenge #2
>401130: challenge #3
>4011d0: challenge #4
>401280: challenge #5
>401330: challenge #6
>4013a0: challenge #7
>401430: challenge #8
>4014c0: challenge #9
>401530: challenge #10
>4015e0: challenge #11
>401680: challenge #12
 
  • مقدمة سريعة لفك ترميز التعليمات - instruction decoding
لفك ترميز التعليمات باستخدام IDAPython ، استخدم الدالة ()idautils.DecodeInstruction:
 
# .text:0040101A 81 EA 66 24 C1 27 sub edx, 27C12466h
inst = idautils.DecodeInstruction(0x40101A)
إذا عملية فك الترميز فشلت، فستُرجع هذه الوظيفة None. في حالة نجاح فك الترميز، نحصل على كائن تعليمي يحتوي على معلومات حول التعليمة ومعاملاتها.

هذه هي ميزات التعليمات الهامة:
  • inst.itype: هذا عدد صحيح يمثل نوع التعليمات. ألـopcodes المختلفة لها نفس الـ itype وبالتالي opcode != itype.
  • inst.size: هذا هو حجم التعليمات البرمجية المراد فك ترميزها.
  • inst.Operands: هذه مصفوفة تستند إلى صفر تحتوي على معلومات المعاملات.
  • inst.Op1 .. OpN: هذه هي الأسماء المستعارة المستندة إلى 1 في مصفوفة Operands.
  • inst.ea : العنوان الخطي للتعليمات البرمجية المراد فك ترميزها
قد تتساءل ما هي العلاقة بين opcode و itype؟ الجواب بسيط. في IDA، تكون وحدة قاعدة البيانات المفتوحة للمعالجات ( او the open database’s processor module ) مسؤولة عن ملء حقل itype استنادًا إلى opcode. في IDA SDK يمكنك العثور على ملف header يسمى allins.hpp. يحتوي ملف الـ header هذا على تعدادات لكافة وحدات المعالجات المدعومة مع enum members لكل تعليمة مدعومة:
// Excerpt from allins.hpp

// x86/x64 itypes
enum
{
NN_null = 0, // Unknown Operation
NN_aaa, // ASCII Adjust after Addition
NN_aad, // ASCII Adjust AX before Division
NN_aam, // ASCII Adjust AX after Multiply
NN_aas, // ASCII Adjust AL after Subtraction
.
.
.
NN_jz, // Jump if Zero (ZF=1)
NN_jmp, // Jump
NN_jmpfi, // Indirect Far Jump
NN_jmpni, // Indirect Near Jump
NN_jmpshort, // Jump Short (not used)
NN_lahf, // Load Flags into AH Register
.
.
.
// Pentium III Pseudo instructions

NN_cmpeqps, // Packed Single-FP Compare EQ
NN_cmpltps, // Packed Single-FP Compare LT
NN_cmpleps, // Packed Single-FP Compare LE
NN_cmpunordps, // Packed Single-FP Compare UNORD
.
.
.
}

لا أعرف السبب ،ولكن يتم استخدام البادئة NN_ prefix لجميع أنواع التعليمات على معالج x86/x64.
إليك مثال بسيط على كيفية فك الترميز والتحقق من نوع التعليمات:
# .text:00402085 74 09 jz short loc_402090
inst = idautils.DecodeInstruction(0x402085)
print("YES" if inst.itype == idaapi.NN_jz else "NO")
يمكن للمرء أن يتحقق بشكل حدسي من التعليمة التي تم فك ترميزها عن طريق المقارنة مع أحد ثوابت idaapi.NN_xxxx.
بالنسبة للمعاملات، يمكن للمرء الوصول إليها عبر inst.Operands أو inst.OpN. للحصول على عدد المعامِلات المستخدمة بواسطة التعليمة البرمجية التي تم فك ترميزها، يجب ألا تعتمد على طول Operands array لأنه سيتم تثبيتها دائمًا على UA_MAXOP == 8 (راجع ida.hpp). بدلاً من ذلك، قم بالنظر مراراً على كل معامل ومعرفة ما إذا كان نوعه o_void.

يتم تعريف معامل التعليمة باستخدام نوع بنية op_t المحدد في ملف الهيدر ua.hpp.

بعض أعضاء المعاملات هي:
  • op.flags: معاملات الرايات.
  • op.dtype: نوع المعامل. أحد ثوابت dt_xxx. يمكن للشخص استخدام هذا الحقل لمعرفة حجم المعامل (1 == dt_byte ، 2 == dt_word ، إلخ).
  • op.type: نوع المعامل. أحد الثوابت.
  • o_xxx. specflag1 .. specflag4: رايات محددة للمعالج.
]هذه هي أنواع المعاملات المدعومة (o_xxx):
  • o_void: لا يوجد مُعامل.
  • o_reg: المعامل هو مسجل (al، ax، es، ds ...).
  • o_mem: مرجع الذاكرة المباشر (DATA).
  • o_phrase: مرجع الذاكرة [Reg Reg + Index Reg].
  • o_displ: ذاكرة مسجل [Base Reg + Index Reg + Displacement].
  • o_imm: قيمة فورية.
  • o_far: العنوان البعيد الفوري (CODE).
  • o_near: العنوان القريب الفوري (CODE).
  • o_idpspec0 .. o_idpspec5: رايات محددة للمعالج.
هناك معاملات إضافية تختلف معانيها بناءً على نوع المعامل:
  • op.reg: رقم المسجل (o_reg).
  • op.phrase: مسجل الفهرسة مع معاملات الوصول الى الذاكرة (o_phrase).
  • op.value: القيمة الفورية (o_imm) أو الإزاحة الخارجية (o_displ).
  • op.addr: عنوان الذاكرة المستخدم من قبل المعامل ( o_mem, o_far, o_displ, o_near).
عندما يكون نوع المعامل o_reg أو o_phrase ، فإن قيم op.reg / op.phrase تحتوي على قيمة التعداد الخاصة بالمسجل. مثل مصطلحات NN_xxx، يوفر IDA SDK أيضًا أسماء المسجلات الثابتة وقيمها؛ ولكن هذا صحيح فقط بالنسبة إلى وحدة المعالج x86/x64. إليك مقتطف من ملف الهيدر intel.hpp:
enum RegNo
{
R_ax = 0,
R_cx,
R_dx,
R_bx,
R_sp,
R_bp,
R_si,
R_di,
R_r8,
R_r9,
R_r10,
R_r11,
R_r12,
R_r13,
R_r14,
R_r15,
.
.
.
}
 
لسوء الحظ، هذه الـ enums غير متوفرة لـ IDAPython ، لكننا على الأقل نعرف ما يكفي لتحديد شيء مثل التالي:
REG_EAX = 0
REG_EDX = 2
REG_EBP = 5
.
.
.
REG_NAMES = { REG_EAX: 'eax', REG_EDX: 'edx', REG_EBP: 'ebp' ...}
إليك مثال آخر على كيفية "disassemble" تعليمة بالكامل:
# .text:0040106F 35 90 8D 28 DA xor eax, 0DA288D90h
out = ''
inst = idautils.DecodeInstruction(0x40106F)
out += "XOR " if inst.itype == idaapi.NN_xor else ""
out += "EAX" if (inst.Op1.type == idaapi.o_reg and inst.Op1.reg == 0) else ""
out += ", 0x%08X" % inst.Op2.value if (inst.Op2.type == idaapi.o_imm) else ""

print(out)

# Outputs: XOR EAX, 0xDA288D90
هكذا تم تغطية مبادئ فك ترميز التعليمات. يرجى الرجوع إلى ملفات الهيدر intel.hpp و allins.hpp و ua.hpp و idp.hpp لمزيد من المعلومات.
 
  • تحديد نطاق دوال البرنامج
في وقت سابق، اكتشفنا كيفية تجاوز جدول دوال البرنامج واسترداد عنوان كل ودالة. دعنا الآن نكتب دالة تستخدم وحدة فك ترميز التعليمات للعثور على حدود التعليمات التي يجب محاكاتها.
يرجى ملاحظة أنه يمكنني استخدام ()FindBinary في IDAPython ولكن هذا ينافي الغرض من هذه الدوينة. لأغراض العرض التوضيحي، أرغب في العثور على نمط الكود البرمجي المعني عن
طريق استخدام فك ترميز التعليمات فقط:
 
def scope_challenge_function(func_ea):
f = idaapi.get_func(func_ea)
if f is None:
return (False, "No function at address!")

emu_start, emu_end = f.startEA, f.endEA

ea = emu_start

#
# Find the start of the emulation pattern
#
stage = 0
while ea <= emu_end:
inst = idautils.DecodeInstruction(ea)
if inst is None:
return (False, "Could not decode")

# Advance to next instruction
ea += inst.size

# mov (eax|edx), [ebp+?]
if (inst.itype == idaapi.NN_mov) and (inst.Operands[0].type == idaapi.o_reg) and \
(inst.Operands[1].type == idaapi.o_displ) and (inst.Operands[1].phrase == REG_EBP):
# mov eax, [ebp+8]
if (stage == 0) and (inst.Operands[0].reg == REG_EAX) and (inst.Operands[1].addr == 8):
stage = 1
# mov edx, [ebp+0xC]
elif (stage == 1) and (inst.Operands[0].reg == REG_EDX) and (inst.Operands[1].addr == 0xC):
stage = 2
emu_start = ea
elif (stage == 2) and (inst.itype == idaapi.NN_popa):
# Let's decode backwards twice and double check the pattern
ea2 = idc.PrevHead(ea)

# Disassemble backwards
for _ in range(0, 2):
ea2 = idc.PrevHead(ea2)

inst = idautils.DecodeInstruction(ea2)
if (inst.itype == idaapi.NN_mov) and (inst.Op1.type == idaapi.o_displ) and \
(inst.Op1.reg == 5):
if inst.Op2.reg == 2 and stage == 2:
stage = 3
elif inst.Op2.reg == 0 and stage == 3:
stage = 4
emu_end = ea2
break

break


if stage != 4:
return (False, "Could not find markers")

return (True, (emu_start, emu_end))
يتمثل النمط الأساسي عند فك ترميزالتعليمات في تقديم عنوان فك الترميز (متغير ea في هذه الحالة) من خلال inst.size بعد كل عملية فك ترميز ناجحة. بعد ذلك، ينبغي للمرء التحقق من نوع التعليمات، ثم تفقد المعاملات وفقًا لذلك.

لاحظ أنه في المرحلة رقم 2، انا بدأت في فك التشفير للخلف. للرجوع إلى الخلف في قائمة الـ disassembly بشكل مناسب، يمكن استخدام دالة ()idc.PrevHead للحصول على عنوان البدء للتعليمات المحددة مسبقًا (راجع السطر 37). دعنا نختبر هذه الدالة:
 
Python>ok, info = scope_challenge_function(0x401000)
Python>if ok: print("start=%08X end=%08X" % (info[0], info[1]))
start=00401010 end=00401078
 
  • محاكاة التعليمات
في الخطوة السابقة، تمكنا من الحصول على عنوان البداية والنهاية للحدود المراد محاكاتها. الآن دعنا نكتب دالة محاكاة بسيطة تدعم فقط
مجموعة محدودة من التعليمات (NOT ، DEC ، INC ، XOR ، SUB و ADD):
def emulate_challenge_function(info, c1, c2, dbg = False):
emu_start, emu_end = info
if dbg:
print("Emulating from %x to %x (%d, %d)" % (emu_start, emu_end, c1, c2))

# Reset registers
regs = {
REG_EAX: c1,
REG_EDX: c2
}

def get_opr_val(inst, regs):
if inst.Op2.type == o_imm:
return (True, inst.Op2.value)
elif inst.Op2.type == idaapi.o_reg:
return (True, regs[inst.Op2.reg])
else:
return (False, 0)

ea = emu_start
while ea < emu_end:
out = ">%x: " % ea
ok = True
inst = idautils.DecodeInstruction(ea)
ea += inst.size
if inst.itype == idaapi.NN_not:
out += "NOT"
regs[inst.Op1.reg] = ~regs.get(inst.Op1.reg, 0) & 0xffffffff
elif inst.itype == idaapi.NN_dec and inst.Op1.type == idaapi.o_reg:
out += "DEC"
regs[inst.Op1.reg] = (regs.get(inst.Op1.reg, 0) - 1) & 0xffffffff
elif inst.itype == idaapi.NN_inc and inst.Op1.type == idaapi.o_reg:
out += "INC"
regs[inst.Op1.reg] = (regs.get(inst.Op1.reg, 0) + 1) & 0xffffffff
elif inst.itype == idaapi.NN_xor:
ok, val = get_opr_val(inst, regs)
regs[inst.Op1.reg] = (regs.get(inst.Op1.reg, 0) ^ val) & 0xffffffff
out += "XOR %08X" % val
elif inst.itype == idaapi.NN_sub:
ok, val = get_opr_val(inst, regs)
regs[inst.Op1.reg] = (regs.get(inst.Op1.reg, 0) - val) & 0xffffffff
out += "SUB %08X" % val
elif inst.itype == idaapi.NN_add:
ok, val = get_opr_val(inst, regs)
regs[inst.Op1.reg] = (regs.get(inst.Op1.reg, 0) + val) & 0xffffffff
out += "ADD %08X" % val
else:
ok = False

# Dump registers
for k, v in regs.items():
out += (" [%s: %08X] " % (REG_NAMES.get(k, "%x" % k), v))

if not ok:
return (False, "Emulation failed at %08X" % ea)

if dbg:
print(out)

return (True, (regs[REG_EDX] << 32) | regs[REG_EAX])
 
عندما تبدأ الدالة، يتم ملء قاموس regs بالقيم الأولية للمسجلات. نحن نستخدم op.reg كمفتاح في هذا القاموس. سيحتوي أي مسجل غير مهيأ على القيمة صفر. دالة المحاكاة بعد ذلك تدخل في loop وتفك ترميز كل تعليمة. لكل تعليمة، تقوم بفحص نوعها (لمعرفة العملية التي يجب محاكاتها) ومعاملاتها (لمعرفة كيفية استرداد القيم المطلوبة). في نهاية الحلقة ، يتم إرجاع قيمة 64 بت.

يمكننا التحقق من صحة المحاكاة من خلال مقارنة النتائج التي يتم إرجاعها من المحاكاة بالنتائج التي حصلنا عليها سابقًا:
for i in range(0, challenge_funcs_tbl_size):
func = idc.Dword(challenge_funcs_tbl + i * 4)

ok, info = scope_challenge_function(func)
if ok:
ok, val = emulate_challenge_function(info, 123, 456, dbg)
if (val != RESULTS[i]):
print("Mistmatch #%d: %16X vs %16X" % (i, val, RESULTS[i]))
break

else:
print("Failed to scope challenge function #%d" % i)[/i][/i]
 
آمل أن تكونوا قد وجدتم هذه التدوينه مفيدة. لا تتردد في طرح الأسئلة و/أو الإشارة إلى الأخطاء في هذه التدونة. يمكنك تنزيل الملفات المستخدمة في هذه المقالة من الملفات المرفقة
باس الملف المرفق
Password: 123

-----------------------------------
المقالة مترجمة من http://0xeb.net/2018/02/writing-a-simple...idapython/
لا تتردد في طرح الأسئلة و/أو الإشارة إلى الأخطاء في هذه الترجمة
لا تنسوني ووالدي من الدعاء Smile
[/align]


الملفات المرفقة
.zip   ida-emulate-example.zip (الحجم : 54.18 KB / التحميلات : 31)
سبحان الله وبحمده، سبحان الله العظيم
أعضاء أعجبوا بهذه المشاركة : TeRcO , mribraqdbra , M!X0R , cyberman , esso_x , hesham
#2
صراحة موضوع رائع يكاد أن ينعدم متل هاته المواظيع زادك الله في علمك وشكرا
أعضاء أعجبوا بهذه المشاركة :


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 3 ) ضيف كريم