
BlackLotus-Z2A-Challenge، لا يوجد شيء لرؤيته هنا الآن، من فضلك امضِ قدمًا
BlackLotus-Z2A-Challenge، لا شيء لتراه هنا في الوقت الحالي، تفضل بالمضي قدمًا
الأهم أولاً

لأغراض جمالية فقط، سأستعير (بكل خجل) :)) قواعد كشف yara من حل @darthmaulware(Ryan “DM” Smith) فقط لأجعل الأمر يبدو احترافيًا. اذهب وتفقّد حسابه على تويتر، إنه شخص رائع بجنون! ملاحظة: ريان، من فضلك لا تغضب لأنني سرقت ذلك :))) وشكرًا لدعمك في ديسكورد :)
من فضلكم تفقّدوا أعماله أيضًا :)
https://gitlab.com/malre-rcs/zero2automated/-/blob/main/solutions/bi_weekly_challenge/BlackLotus_20230321/BlackLotus_HTTP_Downloader.ipynb``` rule Blacklotus_HTTP_Downloader { meta: description = "Rule to detect Blacklotus HTTP Downloader" author = "Darth Maulware" sha256 = "d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66"
strings:
$opcode1 = {48 89 4C 24 08 48 89 54 24 10 4C}
$opcode2 = {89 44 24 18 4C 89 4C 24 20 48 83}
$opcode3 = {EC 28 B9 31 62 D7 2E 90 90 E8 ??}
$opcode4 = {?? ?? ?? 48 83 C4 28 48 8B 4C 24}
$opcode5 = {08 48 8B 54 24 10 4C 8B 44 24 18}
$opcode6 = {4C 8B 4C 24 20 4C 8B D1 90 90}
condition:
(uint16(0) == 0x5a4d and filesize < 500KB and all of them)
}
أيضًا لأسباب جمالية سأسرق هذا أيضًا لأنه يبدو رائعًا :) مرة أخرى آسف ريان، من فضلك لا تغضب مني :)```
C:\\Users\\REM\\Desktop>capa.exe -f pe -r capa-rules-5.0.0 d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66.exe
matching: 100%|████████| 124/124 [00:02<00:00, 46.96 functions/s, skipped 1 library functions (0%)]
+------------------------+------------------------------------------------------------------------------------+
| ATT&CK Tactic | ATT&CK Technique |
|------------------------+------------------------------------------------------------------------------------|
| DEFENSE EVASION | Obfuscated Files or Information T1027 |
| DISCOVERY | Process Discovery T1057 |
| EXECUTION | Shared Modules T1129 |
+------------------------+------------------------------------------------------------------------------------+
+-----------------------------+-------------------------------------------------------------------------------+
| MBC Objective | MBC Behavior |
|-----------------------------+-------------------------------------------------------------------------------|
| ANTI-BEHAVIORAL ANALYSIS | Debugger Detection::Process Environment Block BeingDebugged [B0001.035] |
| | Debugger Detection::Process Environment Block NtGlobalFlag [B0001.036] |
| CRYPTOGRAPHY | Encrypt Data::RC4 [C0027.009] |
| | Generate Pseudo-random Sequence::RC4 PRGA [C0021.004] |
| DATA | Encode Data::XOR [C0026.002] |
| DEFENSE EVASION | Obfuscated Files or Information::Encoding-Standard Algorithm [E1027.m02] |
+-----------------------------+-------------------------------------------------------------------------------+
+------------------------------------------------------+------------------------------------------------------+
| CAPABILITY | NAMESPACE |
|------------------------------------------------------+------------------------------------------------------|
| execute syscall instruction (35 matches) | anti-analysis |
| check for PEB BeingDebugged flag (2 matches) | anti-analysis/anti-debugging/debugger-detection |
| check for PEB NtGlobalFlag flag | anti-analysis/anti-debugging/debugger-detection |
| encode data using XOR (2 matches) | data-manipulation/encoding/xor |
| encrypt data using RC4 PRGA (2 matches) | data-manipulation/encryption/rc4 |
| get process heap flags | host-interaction/process |
| get ntdll base address (3 matches) | linking/runtime-linking |
| parse PE header (2 matches) | load-code/pe |
| resolve function by parsing PE exports (2 matches) | load-code/pe |
+------------------------------------------------------+------------------------------------------------------+
لأكون صريحًا، لو كنت مكانك لما وثقت 100% في capa (على الأقل في هذه الحالة تحديدًا) لأنه هنا يقول إن العينة تستخدم rc4 بينما في الواقع العينة تستخدم aes، ولكن لا يهم، كما ذُكر هذا لأغراض تجميلية فقط :)
قبل أن نبدأ، ستواجه خلال هذا التقرير الكثير من

يرجى تجاهل هذا لأن ida يفشل في تفكيك هذا بشكل صحيح في لغة التجميع، هذا هو

وهذا يتسبب في تعطل المٌنقّح (debugger)؟ لماذا؟
لأنه يحاول الكتابة في العنوان 0، وهو ما يُعرف في التراث الشعبي للهاكرز بالكتابة في عنوان مؤشر فارغ (null pointer)، وهو شيء كان يُستغل على نطاق واسع للحصول على CE (تنفيذ كود)، وقد تم التخفيف من ذلك بوضوح.
ومع هذا التخفيف الحالي، إذا حاولت الكتابة في 0 فسيتعطل تلك العملية، وهي في حالتنا البرمجية الخبيثة، وبالتالي المٌنقّح.
الآن إذا فتحنا هذا في ida

أعدت تسمية كل دالة للإشارة إلى بعض المنطق الذي تقوم به، لنبدأ بالدالة الأولى، do_syscall()

نلاحظ فورًا استخدام استدعاءات النظام (syscalls)، وهي طريقة معروفة لجعل حياة المحلل أصعب عندما يتعلق الأمر بالتحليل الديناميكي.
لمن ليسوا على دراية بـ syscalls في ويندوز، إليكم فيديو رائع من إعداد oalabs(https://www.youtube.com/watch?v=Uba3SQH2jNE). من فضلكم شاهدوه لأنني شاهدته أيضًا وقد ساعدني كثيرًا في فهم ما يحدث في هذه الدالة.
إذا فحصنا «الكود الزائف» (pseudo-code) الذي أنتجه ida، نرى أنه يبدو هكذا

إذا فحصنا solve_hash بشكل ثابت، فسيبدو هكذا


من منظور الكود الزائف يبدو هكذا

يُرجى الرجوع إلى solve_hash.py لرؤية «محاكاتي» لهذا الأمر في حال أردت رؤية جزء من الأتمتة ومعرفة كيفية حل استدعاءات النظام عبر خوارزمية بحث تعتمد على التجزئة (hashing). ولكن على أي حال، هذا جزء من مشروع اسمه SysWhispers2 أو على الأقل هذا ما أفترض أن مؤلفي البرمجية الخبيثة استلهموا منه. على أي حال، يُرجى الرجوع إلى مقطع الفيديو أعلاه لـ oalabs لفهم أفضل.
على أي حال، دالة anti_debug يمكن تجاوزها بسهولة وهي معروفة جيدًا (https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-ntglobalflag). طريقة تجاوزها هي تثبيت scyllahide وتحديد خيار NtGlobalFlag (والذي يجب أن يكون مفعّلًا افتراضيًا إذا كنت تستخدم x86dbg). على أي حال، هذا ما يفترض أن تتحقق منه

وهكذا تبدو «الدالة الزائفة» لمكافحة التصحيح (anti-debug)

بسيطة جدًا في رأيي
بعد ذلك لدينا دالة check_inmemory_ldr والتي تبدو هكذا


الآن ولغرض تحليل الدالة، إذا سألنا x86dbg بلطف، يمكننا أن نرى أنه إذا شغّلنا حتى تعليمة syscall، فإن x86dbg سيكون لطيفًا بما يكفي ليعيد لنا استدعاء النظام الذي سيتم تنفيذه. في حالتنا

الآن بناءً على السياق الحالي، يمكننا أن نفترض أن Ntsetinformationthread سيُستخدم كنوع من خدع مكافحة التحليل. وبالتأكيد إذا قمنا ببحث سريع على جوجل، سنجد هذا https://ntquery.wordpress.com/tag/ntqueryinformationthread/
لحسن الحظ يمكن تجاوزها بسهولة فقط عن طريق عمل patch بـ nop+ret :)
=============================================================================
باتباع ترتيب التنفيذ، بعد هذا تأتي الدالة التالية

مرة أخرى، إذا فحصنا لنرى ماذا تفعل

إنها ببساطة تتحقق من علامة (flag) في teb لمعرفة ما إذا كانت العملية الحالية (الملف التنفيذي في حالتنا) قيد التصحيح. وهذا أيضًا سهل التجاهل لأنه طريقة معروفة (https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-peb-beingdebugged-flag) بنفس الطريقة التي استخدمنا بها scyllahide، هذه المرة يجب أن تكون مفعّلة

والتي يجب أن تكون مفعّلة افتراضيًا
=============================================================================
الآن custom_hash2_and_aplib_possible والتي تبدو هكذا

ومن منظور الرسم البياني (graph)

يُرجى الرجوع إلى decompress_aplib.py لرؤية «محاكاة» هذه الدالة.
عند استكشاف get_ntdll_and_unhook2 تبدو هكذا


من منظور الرسم البياني تبدو هكذا

ليست سيئة للغاية :))
بالتراجع قليلًا، لدينا aplib_decompress، تبدو الآن هكذا

من منظور تحليل الكود الثابت تبدو هكذا




ممم، كبيرة قليلًا، لا داعي للقلق يا رفاق، إنها قابلة للتنفيذ :)
إذا استخدمت سكريبت المحاكاة aplib_decompress.py، يجب أن تحصل على شيء كهذا

شيء رائع لم ألاحظه في المدونات/التحليلات الأخرى هو هذا: إذا ألقينا نظرة مرة أخرى على الكود الزائف لـ ida الخاص بـ ntdll_and_unhook2

سترى عملية memcpy مثيرة للاهتمام
في مرحلة ما أثناء قيامي بالتحليل الديناميكي، لاحظت تحميل ملف dll آخر، وهو إصدار آخر من ntdll

إذا نظرنا في المٌنقّح يبدو هكذا

لم أتمكن من اكتشاف ما تم تعليقه أو تصحيحه (hooked/patched)، لكن إذا كان أحد يعرف، فيرجى إرسال pull request وتعديل هذا المستند. أيضًا في محاولاتي لمعرفة ما يتم تعليقه، حاولت إجراء مقارنة ثنائية (bindiff) بين ملفَي ntdll، وللأسف لم أجد شيئًا، لكن ربما لأنني كنت أجري المقارنة على ملف نظام مصاب بالفعل، لذا لم تكن عملية نظيفة، ربما لهذا السبب ¯_(ツ)_/¯

=============================================================================
بالمضي قدمًا في عملية التحليل، لدينا بين الدوال غير المفسّرة كل من some_hasing وntquertyinformationprocess_anti_debug، وهاتان لم يتم شرحهما. أما check_if_being_debug_through_teb وanti_debug فقد تم شرحهما بالفعل لحسن الحظ لأنهما استُخدمتا في الدالة/الدوال السابقة، لذا يرجى قراءة الأقسام السابقة إذا أردت مراجعة المعلومات عنهما. أود أن أبدأ أولًا بـ ntquertyinformationprocess_anti_debug ثم أنهي بـ some_hasing.
عند فحصها نرى نفس الدالة تُستدعى 3 مرات.

ومن منظور لغة التجميع


للراحة، قمت بالفعل بتسميتها، وهي ntquertyinformationprocess_ProcessDebugPort. من أين عرفت أن الدوال التي تم استدعاؤها هي ntquertyinformationprocess_ProcessDebugPort؟ فحصها يكشف استدعاء دالة شاهدناها بالفعل/خوارزميات معروفة لنا

ماذا عن التعليقات التي وضعتها في ida؟ حسنًا، إذا بحثت عن ntqueryinformationprocess على جوجل، فسنجد مصدرًا جيدًا حول مكافحة التصحيح (https://anti-debug.checkpoint.com/techniques/debug-flags.html). إذا تابعنا، سنرى أنه يشرح لنا أنه بناءً على قيم معينة تُمرر كوسائط لهذه الدوال، يمكن استخدامها كطريقة لمكافحة التصحيح.
على سبيل المثال، بالنسبة للاستدعاء الأول، يمكننا رؤية وسائط المكدس التالية في المٌنقّح

إذا ذهبنا الآن وتفقدنا صفحة msdn الخاصة بـ ntqueryinformationprocess

نفس العملية تتكرر لاستدعائي النظام التاليين

حيث أن 0x1e خاص بطريقة مكافحة التصحيح ProcessDebugObjectHandle (https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software)
وأخيرًا ProcessDebugFlags

إذًا كيف نتجاوزها؟! خذها بسهولة يا صديقي، لأن ScyllaHide يغطي ظهرنا

كما ترى

إذًا نحن بأمان! ليس تمامًا، بينما ScyllaHide يغطينا لأول استدعائي نظام، بالنسبة لآخر استدعاء نظام علينا أن نفعله يدويًا! والآن ماذا أفعل؟؟؟ حسنًا، الحل بسيط! نعود من هذه الدالة أي من ntquertyinformationprocess_anti_debug بأكملها ونجعل eax يساوي 0. لذا في الظروف العادية يبدو الأمر هكذا

ومع «مساعدتنا» يبدو هكذا ونترك التنفيذ يمر بأمان :)

=============================================================================
الآن some_hasing، أنتم تعرفون التمرين بالفعل

والآن الكود الزائف

نلاحظ شيئًا غريبًا هنا. الكود الزائف لـ ida يفشل هنا... لأنه إذا تابعنا الرسم البياني بعد call_syscall، هناك تعليمات أخرى يجب تفكيكها. إذًا ماذا نفعل الآن؟ حسنًا، سنعتمد على المٌنقّح هنا لتحليل هذا الكود ديناميكيًا...
لذا نرى أن استدعاء النظام الذي يقوم به هو

الآن إذا بحثنا عن ntquerydefaultlocale، يوضح جوجل أن هذه واجهة برمجية غير موثقة تأخذ وسيطين (http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FLocale%2FNtQueryDefaultLocale.html). رائع، إذًا ماذا تفعل؟ إنها تعيد مُعرّف اللغة الحالي (Locale Identifier). رائع، إذًا ما هو مُعرّف اللغة؟ من msdn (https://learn.microsoft.com/en-us/windows/win32/intl/locale-identifiers) هو قيمة 32 بت تتكون من معرّف اللغة ومعرّف ترتيب الفرز. باختصار شديد، هي اللغة التي تتحدث بها على ذلك الكمبيوتر :)
بعد ذلك تتحقق مما إذا كانت الواجهة البرمجية لم تفشل في التنفيذ، وإذا لم تفشل في التنفيذ، فإنها تأخذ القيمة التي أعادتها ntquerydefaultlocale، وتطرح 0x419 وتقارنها مع 0x26 (غالبًا ثابت) كما ترى في الصورة أدناه.

إذا لم تكن أصغر من أو تساوي 0x26، فإنها تقارنها مع 0x818، وإلا فإنها تقوم بنفس المقارنة مع 0x819 كما ترى بوضوح

إذًا ما الذي يحدث هنا؟ ولماذا هذه الثوابت تحديدًا؟ حسناً، سأكون مباشرًا. أثناء بحثي عن ثوابت مختلفة، صادفت هذا المقال (https://www.cnblogs.com/DirWang/p/17281690.html#autoid-8-0-0)، حيث قام باحث بتحليل blacklotus بشكل أفضل مما أستطيع. وكما قال أحدهم يومًا: «لا يمكنك الغش في تحليل البرمجيات الخبيثة، يمكنك فقط أن تجعل عملك أسهل». ما قاله الباحث هو أن هذه الدالة تتحقق أساسًا من ثوابت محددة تحدد اللغة المستخدمة على الكمبيوتر. في مقاله، يقدم رابطًا لهذا (https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/[MS-LCID].pdf) وهو مستند قياسي من مايكروسوفت يحتوي على كل معرّفات اللغة.
الآن باستخدام منطقنا الهاكوري المتميز، يمكننا استنتاج أن 0x26 غالبًا ما يُستخدم كإزاحة (offset)، لذا أي 0x26 من معرّفات اللغة التالية بعد 0x419، وهي

إذا فحصنا هذا المستند أيضًا، يمكننا أن نرى أن 0x818 يقابل

و0x819 يقابل

ونعرف من «التحقيقات»/التقارير السابقة أن هذه البرمجية الخبيثة لم تكن تعمل على أجهزة معينة من مناطق معينة في العالم، لذا يمكننا أن نستنتج أن هذه الدالة تتحقق لمعرفة منطقة الجهاز المصاب.
=============================================================================
مجنون حتى الآن يا صديقي، ما التالي؟ لدينا دالة some_more_syscall. حسنًا! ماذا لديك إذًا؟ ها هي

نريد المزيد! بالتأكيد يا صديقي!



هممم

إذًا تتحقق من وجود مصحح النواة kerneldebugger (https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm)(0x23)، تحقق تحقق!
إذًا ماذا؟! لدينا pcr (حفلة أكوام وتوليفات)

=============================================================================
الآن إذا فحصنا دالة iterate_over_modules() تبدو هكذا

من منظور «الكود الزائف» تبدو هكذا

من وجهة نظر مستقلة، يبدو أن لغة التجميع والكود الزائف لـ ida متطابقان، إذاً ما هو منطق هذه الدالة؟ حسنًا، بسيط جدًا، إنها تتكرر عبر الوحدات في الذاكرة (dll's) وتتحقق من قائمة تجزئات :) v4[0] = 0x1E7EACEF; v4[1] = 0x4468A620; v4[2] = 0x68536B95; v4[3] = 0x73EBBB53; v4[4] = 0xDA165168; v4[5] = 0xB24D33A7; v4[6] = 0xB1E2CEC6; v4[7] = 0x5136992; v4[8] = 0x98C500D9; v4[9] = 0x3E0169B6;
وإذا لم يتم العثور على أي dll في الذاكرة له نفس التجزئة، نعود بقيمة 0، وإلا نعود بقيمة 1 ونتسبب في تعطل المٌنقّح. وبناءً على هذا الاستنتاج، يمكننا القول إن هذه طريقة أخرى لمكافحة التحليل. صحيح، ولكن ماذا عن كل قيمة من قيم التجزئة؟ حسنًا، سأغش مجددًا (كما قال أحدهم، لا يمكنك الغش في تحليل البرمجيات الخبيثة، فقط تجعل حياتك أسهل :)). الباحث الآسيوي المذكور أعلاه كان لطيفًا بما يكفي لتزويدنا بقائمة القيم التي اشتُقت منها هذه القيم
sbiedll.dll dbghelp.dll api_log.dll dir_watch.dll pstorec.dll vmcheck.dll wpespy.dll cmdvrt64.dll avghookx.dll snxhk.dll
الآن لنتحقق ديناميكيًا مما إذا كانت أي من القيم تطابق أي dll مذكور

وبالتأكيد يطابق :)
لكن كيف توصلت إلى استنتاج أن هذه الخوارزميات تتحقق من هذه القيم؟ حسنًا، عندما قمت بمحاكاة جزء من هذه البرمجية الخبيثة، كان عليّ إعادة تنفيذ iterate_over_module_name_and_hash (في ملف solve_hash_syscalls.py) وفي هذه الدالة لدينا

حيث أن x (الوسيط المُمرر) في هذه الحالة هو v2 وهو مصفوفة (مؤشر) من القيم التي تزداد (أي يتقدم موضع المؤشر في المصفوفة) طالما أنها لا تطابق أيًا من القيم المذكورة أعلاه. يا رجل، هذا كلام صعب :P
رائع! التالي
=============================================================================
iterate_over_modules2 تقريبًا نفس القصة هنا

والكود الزائف

تقريبًا نفس القصة، فقط تجزئات مختلفة :)
v5[0] = 0x7D73878E; v5[1] = 0xEF36424B; v5[2] = 0xAF64BC2B; v5[3] = 0x1DBBC879; v5[4] = 0xAE6D1D56; v5[5] = 0x7B3242F2; v5[6] = 0x14D922B9; v5[7] = 0x4C92DF53;
والتي تقابل
sample.exe bot.exe sandbox.exe malware.exe test.exe klavme.exe myapp.exe testapp.exe
=============================================================================
iterate_over_modules3 نفس القصة هنا

والكود الزائف

نفس القصة، تجزئات مختلفة :)v4[0] = 0x42D12D59; v4[1] = 0xEC5D7AA; v4[2] = 0x861E460F; v4[3] = 0x84BCC8DB; v4[4] = 0x6474D72B; v4[5] = 0xB8B9C504; v4[6] = 0x69A0620E; v4[7] = 0x6017EE43; v4[8] = 0xE93BE2E0; v4[9] = 0x149EFC55; v4[10] = 0xE3FA84A4; v4[11] = 0x7CFDD7AF; v4[12] = 0x5B098C67; v4[13] = 0x2F1FB18E; v4[14] = 0xFE8F2B18;
والتي تقابل
prl_cc.exe prl_tools.exe qemu-ga.exe vmtoolsd.exe vmwaretray.exe vmwareuser.exe VGAuthService.exe vmacthlp.exe vboxservice.exe vboxtray.exe VMSrvc.exe VMUSrvc.exe xenservice.exe
=============================================================================
Anti_debug_measure_1 انتهى بي المطاف إلى إعادة تسميته إلى anti_debug_measure2_RtlAddVectoredExceptionHandler_int3. لماذا؟ سترى خلال دقيقة. إذاً يبدو هكذا

ومن منظور الكود الزائف يبدو هكذا

إذًا ما هذا بحق الجحيم؟ حسنًا، إنه في الأساس ينشئ معالج استثناء لـ __debugbreak(int 3) والذي سيُنفّذ الكود كلما تم إطلاق int3. انتهى بي الأمر بالبحث أكثر وصادفت هذا
(https://blog.lexfo.fr/dridex-malware.html) وهو مورد رائع يخبرنا أن هذا مجرد آلية لمكافحة التصحيح، وفي حالتنا هذه نكتفي بتشغيل هذه الدالة ونتجاهل sub_13F2820D0 الذي يتم تشغيله كلما نفّذنا int3 ونصحّح eax إلى 0 :) إذاً التنفيذ في الذاكرة يبدو هكذا :)
قبل التصحيح

بعد التصحيح

بعد ذلك تخرج من الدالة وتعدّل rax/eax إلى 0 أيضًا لتتجاوز تعليمة jne التي تؤدي إلى تحطيم المصحح

=============================================================================
Anti_debug_measure_2 والذي غيّرته لاحقًا إلى anti_debug_measure2_RtlAddVectoredExceptionHandler_int2


مرة أخرى، لا جديد تحت الشمس، نفس الشيء فقط ربط (hook) إنتربت/استدعاء نظام آخر، هذه المرة int2، نفس الحيلة للتجاوز وهي استخدام التصحيح الديناميكي لقيمة الإرجاع لتجاوزها :)
إذا بحثت في جوجل عن anti analysis 2dh ستظهر الكثير من النتائج، لذا نعم يمكنك استخدام ذلك كمرجع لمعرفة المزيد، لم أقضِ وقتًا طويلًا مع هذا :)
بالنسبة لهذه، حتى لو حاولت مثلاً الـ step over فسينتهي بك الأمر عند تعليمة ret كما هنا

ولتجاوز ذلك، ببساطة قم بالتنفيذ حتى العودة (return) وستكون بخير :)
=============================================================================
والآن يأتي دور anti_debug measure heap والذي أعدت تسميته لاحقًا إلى iterate_over_current_process_and_check_again_hases

ومن الميزات الرائعة لهذه الدالة أنها تستخدم ntquerysysteminformation داخل iterate_over_current_process_and_hash_check لسرد جميع العمليات الجارية. وهكذا تبدو iterate_over_current_process_and_hash_check


رائع جدًا، لكن كيف بحق الجحيم توصلت إلى استنتاج أن iterate_over_current_process_and_hash_check تفعل ما يوحي به اسمها؟ حسنًا، أولًا هناك استدعاء ntquerysysteminformation، وإذا بحثت في جوجل سترى أنه يُستخدم للحصول على قائمة بالعمليات الجارية، ومن ثم قمت ببساطة بتخمين مدروس بناءً على مقتطف الكود التالي LODWORD(v4) = RtlAllocateHeap(NtCurrentPeb()->ProcessHeap, 8u, v10); v3 = v4; v5 = ntquerysysteminformation(); v6 = v3; .... memcpy(v9, v6[8], *(v6 + 28)); v9[*(v6 + 28) >> 1] = 0; if ( some_hash_0x1003F(v9) == a1 ) أنها تنسخ قائمة العمليات وتتكرر على كل واحدة وتقارن كل تجزئة من المصفوفة السابقة مع أي عملية كانت تعمل. مرة أخرى، كل التقدير لمدونة أبحاث الآسيوي (asian) لأنني لا أعرف كيف بحق الجحيم توصّل إلى الاسم الفعلي لقيم مصفوفة v4. يُرجى مراجعة iterate_over_modules.py إذا أردت أن ترى كيف قمت بمحاكاة هذا.
ملاحظة: إذا قمت بتصحيح هذه الدالة ديناميكيًا فستصطدم بـ int 2d مرة أخرى، والحل هو نفس ما ذكرته أعلاه، فقط تقوم بالتنفيذ حتى العودة 0xf مرة، وهو ما يمشي عبر الـ hev، وبعد ذلك إذا أردت التأكد من أنك وصلت إلى العودة من iterate_over_current_process_and_check_again_hases ضع نقطة توقف (br) في نهاية هذه الدالة وستكون في أمان :)
============================================================================= anti_debug_measure_heap



لذا نعم، نحن محظوظون لأنها ليست كبيرة، والأكثر من ذلك أننا قمنا بالفعل بتطبيق demangle_strings. الآن أعدت تطبيق هذا للمصفوفات الأكبر، يرجى الذهاب إلى anti_debug_measure.py .
هذا يتحقق بشكل أساسي ضد``` \Registry\Machine\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters \Registry\Machine\SYSTEM\ControlSet001\Services\vioscsi \Registry\Machine\SYSTEM\ControlSet001\Services\VirtIO-FS Service \Registry\Machine\SYSTEM\ControlSet001\Services\VirtioSerial \Registry\Machine\SYSTEM\ControlSet001\Services\BALLOON \Registry\Machine\SYSTEM\ControlSet001\Services\BalloonService \Registry\Machine\SYSTEM\ControlSet001\Services\netkvm \Registry\Machine\SOFTWARE\VMware, Inc.\VMware Tools \Registry\Machine\HARDWARE\ACPI\DSDT\VBOX__ \Registry\Machine\HARDWARE\ACPI\FADT\VBOX__ \Registry\Machine\HARDWARE\ACPI\RSDT\VBOX__ \Registry\Machine\SOFTWARE\Oracle\VirtualBox Guest Additions \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxGuest \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxMouse \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxService \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxSF \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxVideo
الآن get_oem_key







