تقييم الموضوع :
  • 1 أصوات - بمعدل 5
  • 1
  • 2
  • 3
  • 4
  • 5
اشياء بسيطة لاكن مفعولها كبير
#1
اول شي اريد ان اشير اله هوا انه برامج لما تشغلها في debugger او disassembler ف هي لا تتوقف عند ال main بل تتوقف عند entry point هادا اخير ليس له علاقة في معضم احيان ب الهندسة العكسية وغريب في امر قبل مدة كنت بعمل interview لأحد اشخاص و اعطيته شي يعمل له تحليل الغريب انه كان يعرف اسمبلي كويس لاكن بدء يعمل analyse لل entry point مش لل main
لهادا انتبهوا ف debugger و disassmbler لا يتوقف في main لهاد قبل البدء في تحليل عليك ان تجد دالة الmain وهنا ليس هناك طريقة محددة ف كل compiler يقوم ب انتاج entry point بشكل او ب أخر على سبيل المتال 
 
 
.text:08048740 start           proc near               ; DATA XREF: LOAD:08048018↑o
.text:08048740                 xor     ebp, ebp
.text:08048742                 pop     esi
.text:08048743                 mov     ecx, esp
.text:08048745                 and     esp, 0FFFFFFF0h
.text:08048748                 push    eax
.text:08048749                 push    esp
.text:0804874A                 push    edx
.text:0804874B                 call    mov_Vesp_To_ebx_ret
.text:08048750                 add     ebx, 938B0h
.text:08048756                 lea     eax, (___libc_csu_fini - 80DC000h)[ebx]
.text:0804875C                 push    eax
.text:0804875D                 lea     eax, (___libc_csu_init - 80DC000h)[ebx]
.text:08048763                 push    eax
.text:08048764                 push    ecx
.text:08048765                 push    esi
.text:08048766                 mov     eax, offset network_handler
.text:0804876C                 push    eax
.text:0804876D                 call    sub_8048DE0
.text:0804876D start           endp
.text:0804876D
في هاده الحالة نحن في entry point لاكن ال Main هي network_handler 

لاكن سأل يطرح ادا كان كل compiler له شكل من اشكال entry point كيف نعرف مكانها 

هناك جوابين 
اول هوا استخدام ida pro حتى هادا اخير يتوفر على sig خاصة ب entry point ل بعض ال compilers و ايضا يتيح لك اضافة 
sig خاصة في حالة عدم تواجدها في حالة ال compilers  الجدد لا يستطيع تعرف عليهم متلا انا عندي 7.4 من ida و عندي sdk 1909 
وهادا اخير لا يتطيع تعرف على main sig او library sig في حالة  static link لهادا لل compilers ل جديدة تحتاج تضيف sig يدويا 

الحل التاني حاول تعمل تجارب على اصدار ال compiler لي تواجهه وهير رح تعرف كيف يتم تكوين entry point لل compiler لي تستهدف
 

شي التاني هوا فهم assembly والدي هو اساسي جدا ف decompiler خاص ب ida او هاديرة او ...  ليس ب الشيء الدي تعتمد عليه بتاتا, لاكن لمادا 

على سبيل المتال انت تتعامل مع SIMD instructions او AVX  فهادا اخير لا يتوافق مع اي decompliers و معضم decompliers تعطي نتائج خاطئة او طويلة

الشي التاني لو كنت تتعامل مع هدف يستخدم anti deassembly و شتغلت ب decompiler ف هادا اخير سوف يعطي نتائج خاطئة و ايضا لن تستطيع ان تفهم انك تتعامل مع anti  deassembly tricks بينما في assembly view سوف تستطيع ملاحضة بعض instruction الغريبة ومعرفة انه هادا view خاطئ 

ايضا على سبيل المتال بعض compilers تضع stack cookie على بعض الدوال و لا تضعه على بعض الدوال اخرى لاكن هادا لا يتضح بشكل واضح في decompiler و ايضا في بعض احيان يكون فهم كود اسمبلي اسهل من فهم C او بسودوا كود 


لنأخد على سبيل المتال كود اسمبلي التالي 
 

func:
  push rcx 
  xor rcx, rcx 
  mov rdx, rsi 
  and edx, 0xff 
l:mov al, byte [rdi] 
  test al, al   
  jz e
  cmp dl, byte [rdi]
  jne n
  inc rcx
n:inc rdi
  jmp l
e:mov rax, rcx
  pop rcx
  ret
و هوا تحدي بسيط يستغرق دقائق لاكن وللأسف لا أحد حاول معاه ما عدا YANiS الدي ستخدم decompiler وهادا هوا شي الخطير ارجوكم بعدوا من decompilers راهوم يدعطونكم نتائج خاطئة

على كل انا رح اقدم تحليل بسيط لل asm ده لاكن قبل كل شيء لازم نعرف بعض اشياء في x64 هناك اختلاف في calling convention ما بين linux و windows حيت Linux يعمل parm رقم واحد في RDI و تاني في RSI , 
RDX
RCX
R8 
R9 
ترتيب في هاده الحالة من يسار لليمن 
في حالة كان هناك اكتر من 6 يقوم ب دفع args  المتبقين من يمين لل يسار  لل مكدس في شي ما رح اتحدت عليه لاكن مهم جدا اسمه shadow store ابحتوا عنه وهادا اخير يوجد في linux و وندوز و ايضا في حالة ال floating point ف لي فوق يتخلفوا لاكن هادا موضوع اخر ايضا


