21-05-2020, 01:20 PM
(آخر تعديل لهذه المشاركة : 21-05-2020, 01:22 PM بواسطة ahmed_1337.)
اول شي اريد ان اشير اله هوا انه برامج لما تشغلها في debugger او disassembler ف هي لا تتوقف عند ال main بل تتوقف عند entry point هادا اخير ليس له علاقة في معضم احيان ب الهندسة العكسية وغريب في امر قبل مدة كنت بعمل interview لأحد اشخاص و اعطيته شي يعمل له تحليل الغريب انه كان يعرف اسمبلي كويس لاكن بدء يعمل analyse لل entry point مش لل main
لهادا انتبهوا ف debugger و disassmbler لا يتوقف في main لهاد قبل البدء في تحليل عليك ان تجد دالة الmain وهنا ليس هناك طريقة محددة ف كل compiler يقوم ب انتاج entry point بشكل او ب أخر على سبيل المتال
لاكن سأل يطرح ادا كان كل 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 او بسودوا كود
لنأخد على سبيل المتال كود اسمبلي التالي
على كل انا رح اقدم تحليل بسيط لل 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
بعدين نلاحض
بعدين عندنا هادا الكود
ادا دل على شيء دل على typecasting من RDX ل char لمادا char وليس byte اولا ادا كنت من مستخدمين لغة C سوف تفهم انه نوع الوحيد الدي يستخدم ب كترة و طوله هوا 1 byte هوا char بينما ادا استخدمت بعض decompilers سوف تلاحض
انه بعضهم يسميها byte
هاكدا
بعدين
وبعدين يعمل
يوجد هادا الكود والدي هوا بسيط نوعا ما
حيت كل يقوم بعمل check لكي يرى ادا al يحتوي على قيمة 0 في حالة كانت قيمة صفر يقفز ل e
فوق فهمنا ان rdx لي هوا arg2 يتم عمل له cast لي char هنا يوجد check على قيمة 0 اضن ان امور اصبحت واضحة
هادا الكود يقوم ببحت عن اخر char في string
ويتأكد هادا استنتاج في الكود الدي يتبع الدي فوق
ليس هناك داعي متابعة
و هادا هوا decompilation يدوي
على كل في هاده الحالة decompiler سوف يعطي نتائج متقاربة لكن ليسة دقيقة
على كل جربت هادا تحدي على شخص خبير
حيت اخد منه اقل من 30 تانية لكي يتنتج ما الدي يفعله الكود و ايضا احد اصدقاء الدي يشتغل مبرمج لا علاقة له ب الهندسة العكسية استطاع حله في 5 دقائق وهادا كان حله
على كل مشكل الحقيقي في انه معضم 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 ضروري جدا
لهادا انتبهوا ف 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 ضروري جدا