أولاً يقوم بفك تشويش السلسلة إلى```
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
Identifier
SystemManufacturer
SystemBiosVersion
VMWARE
QEMU
VBOX
ثم يستعلم عن
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
ويقارن قيمها مع qemu وvbox وVMWARE كما يظهر في مقتطف IDA ونافذة x86 :)


كما يظهر في المقتطف الأول، فإنه يقارن vmware مع أي قيم كانت مخزنة في جهازي الافتراضي وقت التحليل :)
ليس بالأمر الكبير، فقط شغّل هذه الدالة حتى ret وغيّر eax عند العودة إلى 0 :) لتجاوز طريقة مكافحة التحليل هذه :)
=============================================================================
الآن get_oem_from_firmware





الآن شيء مثير للاهتمام، نرى أن هذه الدالة تبدأ بـ sub_13F267288() والتي يُمرر لها 0x52534D42 كمعامل. إذا بحثت عن هذه القيمة على جوجل ستجد الكثير من الأسئلة الرائعة في منتديات مختلفة مثل (https://ru.stackoverflow.com/questions/778618/c-%D0%9A%D0%B0%D0%BA-%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D1%82%D1%8C-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8E-%D0%BE%D0%B1-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0%D1%85-%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%B0-%D0%BD%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D1%8F-wmi) (https://msdn-whiteknight.github.io/answers/html/tools/html/ru.stackoverflow.com/posts/780170.html) (https://www.maldun.com/analysis/YXNkZmRzZmFkc2Y2NDEwNjlkc2Zhc2RmYXNkZg==/) أو هذا (https://github.com/digitalocean/go-smbios/blob/master/smbios/stream_windows.go) لكن الأكثر إثارة للاهتمام بعد قراءة هذا والبحث عن RSMB قد تصادف هذا https://evasions.checkpoint.com/techniques/firmware-tables.html والذي يوضح لنا أن هذه طريقة لمكافحة التحليل :) رائع، إذن ما الذي تفعله بحق السماء؟
أولاً يقوم بتفريغ جدول البرامج الثابتة SMBIOS، ثم يفك تشفير سلسلة نصية، أول سلسلة تكون qemu، ثم يستدعي sub_13F2655E0 مع المعاملات: السلسلة المفكوك تشفيرها وجدول البرامج الثابتة. من التحليل الثابت


بدقة، إذا كان (v4 != v5) توصلت إلى استنتاج أن هذا تنفيذ يشبه strcmp، فهو يتحقق مما في جدول البرامج الثابتة مقابل السلسلة المفكوك تشفيرها. كما يظهر في المُنقّح

r8 مؤشر إلى جدول البرامج الثابتة، والأكثر إثارة للاهتمام أننا نرى أن ... هراء هراء ... virtualbox هو الاسم الموجود في جدول البرامج الثابتة وrcx هو qemu، لذا يمكننا القول بأمان أن هذا تنفيذ يشبه strcmp. وبالتأكيد كما يظهر نحن آمنون :) بالنسبة لهذا الفحص

الآن تتكرر هذه العملية مع السلاسل النصية VirtualBox وvbox وVBOX وVMware :) بشكل عام، حل تجاوز فحص هذه الدالة هو تشغيلها حتى ret وتصحيح eax ومواصلة التحليل :)
============================================================================
رائع، الآن check_oem_key ()






إذن ما الذي تفعله بحق السماء؟ حسنًا، نفس الحيلة الموضحة سابقًا لكن هذه المرة مع جدول ACPI. ما الذي أعنيه هنا؟ من الأفضل قراءة هذه الشرائح الأربعة عشر (https://dc4420.org/slides/2015-11-24/acpi_vm_detect.pdf) فهي تشرح ذلك بشكل أفضل، لكنها نفس الحيلة الرخيصة :)) هذه المرة ضد BOCHS وBXPC وVMWARE


============================================================================
أريد أن أبدأ بالدالة anti_debug_processor_Timing() ثم أنتهي بـ check_for_flags(). إذن

هذا ما يبدو عليه. إذن ما الذي يفعله؟ يقرأ القيمة الحالية للطابع الزمني للمعالج، ثم يأخذ اسم المعالج (في حالتنا GenuineIntel)، ثم يطرح الطابع الزمني المسترجع من اسم المعالج، ثم يتحقق ببساطة إذا كانت النتيجة أكبر من 19999.
بعد rdtsc

بعد cpuid

كما يظهر، يتم تقسيم السلسلة إلى 3 مسجلات

وفي حالتنا نرى أننا "فشلنا" في هذا الفحص وضبط eax إلى 1

حل هذا الفحص المضاد هو ببساطة العودة من الدالة وتصحيح eax إلى 0 :)
============================================================================
الآن entry_to_peb()







من منظور شبه الكود



حتى فحص if لا يوجد شيء جديد، لقد رأينا هذا النوع من الخوارزميات مسبقًا، فما الأمر إذن؟ حسنًا، إذا ذهبت إلى التحليل المُشار إليه سابقًا للبحث الآسيوي، سترى أنه يقول إنه يتحقق مما إذا كان إصدار ويندوز أكبر من win7/server 2008 r2. لكن كيف توصل إلى هذه الفكرة؟ حسنًا، إذا قرأنا http://waleedassar.blogspot.com/2012/08/major-minorsubsystemversion.html فهو يقول

وأيضًا إذا قرأت هذا :)
وتطبّق ما هو مذكور هنا من أنه يتم تحويله تلقائيًا إلى بنية KUSER_SHARED_DATA، لكن هنا كان برنامج IDA لدي به خلل أثناء التحليل، فالأمر على ما هو عليه :)
حتى لا أُصيبك بالملل بتكرار نفس الخوارزمية تقريبًا، إليك السلاسل النهائية المستخرجة والمفكوك تشفيرها للدوال :) كانت هذه عملية شاقة لأنها تمت باستخدام مُنقّح :) كنت كسولًا جدًا لمحاكاة هذا``` user32.dll advapi32.dll Rpcrt4.dll bcrypt.dll ole32.dll Cabinet.dll
CreateWindowExW
ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy
DestroyWindow
CloseHandle
CreateProcessW
InitializeProcThreadAttributeList
UpdateProcThreadAttribute
LoadAppInitDlls
Sleep
GetExitCodeProcess
MoveFileExW
OpenSCManagerW
OpenServiceW
QueryServiceStatus
StartServiceW
CloseServiceHandle
GetUserNameW
ConvertSidToStringSidW
LookupAccountNameW
CreateWellKnownSid
LookupPrivilegeValueW
ConvertStringSecurityDescriptorToSecurityDescriptorW
RpcStringBindingComposeW
RpcBindingFromStringBindingW
RpcStringFreeW
RpcBindingSetOption
RpcBindingSetAuthInfoExW
RpcBindingFree
NdrClientCall2
NdrClientCall3
BCryptOpenAlgorithmProvider
BCryptSetProperty
BCryptGenerateSymmetricKey
BCryptDecrypt
BCryptDestroyKey
BCryptCloseAlgorithmProvider
BCryptGetProperty
BCryptGenRandom
CoCreateInstance
CoInitializeEx
CoUninitialize
CoInitializeSecurity
CoSetProxyBlanket
if >win7/server 2008 r2
{
CreateDecompressor
CloseDecompressor
Decompress
}
وبهذا نصل إلى نهاية النصف الأول من تحدي تحليل blacklotus.
============================================================================
أما بالنسبة للنصف الثاني
من منظور لغة التجميع (Assembly)

من منظور الكود الزائف (Pseudo-code)

سنبدأ التفكيك مع دالة some_hash()
============================================================================
من منظور الرسم البياني (Graph)

من منظور لغة التجميع (Assembly)



من منظور الكود الزائف (Pseudo-code)