في وندوز 

متله متل Linux لاكن اربع args اولين ينحطون في ترتيب من يسار لليمين في 
RCX 
RDX
R8
R9 
في حالة floating point يختلف xmm و ايضا ادا كان اكتر من 4 يتم دفعهم لل stack من يمين لليسار 

وايضا لوا كان احد args يحتوي قيمة اكتر من 64 bit بحيت لا تستطيع وضعه في احد registers لي فوق يتم تمرير pointer ل args 

على كل ابحتوا في الموضوع 

نجي لزبدة الكلام 

او شي نلاحضه انه دالة تعمل push ل RCX و تجعل قيمته 0 و قبل ret تعمل restore لقيمة RCX ادن نستنج منه انه local var وقيمته 0

بعدين نلاحض 
mov rdx, rsi
في هاده الحالة نستنج 2 اشياء اولها نحن نتعامل مع linux calling convention وتاني شي انه يوجد 2 args للدالة وليس 3 لأنه لن يكون من طبيعي عمل overwrite ل arg رقم 3 كما سبق وقلت arg رقم 3 سوف يتم وضعه في RDX 

بعدين عندنا هادا الكود
and edx, 0xff 

ادا دل على شيء دل على typecasting من RDX ل char لمادا char وليس byte اولا ادا كنت من مستخدمين لغة C سوف تفهم انه نوع الوحيد الدي يستخدم ب كترة و طوله هوا  1 byte هوا char بينما ادا استخدمت بعض decompilers سوف تلاحض 
انه بعضهم  يسميها byte 


هاكدا 
rdx = (char)rdx
يجب ان لا ننسى ان rdx هوا arg رقم 2 في هاده الحالة 

بعدين 
mov al, byte [rdi]
هادا يقوم بنقل byte من arg اول 
وبعدين يعمل 
يوجد هادا الكود والدي هوا بسيط نوعا ما  
  test al, al   
  jz e

حيت كل يقوم بعمل check لكي يرى ادا al يحتوي على قيمة 0 في حالة كانت قيمة صفر يقفز ل e 
فوق فهمنا ان rdx لي هوا arg2 يتم عمل له cast لي char هنا يوجد check على قيمة 0 اضن ان امور اصبحت واضحة 
هادا الكود يقوم ببحت عن اخر char في string 

ويتأكد هادا استنتاج في الكود الدي يتبع الدي فوق 
  cmp dl, byte [rdi]
حيت يتم عمل check لمعرفة ادا dl يساوي rdi بحيت انه dl هوا char و rdi هوا pointer ل string  وهنا تكون امور اصبحت واضحة وضوح الشمس 

ليس هناك داعي  متابعة 
و هادا هوا decompilation يدوي 
 
 
int func(char *str, char character) {
  int counter = 0;
  while(*str) {
    if (*str == character) counter++;
    str++;
  }
   return counter;
}

على كل في هاده الحالة decompiler سوف يعطي نتائج متقاربة لكن ليسة دقيقة 

على كل جربت هادا تحدي على شخص خبير 
حيت اخد منه اقل من 30 تانية لكي يتنتج ما الدي يفعله الكود و ايضا احد اصدقاء الدي يشتغل مبرمج لا علاقة له ب الهندسة العكسية استطاع حله في 5 دقائق وهادا كان حله 
 
 
uint64_t func(char *ptr, char c) {
  size_t count = 0;

  while (*ptr) {
    if (*ptr == c)
      count++;
    ptr++;
  }

  return count;
}

على كل مشكل الحقيقي في انه معضم compilers في وقتنا الحالي تستخدم simd و AVx لما تضع optimization ولحد ساعة لم اجد decompiler يستطيع تعامل معها بشكل جيد

لهادا كنصيحة حاول تعمل تجارب لكي تتعلم كيف تقرء الأسمبلي بشكل جيد و ركزوا على simd و avx و floating point فهم شوية tricky 
 

شي 3 على كل شخص لازم يتعلم كيف يعمل hooking شي ضروري 

متال بسيط قبل حوالي 3 ايام كان عندي sample بسيط مبرمج ب C# لاكن كان محمي ب vmprotect 
ولكي استطيع تعامل مع هاده الحماية كان لازم ان اشغل برنامج تحت بئية dnspy لاكن كل مرة يعمل لي detect ل debugger بعد استخدام api monitor لاحضت انه يعمل tick count و remote debugger check و isdebugger و ... 

بنسبة ل isdebuggerpresnt و check remote debugger هما معمول لهم bypass  في dnspy لاكن tick count لا 
فكان عليا ان اعمل hook ل دالة ntqueryperformancecounter واجعلها ترجع قيم صغيرة عشان ما يتم كشفي 
وسبب وراء ال hook هو انه  vmprotect يعمل لها check في كل تانية من اماكن عديدة و محاولة عمل patch لكل اماكن ده شيء غبي نوعا ما 

لهادا تعلموا كيف تقومون ب عمل hook ضروري جدا 
 

أعضاء أعجبوا بهذه المشاركة : PowerUser , the9am3 , Small Axe , fantazma , [email protected] , rce3033


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


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