ربما يعرف الكثير من الأشخاص بالفعل نوعًا من الوحش هذا -
Ghidra ("Hydra") وما الذي يأكله البرنامج عن كثب ، على الرغم من أن هذه الأداة كانت متاحة للجمهور مؤخرًا فقط - في مارس من هذا العام. لن أزعج القراء بوصف Hydra ووظائفها وما إلى ذلك. أنا متأكد من أن الأشخاص الموجودين في هذا الموضوع قد درسوا كل هذا بالفعل ، والذين لم يطلعوا بعد على الموضوع - يمكنهم القيام بذلك في أي وقت ، حيث أصبح من السهل الآن العثور على معلومات مفصلة على الإنترنت. بالمناسبة ، تم بالفعل
تغطية أحد جوانب Hydra (تطوير المكونات الإضافية له) على Habré (مقالة ممتازة!) سأقدم فقط الروابط الرئيسية:
لذلك ، Hydra عبارة عن أداة
فك تجميع وتقطيع تفاعلية مجانية عبر النظام الأساسي مع بنية معيارية ، مع دعم تقريبًا لجميع أبنية وحدة المعالجة المركزية الرئيسية وواجهة رسومية مرنة للعمل مع التعليمات البرمجية المفككة ، والذاكرة ، والرمز المسترجع (decompiled) ، ورموز تصحيح الأخطاء ، وأكثر من ذلك بكثير .
دعونا نحاول كسر شيء مع هذا هيدرا!
الخطوة 1. البحث ودراسة الكراك
ك "ضحية" نجد برنامج "crackme" بسيط. لقد ذهبت للتو إلى
crackmes.one ، المشار إليه في البحث مستوى الصعوبة = 2-3 ("بسيط" و "متوسط") ، ولغة المصدر للبرنامج = "C / C ++" والنظام الأساسي = "Multiplatform" ، كما في لقطة الشاشة أدناه:

أسفر البحث عن 2 نتيجة (باللون الأخضر أدناه). تحولت الكراك الأول إلى 16 بت ولم تبدأ على Win10 64 بت ، ولكن الثانية (
level_2 بواسطة seveb ) ظهرت. يمكنك تنزيله من
هذا الرابط .
تحميل وتفريغ الكراك. كلمة مرور الأرشيف ، كما هو موضح في الموقع ، هي
crackmes.de . في الأرشيف ، نجد دليلين متوافقين مع نظامي Linux و Windows. على جهازي ، أذهب إلى دليل Windows
وألتقي فيه "القابل للتنفيذ" الوحيد -
level_2.exe . لنركض ونرى ما تريد:

يبدو وكأنه المشكله! عند بدء التشغيل ، لا يعرض البرنامج أي شيء. نحن نحاول تشغيلها مرة أخرى ، ونمررها بسلسلة تعسفية كمعلمة (فجأة ، هل تنتظر المفتاح؟) - ومرة أخرى لا شيء ... ولكن لا تيأس. لنفترض أنه يتعين علينا أيضًا اكتشاف معلمات الإطلاق كمهمة! حان الوقت للكشف عن "السكين السويسري" - هيدرا.
الخطوة 2. إنشاء مشروع في هيدرا والتحليل الأولي
افترض أن لديك بالفعل Hydra مثبتة. إن لم يكن بعد ، ثم كل شيء بسيط.
تثبيت غيدرا1) تثبيت
JDK الإصدار 11 أو أعلى (لدي
12 )
2) قم بتنزيل Hydra (على سبيل المثال ،
من هنا ) وتثبيته (في وقت كتابة هذا التقرير ، كان أحدث إصدار من Hydra هو 9.0.2 ، ولدي 9.0.1)
نطلق Hydra وفي مدير المشروع المفتوح يتم إنشاء مشروع جديد على الفور ؛ أعطيتها الاسم
crackme3 (بمعنى ، تم إنشاء مشاريع crackme و crackme2 بالفعل من أجلي). المشروع ، في الواقع ، دليل للملفات ، يمكنك إضافة أي ملفات إليه للدراسة (exe ، dll ، إلخ). سنضيف على الفور level_2.exe (
ملف | استيراد أو المفتاح
I فقط):

نرى أنه قبل الاستيراد ، حددت هيدرا الدجال التجريبي الخاص بنا باعتباره PE 32 بت (قابل للتنفيذ محمول) لنظامي التشغيل Win32 OS و x86. بعد الاستيراد ، لدينا انتظار لمزيد من المعلومات:

هنا ، بالإضافة إلى عمق البت المذكور أعلاه ، قد لا نزال مهتمين
بترتيب endianness ، والذي في حالتنا هو
القليل (من البايت المنخفض إلى العالي) ، والذي كان متوقعًا لمنصة Intel 86.
مع تحليل أولي ، لقد انتهينا.
الخطوة 3. إجراء التحليل التلقائي
حان الوقت لبدء التحليل التلقائي الكامل للبرنامج في هيدرا. يتم ذلك بالنقر المزدوج فوق الملف المقابل (level_2.exe). بفضل هيكلها المعياري ، توفر Hydra جميع وظائفها الأساسية بنظام مكون إضافي يمكن إضافته / تعطيله أو تطويره بشكل مستقل. نفس الشيء مع التحليل - كل مكون إضافي مسؤول عن نوع التحليل. لذلك ، أولاً ، نواجه هذه النافذة حيث يمكنك تحديد أنواع تحليل الاهتمام:
لأغراضنا ، من المنطقي ترك الإعدادات الافتراضية وتشغيل التحليل. يتم إجراء التحليل نفسه بسرعة كبيرة (استغرق الأمر مني حوالي 7 ثوانٍ) ، على الرغم من أن المستخدمين في المنتديات يشكون من أن Hydra تخسر في المشروعات الكبيرة بالنسبة للمشاريع الكبيرة. قد يكون هذا صحيحًا ، لكن بالنسبة إلى الملفات الصغيرة ، فإن هذا الاختلاف ليس مهمًا.
لذلك ، فإن التحليل كامل. يتم عرض نتائجها في نافذة متصفح كود:

هذه النافذة هي النافذة الرئيسية للعمل في هيدرا ، لذلك يجب عليك دراستها بعناية أكبر.
رمز متصفح واجهة نظرة عامةتقسم إعدادات الواجهة الافتراضية النافذة إلى ثلاثة أجزاء.
في
الجزء المركزي ، النافذة الرئيسية - قائمة من المفكك ، والتي تشبه إلى حد ما "إخوانها" في المؤسسة الدولية للتنمية ، OllyDbg ، إلخ. بشكل افتراضي ، تكون الأعمدة في هذه القائمة (من اليسار إلى اليمين): عنوان الذاكرة ، شفرة تشغيل الأمر ، أمر ASM ، معلمات أمر ASM ، مرجع تبادلي (إن أمكن). بطبيعة الحال ، يمكن تغيير العرض من خلال النقر على الزر في شكل جدار من الطوب في شريط الأدوات في هذه النافذة. بصراحة ، لم أر مثل هذا التكوين المرن لمخرج المفكك في أي مكان ، إنه مناسب للغاية.
في
الجزء الأيسر من لوحة 3:
- أقسام البرنامج (انقر على الماوس للتنقل خلال الأقسام)
- شجرة الشخصيات (الواردات ، الصادرات ، الوظائف ، الرؤوس ، إلخ.)
- اكتب شجرة المتغيرات المستخدمة
بالنسبة لنا ، فإن النافذة الأكثر فائدة هنا هي شجرة الرموز ، والتي تتيح لك العثور بسرعة ، على سبيل المثال ، على وظيفة باسمها والانتقال إلى العنوان المقابل.
على
الجانب الأيمن توجد قائمة برمز فك الشفرة (في حالتنا ، في C).
بالإضافة إلى النوافذ الافتراضية ، في قائمة
النافذة ، يمكنك اختيار ووضع العشرات من النوافذ الأخرى وعرضها في أي مكان في المتصفح. للراحة ، أضفت إطار بايت ونافذة مع رسم بياني دالة إلى الوسط ، وإلى اليمين ، متغيرات السلسلة (سلاسل) وجدول وظائف (وظائف). هذه النوافذ متاحة الآن في علامات تبويب منفصلة. وأيضًا ، يمكن فصل أي نوافذ وجعلها "عائمة" ، ووضعها وتغيير حجمها حسب تقديرك - وهذا أيضًا حل مدروس للغاية ، في رأيي.
الخطوة 4. تعلم خوارزمية البرنامج - main () وظيفة
حسنًا ، دعنا ننتقل إلى التحليل المباشر لبرامج الكراك لدينا. في معظم الحالات ، يجب أن تبدأ بالبحث عن نقطة دخول البرنامج ، أي الوظيفة الرئيسية التي يطلق عليها عندما تبدأ. مع العلم أن الكراك قد كتب في C / C ++ ، فإننا نعتقد أن اسم الوظيفة الرئيسية سيكون
الرئيسي () أو شيء من هذا القبيل :) يقال ويفعل. أدخل "الرئيسي" في مرشح شجرة الرموز (في اللوحة اليمنى) وانظر الوظيفة
_main () في قسم
الوظائف . انتقل إليها بنقرة ماوس.
نظرة عامة على الوظيفة الرئيسية () وإعادة تسمية الوظائف الغامضة
في قائمة disassembler ، يتم عرض قسم الكود المقابل على الفور ، وعلى اليمين نرى الكود C المعطل لهذه الوظيفة. تجدر الإشارة إلى ميزة واحدة أكثر ملاءمة لمزامنة اختيار Hydra: عندما يختار الماوس مجموعة من أوامر ASM ، يتم تمييز قسم الرمز المقابل في أداة فك الترميز والعكس. بالإضافة إلى ذلك ، إذا كانت نافذة عرض الذاكرة مفتوحة ، تتم مزامنة التخصيص مع الذاكرة. كما يقولون ، كل عبقري بسيط!
على الفور ، لاحظت ميزة مهمة للعمل في هيدرا (على عكس ، على سبيل المثال ، العمل في المؤسسة الدولية للتنمية).
يركز العمل في Hydra بشكل أساسي على تحليل الشفرة المضغوطة . لهذا السبب ، فإن مبدعي هيدرا (نتذكر - نحن نتحدث عن جواسيس من NSA :)) قد أولوا اهتمامًا كبيرًا بجودة فك التشفير وراحة التعامل مع الكود. على وجه الخصوص ، يمكن للمرء ببساطة الانتقال إلى تحديد الوظائف والمتغيرات وأقسام الذاكرة بمجرد النقر المزدوج في الشفرة. وأيضًا ، يمكن إعادة تسمية أي متغير ووظيفة على الفور ، وهو أمر مريح للغاية ، لأن الأسماء الافتراضية لا تحمل معنى ويمكن أن تكون مربكة. كما سترى لاحقًا ، سنستخدم هذه الآلية غالبًا.
لذلك ، هنا هي الوظيفة
الرئيسية () ، والتي "تشريح" هيدرا على النحو التالي:
القائمة الرئيسية ()int __cdecl _main(int _Argc,char **_Argv,char **_Env) { bool bVar1; int iVar2; char *_Dest; size_t sVar3; FILE *_File; char **ppcVar4; int local_18; ___main(); if (_Argc == 3) { bVar1 = false; _Dest = (char *)_text(0x100,1); local_18 = 0; while (local_18 < 3) { if (bVar1) { _text(_Dest,0,0x100); _text(_Dest,_Argv[local_18],0x100); break; } sVar3 = _text(_Argv[local_18]); if (((sVar3 == 2) && (((int)*_Argv[local_18] & 0x7fffffffU) == 0x2d)) && (((int)_Argv[local_18][1] & 0x7fffffffU) == 0x66)) { bVar1 = true; } local_18 = local_18 + 1; } if ((bVar1) && (*_Dest != 0)) { _File = _text(_Dest,"rb"); if (_File == (FILE *)0x0) { _text("Failed to open file"); return 1; } ppcVar4 = _construct_key(_File); if (ppcVar4 == (char **)0x0) { _text("Nope."); _free_key((void **)0x0); } else { _text("%s%s%s%s\n",*ppcVar4 + 0x10d,*ppcVar4 + 0x219,*ppcVar4 + 0x325,*ppcVar4 + 0x431); _free_key(ppcVar4); } _text(_File); } _text(_Dest); iVar2 = 0; } else { iVar2 = 1; } return iVar2; }
يبدو أن كل شيء يبدو عاديًا - تعريفات المتغيرات وأنواع C القياسية والظروف والحلقات ومكالمات الوظائف. لكن من خلال إلقاء نظرة فاحصة على الكود ، نلاحظ أنه لسبب ما لم يتم تعريف أسماء بعض الوظائف واستبدالها
بوظيفة pseudo-
_text () (في نافذة أداة فك
التشفير - .text () ). لنبدأ بتحديد هذه الوظائف.
النقر المزدوج على نص المكالمة الأولى
_Dest = (char *)_text(0x100,1);
نرى أن هذه مجرد وظيفة التفاف حول وظيفة
calloc () القياسية ، والتي تستخدم لتخصيص الذاكرة للبيانات. لذلك دعونا فقط إعادة تسمية هذه الوظيفة إلى
calloc2 () . اضبط المؤشر على رأس الوظيفة ، واتصل بقائمة السياق وحدد
إعادة تسمية وظيفة (مفتاح التشغيل
السريع -
L ) وأدخل اسمًا جديدًا في الحقل الذي يفتح:

نرى أنه تمت إعادة تسمية الوظيفة على الفور. نعود إلى الجسم
الرئيسي () (زر
الخلف في شريط الأدوات أو
Alt + <- ) ونرى أنه هنا بدلاً من الكلمة
المفتاحية _text () calloc2 () الغامضة بالفعل. ! ممتاز
نحن نفعل الشيء نفسه مع جميع وظائف المجمع الأخرى: نذهب إلى تعريفاتهم واحدة تلو الأخرى ، وننظر في ما يقومون به ، وإعادة تسميتهم (أضفت الفهرس 2 إلى الأسماء القياسية لوظائف C) ونعود إلى الوظيفة الرئيسية.
نحن نفهم رمز الوظيفة الرئيسي ()
حسنًا ، اكتشفنا بعض الوظائف الغريبة. نبدأ في دراسة رمز الوظيفة الرئيسية. تخطي تعريفات المتغيرات ، نرى أن الدالة تُرجع قيمة المتغير iVar2 ، وهو صفر (علامة على نجاح الوظيفة) فقط إذا تم استيفاء الشرط المحدد بواسطة السلسلة
if (_Argc == 3) { ... }
_Argc هو عدد معلمات سطر الأوامر (الوسائط) التي تم تمريرها إلى
main () . وهذا يعني أن برنامجنا "يأكل" وسيطات اثنين (الوسيطة الأولى ، كما نتذكر ، هي دائمًا الطريق إلى الملف القابل للتنفيذ).
حسنا ، دعنا ننتقل. هنا نقوم بإنشاء سلسلة C (صفيف
char ) من 256 حرفًا:
char *_Dest; _Dest = (char *)calloc2(0x100,1);
التالي لدينا حلقة من 3 التكرار. في ذلك ، نتحقق أولاً من
تحديد علامة
bVar1 ، وإذا كان الأمر كذلك ، انسخ وسيطة سطر الأوامر التالية (السلسلة) إلى
_Dest :
while (i < 3) { if (bVar1) { memset2(_Dest,0,0x100); strncpy2(_Dest,_Argv[i],0x100); break; } ... }
يتم تعيين هذه العلامة عند تحليل الوسيطة التالية:
n_strlen = strlen2(_Argv[i]); if (((n_strlen == 2) && (((int)*_Argv[i] & 0x7fffffffU) == 0x2d)) && (((int)_Argv[i][1] & 0x7fffffffU) == 0x66)) { bVar1 = true; }
يحسب السطر الأول طول هذه الوسيطة. علاوة على ذلك ، يتحقق الشرط من أن طول الوسيطة يجب أن يكون 2 والحرف قبل الأخير == "-" والحرف الأخير == "f". لاحظ كيف يقوم "decompiler" بترجمة استخراج الأحرف من السلسلة باستخدام قناع البايت.
يمكن تجسس القيم العشرية للأرقام ، وفي نفس الوقت أحرف ASCII المقابلة ، عن طريق الضغط على المؤشر فوق الحرف السداسي العشري المقابل. لا يعمل تعيين ASCII دائمًا (؟) ، لذلك أوصي بالنظر في جدول ASCII على الإنترنت. يمكنك أيضًا مباشرة في Hydra تحويل الأرقام القياسية من أي نظام أرقام إلى أي نظام آخر (عبر قائمة السياق -> تحويل ) ، في هذه الحالة سيتم عرض هذا الرقم في كل مكان في نظام الأرقام المحدد (في أداة فك الشفرة وفي أداة فك الشفرة) ؛ ولكن شخصيا ، أنا أفضل أن أترك الهيكس في الكود من أجل الانسجام في العمل ، لأنه عناوين الذاكرة ، الإزاحة ، إلخ. يتم تعيين hexes في كل مكان.
بعد الحلقة يأتي هذا الرمز:
if ((bVar1) && (*_Dest != 0)) { _File = fopen2(_Dest,"rb"); if (_File == (FILE *)0x0) { perror2("Failed to open file"); return 1; } ... }
أنا هنا على الفور وأضاف التعليقات. نحن نتحقق من صحة الوسائط ("-f path_to_file") ونفتح الملف المقابل (تم تمرير الوسيطة الثانية ، والتي قمنا بنسخها إلى _Dest). سيتم قراءة الملف بالتنسيق الثنائي ، كما هو موضح بواسطة المعلمة "rb" للدالة
fopen () . إذا فشلت القراءة (على سبيل المثال ، الملف غير متوفر) ، يتم عرض رسالة خطأ في دفق stderror وينتهي البرنامج بالكود 1.
التالي هو الأكثر إثارة للاهتمام:
ppcVar3 = _construct_key(_File); if (ppcVar3 == (char **)0x0) { puts2("Nope."); _free_key((void **)0x0); } else { printf2("%s%s%s%s\n",*ppcVar3 + 0x10d,*ppcVar3 + 0x219,*ppcVar3 + 0x325,*ppcVar3 + 0x431); _free_key(ppcVar3); } fclose2(_File);
يتم تمرير واصف الملف المفتوح (
_File ) إلى الدالة
_construct_key () ، والتي من الواضح أنها تقوم بالتحقق من المفتاح المطلوب. هذه الدالة تقوم بإرجاع صفيف بايت ثنائي الأبعاد (
char ** ) ، والذي يتم تخزينه في متغير
ppcVar3 . إذا كانت المصفوفة فارغة ، فسيتم عرض "Nope" الموجزة على وحدة التحكم (أي ، في رأينا ، "Nope!") ويتم تحرير الذاكرة. بخلاف ذلك (إذا لم تكن المصفوفة فارغة) ، يتم عرض المفتاح الصحيح ظاهرًا كما يتم تحرير الذاكرة. في نهاية الوظيفة ، يتم إغلاق واصف الملف ، ويتم تحرير الذاكرة ،
ويتم إرجاع قيمة
iVar2 .
لذلك ، أدركنا الآن أننا بحاجة:
1) إنشاء ملف ثنائي مع المفتاح الصحيح ؛
2) اجتياز طريقها في الكراك بعد الحجة "-f"في
الجزء الثاني من المقالة ، سنقوم بتحليل الوظيفة
_construct_key () ، والتي ، كما اكتشفنا ، مسؤولة عن التحقق من المفتاح المطلوب في الملف.