به نام خدا
با سلام خدمت دوستان.
خب فرصتی پیش اومد که بتونم مرحله چهارم مسابقه رو براتون حل کنم و توضیح بدم. من قول داده بودم هفته ای دوتا چالش رو بزارم ولی خب متاسفانه با توجه به شرایط کاری و کمبود وقت و با توجه به اینکه پیچیدگی مراحل داره بیشتر میشه، نشد این هفته دوتا مرحله رو حل کنم براتون. ولی خب امیدوارم همین جوری هفته ای یکی دوتا رو بتونم بزارم.
خب پس از عبور از مراحل 1 تا 3 رسیدیم به چالش شماره 4. این مسابقه واقعا هوشمندانه و هدفمند طراحی شده در کل. به اینصورت که از مراحل آسون شروع میشه و به مراحل خیلی سخت میرسه. ما تو 3 مرحله قبلی نحوه reverse کردن فایلهای باینری ویندوزی و اندرویدی رو یاد گرفتیم و الان توی این چالش میریم سراغ تحلیل فایلهای اجرایی لینوکسی. قشنگ مشخصه که این چالش به صورت هدفمند تلاش کرده که یه جورایی تمام حالات مهندسی معکوس رو پیاده کنه.
خب توی این مرحله ما قراره آنالیز فایلهای باینری لینوکسی رو یاد بگیریم و یه کم هم قراره ترافیک شبکه رو آنالیز کنیم. قطعا بدافزارهای زیادی ممکنه بشناسید که تحت شبکه اطلاعاتشون رو دریافت و ارسال میکنند. توی این چالش دقیقا ما با یه همچین حالتی مواجه میشیم و باید ترافیک شبکه رو هم آنالیز کنیم که خب البته ما با یه بدافزار اینجا رو به رو نیستیم ولی خب من سعی میکنم که نکاتی که لازمه رو توضیح بدم. در ادامه ما یه مقدار کار با نرم افزار IDAPro رو یاد میگیریم و اینکه چه جوری با IDA میتونیم یه فایل باینری رو آنالیز کنیم. یه مقدار هم کار با دیباگر لینوکسی gdb رو یاد میگیریم و خب کلا توی این مرحله خیلی نسبت به مراحل قبل جزییات رو بررسی میکنیم.
چالش شماره 4 : Dnschess
فایلهای مربوط به این چالش رو میتونید از اینجا دانلود کنید.
پیش نیازها:
- یه لینوکس Ubuntu x64 یا هر لینوکس دیگه ای که دوست دارید ولی به شرط اینکه، گرافیک داشته باشه و 64 بیتی باشه حتما.
- ابزار IDA Pro
- آشنایی با زبان اسمبلی و پایتون
- دیباگر gdb که خب به صورت پیش فرض توی اکثر لینوکسها موجوده
- ابزار wireshark یا tcpdump
- پایتون 2.7 یا بالاتر
خب شما یک فایل زیپ دارید که داخلش چهار تا فایل هست. در ابتدا وقتی فایل Message رو باز میکنیم به ما گفته شده که «ترافیک مشکوکی توی شبکه مشاهده شده و ما فهمیدیم که این ترافیک رو این بازی شطرنج که توی یه سیستم عامل اوبونتو اجرا میشه، داره تولید میکنه. ممکنه کار هکرها باشه. با حرکات درست سعی کنید این رو حل کنید».
خب از این پیام میفهمیم که ما با یه بازی شطرنج رو به رو هستیم. که خب وقتی هم گفته توی سیستم عامل اوبونتو میفهمیم که فایل ما لینوکسیه.
ما سه تا فایل دیگه هم داریم که دونه دونه میخوایم ببینیم از چه جنسی هستن.
در ابتدا یه فایل داریم به نام capture.pcap ، این فایل از پسوندش مشخصه که از جنس فایلهای ترافیک شبکه هست که دامپ گرفته شده. ببینید شما میتونید ترافیکی که داره توی یک شبکه رد میشه رو با ابزارهای مختلف از جمله wireshark ، شنود کنید و این ترافیک رو توی یه فایل با فرمت pcap دخیره کنید. پس ما الان متوجه شدیم که این فایل همون ترافیکیه که توی فایل message در موردش صحبت کرده.
خب دوتا فایل دیگه هم داریم یکی به اسم ChessUI و یکی هم به اسم ChessAI.so
اگه لینوکس کار کرده باشید تو نگاه اول متوجه میشید که این فایل با پسوند .so ، یه فایل کتابخونه لینوکسیه. ما توی ویندوز یه سری فایلها داریم که داخلشون توابع اماده ای هستن که کار رو برای برنامه نویس راحت میکنن و باعث میشن که کد کمتری زده بشه که به این فایلها میگیم dll. حالا دقیقا همین مفهوم رو هم توی لینوکس داریم که البته توی لینوکس بهشون میگیم فایلهای so یا shared object. کارکرد این فایلها دقیقا مثل همون فایلهای dll هست توی ویندوز.
اما فایل دوم که خب بدون پسوند هست، قطعا باید همون فایلی باشه که توی توضیحات گفته شده به ما. همون بازی شطرنج. که خب از اون UI آخرش مشخصه که این فایل احتمالا یه ui داره. البته در مورد نحوه تشخیص فایلها، راه بهتری هست که من در ادامه میگم. ولی الان خواستم بگم که هر کدوم از این فایلها چی هستند.
خب پس الان هدف اصلی ما این دوتا فایل باینری لینوکسی هستند که یه بازی شطرنج رو به ما نشون میده و ما باید ببینیم چه جوری باید این مرحله رو رد کنیم.
خب من الان سیستم عاملی که خودم باهاش کار میکنم، یه لینوکس Debian هست که تمام ابزارهایی که نیازه رو روش نصب کردم از قبل اما شما اگه میخواین لینوکس داشته باشید میتونید روی ماشین مجازی نصب کنید البته دقت کنید نسخه 64 بیتی و اینکه اگر Ubuntu نصب میکنید حتما نسخه جدید نصب کنید.
خب بیایم یه کم با فایلایی که داریم بازی کنیم ببینیم چی هستند و اصن ماهیت این فایلها چی هست.
توی لینوکس یه ابزار قدرتمندی داریم که میتونه برای ما کار file type detection رو خیلی سریع و با دقت بالایی انجام بده و اونم ابزاریه به نام file .
این ابزار، تقریبا با درصد بالایی تمام فرمت های فایلارو شناسایی میکنه و به شما میگه جنس فایلتون چیه، اعم از ویندوز، لینوکس، مک و …
این ابزار به صورت پیش فرض توی تمام لینوکسها نصبه. حالا اینجا میخوام بگم که اگه یه فایل رو نمیدونستیم جنسش چیه، و فرمتش چیه، چجوری با این ابزار تشخیصش بدیم. خب خیلی راحت یه ترمینال توی لینوکستون باز کنید و دستور زیر رو بزنید.
خب میبینید که دستور فایل رو زدیم و بهش گفتیم که فایل ChessUI رو به ما بگو چیه. همونطور که میبینید، اومده و گفته که این فایل از نوع ELF64 هست و بعد هم یه سری توضیحات اضافه به ما داده که گفته که این فایل executable هم هست. خب elf به فایلهای اجرایی لینوکسی میگن. یعنی جنس فایلهای لینوکسی از نوع elf هست که مخفف executable and linkable format ئه. فایلهای اجرایی ویندوزی، PE هستند که مخفف Portable Executable هست. خب اینجا گفته که این فایل اجرایی 64 بیتی هم هست. پس ما فهمیدیم که با یه فایل اجرایی لینوکسی مواجه هستیم. در ادامه همین کارو برای فایل ChessAI.so هم میکنیم.
خب همونطور که توی عکس میبینید این فایل ChessAI.so رو همون چیزی که فکرشو میکردیم تشخیص داده، و نوشته برامون که این فایل یه sharedobject هست.
خب بریم یه دور این فایل ChessUI که فایل اصلی هست رو اجرا کنیم ببینیم چیه اصن. خب توی لینوکس دسترسی اجرای یک فایل به صورت پیشفرض بسته ست و شما باید اول بهش دسترسی اجرا بدید و بعد اجراش کنید، که خب توی عکس زیر میبینید که من چه جوری فایل رو اجرا کردم و همونطور که میبینید یه صفحه شطرنج باز شده برامون. طبق چیزی که فایل Message گفته بود، همه چی درسته.
خب حالا ما باید طبق چیزی که فایل Message گفته، با حرکات درست، این بازی رو برنده بشیم تا رمز عبور مرحله بعد به ما نشون داده بشه.
خب یعنی حالا ما باید شطرنج بازی کنیم؟ مگه اومدیم مسابقات شطرنج؟ خب بیاین همینجوری شروع کنیم یه بازی بکنیم ببینیم چه جوریه:
خب ببینید من با اولین حرکتی که انجام دادم به من گفت که GameOver . من حرکت اشتباهی هم نرفتم. طبق قوانین شطرنج بازی کردم ولی نمیدونم چرا خطا میده. خب ما مجبوریم بازی رو دوباره شروع کنیم یه حرکت دیگه بزنیم ببینیم چیه قضیه.
فقط به این رشته هایی که بالا با فلش قرمز مشخص کردم دقت کنید که بعدا اینارو باز هم خواهیم دید توی کد.
خب همونطور که میبینید من با مهره شاه خودم رفتم شاه اونو زدم 😀 ولی بازم میگه GameOver . خب حالا میفهمیم که این یه بازی شطرنج عادی نیست و حتما یه قلق خاصی داره که باید بزنیم.
خب من میخوام ببینیم اصن این فایل کتابخونه ای که به اسم ChessAI.so داریم، واقعا به چه کاری میاد. و اینکه آیا اصن این بازی از این کتابخونه استفاده میکنه یا نه. خب راحت ترین کار اینه که اسمشو عوض کنیم و بعد دوباره شطرنجو اجرا کنیم، اگه خطای اجرا داد، یعنی به اون فایل نیاز داره. این کارو میخوایم بکنیم ببینیم اصن اینا با هم ارتباطی دارن یا نه. توی تحلیل بدافزار شما ممکنه کنار یه فایل اجرایی چندین فایل کتابخونه ای هم داشته باشید و برا اینکه بفهمید بدافزار از کدومش داره استفاده میکنه، میتونید با این کار بفهمید.
خب همونطور که میبینید من اسم کتابخونه رو یه 1 به تهش اضافه کردم و وقتی اجرا کردم میبینید که پیغام میده و میگه که من این کتابخونه رو پیدا نمیکنم.
خب پس متوجه شدیم که این فایل کتابخونه نیازه و این شطرنج داره ازش استفاده میکنه. خب بریم ببینیم باید چیکار کنیم.
فراموش کردیم که یه فایل دیگه هم توی این مرحله به ما داده شده و اونم فایل Capture.pcap هست که ترافیک شبکه توش هست. بریم ببینیم این فایل چه ترافیکی رو به ما نشون میده.
برا این کار من از wireshark که روی لینوکسم نصبه استفاده میکنم. حتما نیاز نیست این فایل رو روی لینوکستون باز کنید. اگه wireshark رو روی ویندوز هم دارید میتونید این فایل رو روی ویندوز باز کنید و ترافیک رو ببینید.
خب وقتی باز میکنیم فایل رو روی wireshark ، همه چی بر ملا میشه. البته نه همه چیز ولی تقریبا میفهمیم که این بازی چه جور کار میکنه.
خب توی عکس مشخصه که کلا تمام ترافیکی که این بازی تولید کرده، روی پروتکل DNS بوده که وایرشارک به ما نشون داده اینو.
خب پروتکل DNS چیه؟ DNS یه پروتکل هست برای تبدیل اسم به IP . مثلا فرض کنید شما میخواین از مرورگرتون وصل بشید به سایت گوگل. شما تایپ میکنید google.com ولی مرورگر شما اصلا این اسم رو نمیفهمه، به خاطر همین مرورگر باید اول IP سایت گوگل رو چک کنه که بتونه درخواست بده به اون IP. تو این مرحله مرورگر شما میاد و به سرور DNS ی که توی شبکه شما وجود داره درخواست میفرسته و میگه آقای DNS ، به من بگو IP سایت google.com چیه؟ و بعد DNS به اون جواب میده که IP مورد نظر شما فلانه. و بعد مرورگر شما میاد و از اون IP استفاده میکنه برای ارتباط با گوگل. خب اینو بهش میگن پروتکل DNS .
خب حالا ببینید درخواست شماره 1 رو توی عکس که با فلش قرمز مشخص کردم: اینجا سیستمی که بازی شطرنج روش اجرا بوده ترافیک رو در غالب پروتکل DNS ارسال کرده و اسم اون سایتی که توی درخواست ارسال کرده، ترکیبی از اون حرکت مهره ای هست که روی صفحه شطرنج جا به جا شده.
Rook-c3-c6.game-of-thrones.flare-on.com
بازی این رو به عنوان یه آدرس فرستاده به سمت DNS سرور. که خب این خیلی واضحه که چی هست. گفته که مهره rook که همون قلعه هست، از خونه شماره c3 رفته به خونه شماره c6 و بعدش هم یه اسم الکی گذاشته که البته اسم سریال game of thrones هست و ارسال کرده. این درخواست رو سیستمی داده که بازی روش اجرا شده. و از اون طرف سیستمی که DNS سرور بوده توی پکت شماره 2 که با فلش آبی مشخص کردم بهش جواب داده و گفته این سایتی که میخوای، IPش 127.150.96.223 هست. و در ادامه میبینید که همینجور برای حرکت های مختلف یه درخواست فرستاده شده.
اگه با آنالیز بدافزار آشنا باشید متوجه میشید که اینجا چه خبره. حالا من یه توضیحی در این مورد بدم:
بدافزارهایی که میخوان اطلاعاتی که از سیستم هدف سرقت میکنن رو به بیرون از شبکه بفرستن میان و خب ترافیک رو ارسال میکنن از طریق شبکه. ولی بعضی وقتها هست که بدافزار ها برای اینکه به راحتی شناسایی نشن، میان و این اطلاعات رو به یه روش خاص ارسال میکنن توی شبکه که به راحتی کسی نتونه توی شبکه ترافیک اونارو شناسایی کنه. مثلا الان دیدید که این بازی داره اطلاعات رو در غالب پروتکل DNS میفرسته به سمت بیرون که خب اگه کسی ببینه زیاد بهش شک نمیکنه چونکه همه فکر میکنن اگه بدافزار قرار باشه اطلاعاتی بفرسته بیرون در غالب پکت های عادی میفرسته. خب این از این. اینجا من حدس زدم که ممکنه بازی، حرکات رو در غالب ترافیک شبکه ارسال کنه. بیایم برا اینکه مطمعن بشیم یه بار بازی رو اجرا کنیم و شبکه خودمون رو با وایرشارک شنود کنیم ببینیم آیا چیزی ارسال میشه یا نه. اول از همه برا راحتی کار، اتصالتون به اینترنت رو قطع کنید و وایرشارک رو اجرا کنید و دکمه capture رو بزنید. نکته ای بگم اگه توی لینوکس از وایرشارک استفاده میکنید حتما باید وایرشارک رو با دسترسی root اجرا کنید که بتونه شبکه رو capture کنه.
شما وقتی از اینترنت قطع هستید به صورت پیش فرض، روی سیستمتون DNS سروری وجود نداره. برا اینکه بتونیم درخواست های DNS ی که بازی میفرسته رو بتونیم بگیریم، میتونیم توی تنظیمات شبکه DNS سرور رو همون IP localhost بذاریم. برا این کار این فایل رو /etc/resolv.conf باز کنید ، حالا با ترمینال یا با هرچیزی، و این آدرس رو توش اضافه کنید: nameserver 127.0.0.1 مثل عکس زیر و بعدش فایل رو ذخیره کنید. باید فایل رو با دسترسی روت تغییر بدید.
خب حالا وایرشارک رو استارت میکنیم و بعد هم بازی رو اجرا میکنیم و یه مهره ای رو حرکت میدیم. همونطور که میبینید من توی عکس سرباز رو از خونه e2 بردم به خونه e4 و خب میبینید که دقیقا چه آدرسی ارسال شده به DNS. ولی خب جوابی براش نیومده، چونکه ما dns سرور نداریم الان و خب توی پاسخ میبینید که گفته port unreachable . خب شاید به همین خاطره که وقتی ما حرکتی رو انجام میدیم بازی GameOver میشه. چونکه شاید به این دلیله که پاسخی از سمت DNS نمیگیره بازی. خب اگه اینجور باشه، ما باید برا تمام حرکات بازی که انجام میدیم توی DNS سرورمون یه IP بذاریم.
خب حالا بزارید بریم ببینیم اصن این فایلا چه کدی دارن.
اول از همه باید طبق اصول، آنالیز استاتیک رو شروع کنیم. برای آنالیز استاتیک من از ابزار IDAPro استفاده میکنم و البته پلاگین HexRay DEcompiler رو هم من دارم که خب پولیه ولی شما میتونید نسخه کرک شده رو هم پیدا کنید. البته اینو بگم که آیدا یه نسخه مجانی هم داره ولی امکاناتش خیلی کمه و اینکه نسخه کرک شدش برای لینوکس موجود نیست ولی شما میتونید نسخه ویندوزی رو با ابزار wine روی لینوکستون اجرا کنید. اما ابزارهای دیگه ای هم هست که دقیقا مثه آیدا کار میکنن و مجانی هستن مثل ابزار Ghidra که خب میتونید دانلودش کنید و استفاده کنید.
خب من طبق اسامی این فایل ها حدس میزنم که تمام فعالیت های این بازی شطرنج توی اون فایل کتابخونه هست. چرا چونکه اگه به اسماشون دقت کنیم، اسم یکیشون ChessUI هست که مشخص میکنه این یه فایل احتمالا فقط UI برنامه هست و اسم اون کتابخونه هم ChessAI هست که این AI مشخص میکنه که این کتابخونه احتمالا کار هوش مصنوعی رو برای این بازی انجام میده.
خب اول بریم سراغ خود فایل اصلی که همون ChessUI هست. من اینجا تا جایی که بشه نکات انالیز ایستا رو میگم ولی شما میتونید آنالیز ایستا رو با مطالعه منابع مختلفی که توی اینترنت هست یاد بگیرید. خب این فایلها همونطور که دیدید توی عکسای قبلی، 64 بیتی هستن، پس من باید از آیدا 64 استفاده کنم برای آنالیز.
من فایل ChessUI رو وقتی توی آیدا باز کنم اول میرم سراغ string هاش ببینم چیا داره توی string هاش و ببینم چیزی ازش در میاد یا نه. خب فایل رو وقتی باز میکنم توی آیدا و میرم توی پنجره Strings ، یه سری رشته میبینیم که توشون gtk نوشته شده. Gtk همون کتابخونه های گرافیکی مربوط به لینوکس هست که خب اینجا ما متوجه میشیم از توابع گرافیکی gtk داره استفاده میشه.
اما یه کم که بریم پایین تر به یه سری رشته قابل توجه میبینیم.
خب ببینید من یه dlopen و dlsym میبینم که اینا توجه جلب کن هستن. چرا؟؟ ببینید توی لینوکس وقتی شما بخواین یه کتابخونه رو استفاده کنید، باید ابتدا با تابع dlopen اون کتابخونه رو باز کنید. یعنی اسم فایل کتابخونه رو بدید به این تابع و بعد یه هندل ازش بگیرید و بعد هم اسم تابع مورد نظرتون رو که توی اون کتابخونه هست، با استفاده از dlsym یه هندل ازش بگیرید و اونوقت میتونید اون تابع رو توی برنامه صدا بزنید. خب من اینا رو که میبینم باید بفهمم که این برنامه داره چه کتابخونه ای رو صدا میزنه و اینکه چه تابعی رو از اون کتابخونه فراخوانی میکنه. از اون طرف دارم اسم فایل ChessAI.so رو هم میبینیم که با یه ./ اینجا برا ما لیست شده. من اینجا میتونم به احتمال قوی بگم که dlopen داره این کتابخونه رو استفاده میکنه داخل برنامه که خب قبلا هم اینو فهمیده بودیم ولی خب الان میتونیم بفهمیم که دقیقا کجا این کتابخونه فراخوانی میشه. خب رشته آخری که با فلش مشخص کردم یه رشته ای هست که نوشته GameOver You Won. خب اینجا من میتونم این حدس رو بزنم که این رشته زمانی که ما بازی رو برنده میشیم نمایش داده میشه. خب پس اونجایی که این رشته توی کد استفاده شده حتما یه خبرایی هست و ما میتونیم بفهمیم که در چه صورتی این رشته نشون داده میشه. خب بریم ببینیم این رشته کجا استفاده میشه. برا این کار آیدا خیلی راحت میتونه به ما با قابلیت xref که یکی از خفن ترین تکنیک های نرم افزار IDAPro هست، کمک کنه. اول روی این رشته دابل کلیک کنید، بعد خود آیدا شما رو میبره توی قسمت کد مربوط به برنامه و اونجایی که این رشته initialize شده رو به شما نشون میده. که خب اون قسمت data هست. اینجا واقعا حوصله توضیح دادن در مورد section های مختلف یه فایل باینری رو ندارم ولی شما حتما باید این چیزا رو بدونید و با section های مختلف یه فایل باینری آشنا بشید که خب منابع براش زیاد هست و میتونید این ویکی رو بخونید.
خب همونطور که توی عکس میبینید الان من روی این رشته کلیک کردم. البته خود آیدا میاد و اسم این متغیر ها رو به همون اسم رشته ای که داخلشون هست تغییر میده که فهم کد راحت تر بشه. خب حالا من فهمیدم که این رشته توی کد توی یه متغیر ذخیره شده. حالا میخوام ببینم که این رشته یا این متغیر تو چه جاهایی از کد ازش استفاده میشه. اینجاس که قابلیت xref آیدا به ما کمک میکنه. برا اینکه بفهمیم، روی این متغیر یا این رشته کلیک میکنیم و دکمه x رو میزنیم. آیدا سریعا برامون یه پنجره باز میکنه که تمام جاهایی که به این قسمت refrence دادن رو نشون میده.
خب همونطور که میبینید فقط یه جا از این رشته استفاده شده. روی اون کلیک کنید تا آیدا شما رو ببره به همون قسمت کد مربوط تا ببینیم این رشته در چه زمانی استفاده میشه و دقیقا چه اتفاقی میافته که این رشته چاپ میشه. خب وقتی میریم داخل اون تکه کد، میبینیم که اینجا ما یه jumpTable داریم. این یعنی چی؟ ببینید شما زمانی که توی کد برنامتون از دستور switchCase استفاده میکنید، وقتی اون کد تبدیل میشه به اسمبلی، کامپایلر میاد و به ازای هر case که شما داری، یه jump به یه آدرس میذاره. به این میگن jumpTable .خب اینجا میخوام شما رو با یکی دیگه از قابلیت های خوب آیدا آشنا کنم که درک کد رو براتون راحت تر میکنه و اونم قابلیت گراف هست. آیدا میتونه برا شما روال اجرای یه تابع رو به صورت گراف رسم کنه. برا این کار تو همین جایی که هستیم الان دکمه space رو بزنید تا به GraphView منتقل بشید.
خب ببینید الان اینجا ما یه گراف از نحوه عملکرد تابع داریم که چه جوری این تابع کار میکنه. حالا میخوایم ببینیم که این گراف رو چه جوری بخونیم و درکش کنیم. ببینید هر تابع توی روال اجراش ممکنه با چندین شرط مواجه بشه و هر کدوم از این شرطا، روال اجرا رو به یه قسمت دیگه از تابع منتقل کنه. پس هر تیکه از این گراف یا همون Node ها، در حقیقت یه جایی از داخل تابع هستن، نه بیرون از تابع. که خب بسته به اون شرط تابع وارد این قسمت ها میشه. این شرط ها همشون با دستورات jump پیاده سازی میشن. آیدا برا اینکه کار رو برا ما راحت تر کنه اومده و این jump ها رو به سه دسته تقسیم کرده.
یه سریا رو شما میبینید که فلش آبی رنگ هستن، اینا در اصل همون پرش های بدون شرط یا jump هستن که با دستور jmp توی اسمبلی وجود دارن. یه سریا با رنگ قرمز هستن و این به این معنی هست که اگه این شرط برقرار نشه مسیر اجرای تابع به سمت این فلش قرمز میره و یه سری فلش سبز هم توی گراف شما دارید که در اصل زمانی اون فلش رو رسم میکنه که تابع شرطش برقرار میشه. اون فلش قرمزا رو که خودم کشیدم با فلشای گراف اشتباه نگیرید.
پس ما فهمیدیم چه جور یه گراف رو توی آیدا بخونیم. اگه خواستید آیدا رو بخورید و کامل بهش مسلط بشید بهتون توصیه میکنم این کتاب رو تا تهش بخونید. چون من بخوام تیکه تیکه اینجا آیدا رو بگم، خودش میشه 100 تا پست که باید ریز به ریز آیدا رو براتون بگم.
خب حالا من یه نکته رو یادآوری کنم، همونجور که توی عکس مشخص کردم، اون مستطیل سمت چپی، میبینید که این رشته GameOver You won اینجا استفاده میشه. خب حالا ما میخوایم بفهمیم که برنامه چه روالی رو طی میکنه که به اینجا میرسه. ببینید الان گفتم که تمام این نقاط گراف همه چیزای داخل یه تابع هستن، پس حالا من باید بفهمم که این تابعی که این رشته توش استفاده شده، کجا داره فراخوانی میشه. این رشته تو چه تابعی استفاده شده؟
خب به اون اول گراف نگاه کنید، با فلش قرمز مشخص کردم. اسم تابعی که این رشته توش استفاده شده sub_4290 هست که خب آیدا به صورت پیش فرض اسامی توابع رو sub میزاره به همون معنی subroutine . خب حالا ما فهمیدیم رشته you won کجاس و تو چه تابعی استفاده میشه. حالا باید بفهمیم که این تابع رو کی و کجا صدا میزنن تا بریم ببینیم در چه صورتی ما میرسیم به رشته you won .
خب بزارید اینجا از DEcompiler آیدا استفاده کنیم تا متوجه بشید که به چه دردی میخوره. اگه شما Decompiler HexRay رو دارید، میتونید با زدن دکمه f5 توی وسط یه تابع یا توی گراف، اون کد رو Decompile کنید. خب الان من توی همین محیط گراف f5 رو میزنم و شما میبینید که آیدا مارو میبره به پنجره pseudocode و خب میبینید که یه شبه کد تمیز C به ما داره نشون میده.
خب ببینید الان این jumpTable رو آیدا تبدیل کرد به این شبه کد C که راحت مشخص شده که این کد طبق همون چیزی که بالاتر گفتم، یه SwitchCase هست. خب ببینید این تابع یه آرگومان میگیره که آیدا اسمشو گذاشته a1 که با فلش قرمز مشخص کردم. بعد اومده روی این a1 شرطها رو گذاشته و switch کرده. خب ببینید زمانی که این A1 برابر با 5 باشه اون رشته You Won رو به ما نشون میشده. با فلش سبز مشخص شده.
پس ما باید ببینیم این تابع ما که اسمش رو هم زده sub_4290 رو کی و کجا با آرگومان 5 فراخوانی میکنن.
خب برا این کار دوباره xref به کمکمون میاد. روی همون اسم تابع، بالای گراف یا توی Decompiler کلیک کنید و دکمه x رو بزنید. دوباره میبینید که یه پنجره باز میشه و لیست جاهایی که این تابع رو استفاده کردن میاره براتون.
خب همونطور که میبینید، اینجا ما 3 جا رو میبینیم که از این تابع استفاده کردن و اونو فراخوانی کردن. من اولیو میزنم و میرم اونجا و میبینیم که اونجا عدد 4 رو پاس داده به تابع که خب مد نظر ما 4 نیست. حالا دومی رو انتخاب میکنم و میریم توی یه تکه کدی که این تابع رو با ارگومان 5 فراخوانی کرده. که خب توی عکس زیر میبینید که اینجایی که مشخص کردم 5 پاس داده شده به تابع و بعدش call انجام شده.
ما توی مرحله دوم در مورد نحوه فراخوانی تابع گفتیم که آرگومان ها قبل از اینکه تابع صدا زده بشه، توی پشته یا همون stack وارد میشن با دستور push ولی اینجا همونطور که میبینید خبری از push نیست و شما میبینید که با یه دستور mov ، مقدار 5 رو ریخته داخل edi . خب پس مگه نباید push میکرد؟ نکته اینجاس که توی معماری x86-64 یا همون 64 بیتی نحوه فراخوانی تابع و ارسال آرگومان ها فرق داره و آرگومان ها به جای اینکه برن توی پشته، میرن داخل register ها. به این صورت که میگم:
فرض کنید ما یه تابع داریم با شکل زیر:
func(1,2,3,4);
برا فراخوانی این تابع به ترتیب، آرگومان اول میره داخل edi یا همون rdi، دومی میره داخل esi یا همون rsi ، سومی میره داخل rdx ، و چهارمی میره داخل rcx . خب البته این برای لینوکسه. برای ویندوز هم به همین صورته ولی خب اسم register ها فرق داره.
پس توی عکس بالا اگه میبینید که قبل از اینکه تابع رو فراخوانی کنه، یه دستور mov زده و 5 رو ریخته داخل edi یعنی این تابع آرگومان اولش 5 هست. که خب این تابع همونجور که بالاتر دیدیم کلا یه آرگومان بیتشر نداره.
خب اینجا بازم به ما چیز خاصی نشون نمیده چونکه هنوز ما نفهمیدیم چرا برنامه اومده و این تابع رو با مقدار 5 صدا زده. خب ببینید الان ما توی یه بلوک از کد هستیم که اسم رو من با فلش آبی مشخص کردم توی عکس بالا. Loc44d0 این تیکه ای از کد هست که تابع مورد نظر ما توش با 5 فراخوانی شده. خب حالا باید ببینیم که این loc44d0 چه زمانی فراخوانی میشه. خب ببینید دوباره روش کلیک میکنیم و x رو میزنیم تا آیدا به ما بگه که کجا این تیکه از کدا صدا زده میشه که در انتها منجر میشه به فراخوانی تابع مد نظر ما، با ارگومان 5 .
خب کلا یه جا بیشتر این تیکه کد فراخوانی نشده و همونجور که میبینید با یه شرط این تیکه اجرا میشه. توی عکس مشخصه که با jz میپره اینجا برنامه.
خب بریم تو این قسمت ببینیم چه خبره. یه کیلیک میکنیم روش و میبینیم که ما رو برد وسط یه تابع.
خب بیاین یه بار مرور کنیم ببینیم چیا داریم الان:
خب اول از همه ما فهمیدیم که اون رشته You Won توی یه تابع هست به نام sub_4290 که اگه مقدار آرگومان ورودی این تابع 5 باشه، این رشته نمایش داده میشه و بعد گفتیم بریم ببینیم کدوم تیکه از کد داره این تابع رو با مقدار 5 فراخوانی میکنه. بعد اومدیم دیدیم یه بلوک از یه تابع ، داره این تابع رو با 5 فراخوانی میکنه که اسم اون بلوک از کد loc44d0 بود. بعد گفتیم خب حالا بریم ببینیم کی داره این بلوک رو فراخوانی میکنه؟ که خب الان رسیدیم به اینجایی که هستیم و تقریبا مشخص شد که چه خبره. چیز خاص سختی تا الان نبوده شاید یه کم پیچیده شده باشه ولی یکی دوبار که مرور کنید متوجه میشید چه خبره.
خب بریم در مورد این کدی که الان داخلش هستیم صحبت کنیم. خب ببینیم چه اتفاقی افتاده اینجا:
نگاه کنید اونجایی که اون بلوک 44d0 اجرا میشه، قبلش یه شرط چک میشه. اومده و eax رو با 1 مقایسه کرده و خب اگه این eax مقدارش 1 باشه میره داخل این بلوک 44d0 . خب حالا بیایم ببینیم Eax چی هست. همونطور که قبلا گفتم مقدار بازگشتی یه تابع همیشه توی eax ذخیره میشه هم تو ویندوز هم تو لینوکس. خب ببینید یه تابعی اومده اجرا شده و بعدش مقدار بازگشتش که تو همون eax هست با 1 مقایسه شده. اینجا میفهمیم که اگه این تابعی که اینجا با فلش آبی مشخص کردم، مقدار بازگشتش، 1 باشه اون رشته You won نمایش داده میشه. ختم کلام رو گفتم براتون.
خب حالا اسم این تابع چیه؟؟ اینجا ببینید نوشته cs:qwordD0B8. اینکه اسم تابع نیست. این اسم یه متغیره. از کجا میفهمیم؟ از اونجا که جلوش نوشته cs و این cs یعنی code segment. و اگه این اصن تابع بود ، خود آیدا اسمشو با sub برامون مینوشت. خب اینجا رو براتون تحلیل کنم که بفهمید هرجا از اینجور call ها دیدید چه جور بفهمید این چه تابعی هست. ببینید این متغیر d0b8 در اصل داره هندل یه تابع رو نگه میداره. اگه برگردین اول کار، من در مورد dlopen و dlsym گفتم که شما وقتی بخواین از یه تابع که داخل یه کتابخونه هست، استفاده کنید، میاین یه هندل به اون تابع میگیرید، ذخیرش میکنید توی یه متغیر و در طول برنامه استفاده میکنید ازش. خب اینجا هم همینه. الان این متغیر در حقیقت داره آدرس یه تابع رو نگه میداره.
خب ببینیم این تابع چیه. چه جوری؟؟ اول باید ببینیم این متغیر کجا استفاده شده. بلاخره یه جایی باید باشه که اون تابع dlsym استفاده شده باشه و بعد آدرس تابع ریخته شده باشه داخل این متغیر d0b8 . خب کافیه روش کلیلک کنیم و x رو بزنیم.
خب ببینید برامون اورده لیست جاهایی که این متغیر استفاده شده. دومی که همین جاست که الان هستیم. ببینید call زده. خب اولی رو ببینید یه دستور mov هست. اینجا جذابه برامون. بریم ببینیم چیه اینجا.
خب همه چی اینجا مشخص میشه و تکلیف ما رو معلوم میکنه:
خب ببینید، از پایین شروع میکنم به گفتن. تابع dlsym اومده و اسم یه تابع رو گرفته که خب آیدا اینجا اون رشته رو به ما نشون داده، getNextMove. بعد مقدار بازگشتی dlsym که الان توی eax هست، درحقیقت همون هندل به این تابع getNextMove هست رو ریخته توی این متغیر D0B8. خب پس ما فهمیدیم که این متغیر داره هندل تابع getNextMove رو نگه میداره. خب حالا این تابع از کدوم کتابخونه اومده؟؟ فلش سبز رو که ببینید مشخص میشه که تابع dlopen اول اومده و اون کتابخونه ChessAI.so رو باز کرده و بعدش با استفاده از تابع dlsym اومده و به سه تا از توابع داخلش دسترسی گرفته. که تو عکس مشخصه . getAiNAme و getAiGreeting و در نهایت getNextMove . این تابع getNextMove اسمش جالبه. یعنی احتمالا این تابع حرکت بعدی رو مشخص میکنه تو صفحه شطرنج.
خب بیایم یه مرور کنیم ببینیم چیا داریم: الان فهمیدیم که اگه این تابعی که هندلش توی متغیر d0b8 ذخیره شده، اجرا بشه و مقدار بازگشتیش 1 باشه اون عبارت You Won نمایش داده میشه. که الان فهمیدیم اون تابعی که توی d0b8 دخیره شده بود همین getNextMove هست که یکی از توابع کتابخونه ChessAI.soهست.
خب حالا کار سخت تر شد. تازه فهمیدیم که هر چی هست تو همون ChessAi هست. و مخصوصا توی تابع getNextMove . خب حالا باید بریم این کتابخونه رو آنالیز کنیم.
من یه نکته بگم قبل از اینکه وارد آنالیز فایل کتابخونه بشیم: ببینید ما وقتی ترافیک رو با وایرشارک شنود کردیم، دیدیم که داره این بازی یه ترافیکی رو میفرسته توی شبکه. ولی نکته اینجاست که وقتی ما فایل ChessUI رو توی آیدا باز کردیم تابعی برای ارسال ترافیک توی شبکه ندیدیم. البته شما ندیدید. من دیدم. چه جوری بفهمیم؟
یکی از مهمترین قسمت هایی که باید توی انالیز ایستا بهش دقت کنیم، import های یه برنامه هست. اینا چی هستن؟ import ها به تمام توابعی گفته میشه که برنامه از کتابخونه های مختلف سیستم عامل استفاده میکنه. توی آیدا شما یه تب دارید به نام imports که توی این قسمت که برید به شما نشون میده از چه توابعی داره استفاده میکنه. که خب وقتی ما میریم تو این تب، هیچ اثری از تابعی که با شبکه ارتباط برقرار کنه نمیبینیم. توابع شبکه رو البته باید اسامیشون رو بشناسید. مثلا socket,bind,connect و … که خب ما اینجا هیچ کدوم از اینا رو نمیبینیم. پس میشه گفت که اون جایی که داره تو شبکه ترافیک میفرسته از داخل همون کتابخونه ChessAI هست. مثلا ببینید توی عکس زیر ما فقط یه مشت تابع میبینیم که همشون تو اسمشون gtk اومده و این به ما نشون میده که این برنامه فقط داره از کتابخونه گرافیک لینوکس استفاده میکنه.
خب بریم سراغ آنالیز ایستای فایل ChessAI.so که ببینیم تو اونجا چه خبره. خب این فایلو توی آیدا باز میکنیم و اولین جایی که میریم طبق معمول، اون تب strings هست تا ببینیم توی این فایل چه خبره و چه رشته های مفیدی برامون وجود داره.
خب وقتی میریم وارد تب strings میشیم، رشته های جذابی رو میبینیم.
خب اینجا دو سه تا رشته خاص داریم. ببینید اون جا با قرمز مشخص کردم، همون رشته ای هست که توی درخواست های DNS ما انتهای آدرس ها میدیدیم که اسم سریال GameofThrones بود. یکی دیگه هم پایینش میبینیم که اگه دقت کرده باشید وقتی بازی میکردید اون پایین صفحه شطرنج اسم حریف رو مینوشت که خب اسمش DeepFlare بود. و از همه جذاب تر اون رشته ای هست که با سبز مشخص کردم. اگه یادتون باشه توی مراحل قبل، تمام رمزهای عبور آخرش با @flare-on.com تموم میشد که خب اینجا هم اینو داریم میبینیم. پس با توجه به این مسایل مشخص میشه که ما باید این فایلو آنالیز کنیم تا بتونیم رمز مرحله بعد رو پیدا کنیم. خب فعلا این رشته ها تو ذهنمون باشه تا بریم ادامه کار.
بالاتر توضیح دادم که وقتی یه فایل باینری رو میخواین انالیز کنید، مهمترین قسمتش import ها هست که به ما میگه این فایل از چه کتابخونه هایی داره استفاده میکنه. حالا وقتی میخواین یه فایل کتابخونه رو انالیز کنید، مهمترین قسمتش، Export ها هست. این چیه؟؟ ببینید یه کتابخونه وظیفش اینه که یه سری تابع رو در اختیار فایل های اجرایی بذاره. به توابعی که یه کتابخونه در اختیار دیگر برنامه ها قرار میده، میگن Exports . یعنی یه کتابخونه مثلا تابع x رو export میکنه و فایل اجرایی میاد و از این کتابخونه استفاده میکنه و تابع x رو import میکنه. خب حالا ما میخوایم این فایل ChessAI.so رو که یه کتابخونه هست رو آنالیز کنیم. پس میریم ببینیم این کتابخونه چه توابعی رو export کرده.
خب از تب exports توی آیدا استفاده میکنیم.
خب همونطور که میبینید، توایع نام آشنایی برامون اینجا هست که توی ChessUI اینا رو با dlsym صدا زده بود. خب دونه دونه اینا رو بررسی میکنیم که ببینیم چیا هستن. اول میریم سراغ getAiGreeting :
خب ببینید این تابع کلا چارتا خط بیشتر نیست و تنها کاری که میکنه اینه که اون رشته ای که دورش خط کشیدم رو برمیگردونه. اگه دقت کنید این رشته همون رشته ای هست که ابتدای بازی توی صفحه شطرنج چاپ میشه. پس این تابع چیز خاصی نداره. میریم سراغ تابع gretAiName:
خب این تابع هم باز چارتا خط بیشتر نیست که مشخصه که اینم داره یه رشته DeepFlare که همون اسم هوش مصنوعی توی بازی هست رو برمیگردونه. پس اینجا فهمیدیم که بازی میاد و این توابع رو فراخوانی میکنه تا فقط دو سه تا رشته بگیره ازشون.
خب بریم سراغ تابعی که قبلا توی ChessUI دیدیم و فهمیدیم که این اگه 1 برگردونه، اون رشته YouWon به ما نشون داده میشه. و اون تابع getNextMove بود.
خب این تابع رو که باز کنیم، کدهای بیشتری میبینیم و اینکه چیزای جالبی و هم برامون داره. اینجا من دارم یه تابع gethostbyname میبینم که این تابع در اصل یکی از توابع شبکه هست. این تابع کارش چیه؟ هیچی، کارش فرستادن درخواست DNS هست. این تابع از کتابخونه socket توی لینوکس میاد. خب این تابع کارش اینه که یه آدرس رو میگیره و به عنوان یه درخواست DNS میفرسته توی شبکه و بعد جواب رو که از DNS سرور گرفت، اونو به ما برمیگردونه.
خب پس مشخص شد که این تابع هست که داره درخواست های DNS رو میفرسته. خب بیاین ببینیم که دیگه چه کارهایی داره میکنه. برا درک بهتر من این تابع getNextMove رو توی حالت Pseduecode باز میکنم تا بهتر متوجه بشید که چه خبره. فقط از الان کامل حواستون رو جمع کنید و خوب دقت کنید چی میگم تا قشنگ متوجه بشید، روال کار این تابع چه جوریه و یاد بگیرید چه جوری یه تابع رو آنالیز کنید. اینجا شما میتونید با خوندن کدهای اسمبلی هم تابع رو آنالیز کنید ولی فقط برا فهم بیشتر من دارم از این شبه کد استفاده میکنم که هم با قابلیت آیدا آشنا بشید و هم راحت تر متوجه بشید.
کل اون تابع getNextMove اینجا توی این عکسه. یه تشکر ویژه باید بکنیم از شرکت HexRays که برامون این Decompiler رو نوشته و البته ما رفتیم و نسخه کرک شدش رو داریم استفاده میکنیم.
خب ببینید توی انالیز هیچوقت خودتون رو توی کد گم نکنید. یعنی اینکه اصلا سعی نکنید خط به خط برنامه رو reverse کنید. اول از همه سعی کنید منطقی که پشت کد هست رو خوب درک کنید و بعد برید سراغ جزییات. خب اینجا نگاه کنید، تابع gethostbyname فقط یه آرگومان گرفته و اونم یه رشتس قطعا. این رشته اون بالاتر تولید شده. رشته شامل چیا میشه؟ ببینید ما قبلا این رشته رو توی ترافیک شبکه دیدم. این رشته اسم یه مهره شطرنجه و بعد هم شماره خونه هایی که توش جابه جا شده و در نهایت هم میبینید که با تابع strcat اومده اون رشته game-of-thrones رو چسبونده ته اون رشته و بعد کلشو فرستاده داخل تابع gethostbyname . همه اینا که گفتم رو از انالیز فایل شبکه و مطابقت دادنش با چیزی که اینجا میبینیم به دست میاریم. خب پس فهمیدیم که الان این تابع gethostbyname به این صورت رشته رو میگیره و میفرسته به سمت DNS سرور و منتظر جواب میشه. خب وقتی جواب بیاد براش، اون جواب که مقدار بازگشتیش هست رو میریزه داخل اون متغیر V9 که توی کد میبینید. خب این v9 چیه؟ در اصل باید ببینیم این تابع gethostbyname چی برمیگردونه. خب برا این کار کافیه یه سرچ بزنیم ببینیم این تابع چیه. خب همونجور که میبینید من سرچ کردم توی سایت http://man7.org و به من گفته که این تابع مقدار بازگشتیش چیه: این سایت دقیقا مثه msdn هست ولی برای لینوکس
خب ببینید من با فلش مشخص کردم گفته که مقدار بازگشتی این تابع یه struct هست از جنس hostent. خب حالا این hostent چیه؟
پایین تر تو همون صفحه توضیح داده بهمون:
خب اینم از hostent همونجور که میبینید یه struct هست که مشخصات اون host توش ذخیره میشه. یعنی شما اسم مثلا سایت google.com رو میدی به این تابع، این تابع از dns سرور میپرسه این اسم رو مشخصاتشو به من بده، و اون سرور یه همچین struct ی برمیگردونه به این تابع gethostbyname .
خب حالا متوجه شدیم که v9 در حقیقت یه struct هست از جنس hostent
خب حالا بریم ادامه کار.
برگردیم به همون تابع getNextMove: خب دیدم که تابع gethostbyname اجرا میشه و بعدش یه شرط میبینیم. این شرط در ابتدا میاد و چک میکنه که آیا اصلا این V9 مقدار گرفته یا نه. اگه خالی باشه یعنی اینکه جوابی از DNS سرور نیومده و خب بلافاصله عدد 2 رو return میکنه و خب این به معنی ارور هست. حالا بریم ادامه. اگه v9 مقدار داشته باشه میاد و یه سری چک ها روش انجام میده. روی کجا چک انجام میده؟؟ روی h_addr_list. یعنی وقتی مطمعن شد که v9 پره و مقدار داره حالا میاد و اون قسمت h_addr_list رو ازش میکشه بیرون و توی متغیری با نام v10 ذخیره میکنه. این h_addr_list در حقیقت همون ip اون host ی هست که به dns درخواست داده. حالا ما IP رو توی v10 داریم. خب من برا اینکه این قسمت خیلی مهمه و توضیحش یه کم پیچیده میشه یه بار دیگه عکس اون if دومی رو اینجا میذارم تا بهتر توضیح بدم.
اینجا سه تا شرط رو چک میکنه که اگه هر کدومش نقض بشه ، این تابع 2 رو return میکنه. یکیش اینه که اولین قسمت ip باید برابر 127 باشه. دومیش چیه؟؟ دومیش میگه که قسمت 4 ام ip رو با 1 اومده and کرده و این مقدار نباید true بشه. یعنی چی؟؟ اینجا گفته که v10[3] & 1 یعنی چی؟ همونطور که میدونید آرایه ها از index صفر شروع میشن. پس اینجا که گفته v10[3] یعنی قسمت اخر IP. حالا این and میخواد چیو بگه؟؟ بیایم یه بار با یه مثال ببینیم میخواد چیو بگه اینجا:
فرض کنید IP که از سمت dnsServer بازگشت داده شده 127.10.11.12 باشه. من اولشو 127 گذاشتم که اولین شرط رو پاس کنه. خب دومین شرط رو بیایم رو این تابع پیاده کنیم. خب : اینip مثال ما رو اگه ببریمش توی یه آرایه اینجوری تیکه تیکه میشه
V10[0]=127,V10[1]=10,V10[2]=11,V10[3]=12
خب شرط دوم رو حالا باهم پیاده میکنیم. اینجا اومده و اون قسمت 4 ام یا همون عدد 12 رو با 1 and کرده. ما هم میایم و 12 رو میبریم توی حالت باینری و با 1 and میکنیم:
0000 1100 and 0000 0001 = 0000 0000
خب ببینید ما الان این عدد 12 رو تبدیل کردیم به باینری و با 1 and کردیم جواب شد 0 . خب این IP توی شرط پذیرفته میشه و شرط رو پاس میکنه چرا؟؟ چون جوابش true نشد. یعنی مقدار غیر صفر نشد. اینجا میخواد بفهمه که بیت آخر از تیکه آخر IP صفره یا یک. که اینجا باید صفر باشه تا شرط رو پاس کنه. پس IPی که از سمت سرور برمیگرده باید اولین تیکش 127 باشه و بیت آخر از تیکه آخر IP هم باید 0 باشه.
خب بریم یه شرط دیگه هم داریم: شرط سوم اومده و اول، تیکه سوم IP رو با 0xf یه عملیات and روش انجام داده و بعدش اومده گفته اگه این مقدار با a1 مخالف بود شرط نقض میشه. خب دوتا سوال اینجا هست: یکی اینکه این دقیقا چی میگه ؟؟ و یکی هم اینکه a1 چیه؟؟ خب اگه توی آیدا روی یه متغیر کلیک کنید اونو براتون به رنگ زرد در میاره و تمام جاهایی که توی کد اون متغیر وجود داره رو هم زرد میکنه که شما بفهمی این متغیر کجاها استفاده شده. خب عکشو ببینیم:
خب ببینید توی تعریف تابع اون بالا میفهمیم که a1 در حقیقت یه int هست که به عنوان اولین آرگومان به این تابع getNextMove پاس داده میشه.خب حالا بیایم اون and رو ببینیم چی میگه:
V10[2]= 11
0000 1011 and 0000 1111= 0000 1011
خب ما الان تیکه سوم IP رو اومدیم و با 0xf عملیات and رو انجام دادیم. نتیجه چی شد؟؟ نتیجه اینه که دقیقا اون نیمه پایینی این عدد رو میخواد بکشه بیرون. ببینید ip توی کامپیوتر از 4 تا byte ساخته میشه. چون هر تیکه IP از 0 تا 255 بیشتر نیست پس برای نگه داریش از یه بایت استفاده میشه. خب حالا هر بایت دو قسمت داره 4 بیت پر ارزش و 4 بیت کم ارزش که اینجا مثلا برا عدد 11، اون 4 تا صفر میشن قسمت پر ارزش و اون بقیه میشن کم ارزش. حالا اینجا چرا اومده این تیکه از ip رو با 0xf عملیات and زده؟ برا اینکه قسمت کم ارزشش رو فقط پیدا کنه. که همون 1011 میشه. مثلا اگه میخواست قسمت پر ارزشش رو پیدا کنه میومد و با 0xf0 عملیات and رو انجام میداد.
خب حالا پس فهمیدیم که این شرط اخر برا چیه: برا اینه که بفهمه تیکه سوم IP قسمت کم ارزشش باید برابر باشه با a1 که این a1 آرگومان اولیه کا به تابع پاس داده میشه.
خب بیایم یه مرور بکنیم: IP که از سمت DNS برمیگرده باید سه تا شرط رو داشته باشه:
اول- باید اولین تیکش، 127 باشه
دوم- باید بیت آخر مربوط به تیکه آخر، صفر باشه
سوم- باید نیمه کم ارزش مربوط به تیکه سوم، با آرگومان اول تابع برابر باشه
خب وقتی هر سه تای این شروط رو پاس کنه اون IP، یه دستور sleep انجام میشه. یعنی اینکه برنامه به مدت 1 ثانیه متوقف میشه و بعد شروع میکنه سه سری xor کردن و در انتها یه عدد رو به بازی یا همون ChessUI برمیگردونه. خب ما فهمیدیم که در چه صورتی میتونیم بازی رو انجام بدیم. یعنی الان ما باید یه لیستی از IP هایی که این سه تا شرط رو پاس میکنه تولید کنیم و بذاریمشون توی اون فایل /etc/hosts که مربوط به dns لینوکسمون هست و بازی رو اجرا کنیم تا بتونیم بازی کنیم. خب دوتا شرط اول که مشکلی نداره. ولی ما برای شرط سوم باید بفهمیم که اون آرگومان اول تابع یا همون a1 چیه که بتونیم از روش یه الگو در بیاریم.
خب برا اینکه بفهمیم این ارگومان اول چیه باید برنامه رو دیباگ کنیم. خیلی پیچیده شده حل این چلنج یعنی قشنگ باید شما هر تکنیکی بلدی رو به کار ببندی تا بتونی به جواب برسی. خب برا دیباگ ما از دیباگر قدرتمند لینوکسی gdb استفاده میکنیم. برا اینکه ما بتونیم بفهمیم که ارگومان اول چیه، کافیه که یه breakpoint بذاریم اول تابع getNextMove و بعد مقدار رجیستر edi رو ببینیم. قبلا گفتیم که مقدار ارگومان اول تابع توی لینوکس میره توی رجیستر edi میشینه.
خب طبق چیزی که توی عکس میبینید عمل کنید تا بتونید برنامه ChessUI رو دیباگ کنید.
خب ببینید به ترتیب شماره ای گذاشتم دستورات رو بزنید. اول ما توی شماره 2 ، یه breakpoint گذاشتیم روی تابع getNextMove و بعد برنامه رو با دستور run اجرا کردیمو خب من سرباز جلوی شاه رو حرکت دادم و خب همون لحظه gdb برنامه رو متوقف میکنه چونکه ما رسیدیم سر تابع getNextMove . خب اینجا با دستور i r edi شما میتونید محتویات edi رو ببینید که همونجور که میبینید 0 هست. یعنی آرگومان اولی که پاس داده شده به getNextMove صفر هست. خب بعدش هنوز برنامه متوقفه. باز زدن دستور finish ، gdb میاد و تا اخر تابع رو اجرا میکنه و دوباره متوقف میشه و هونجور که میبینید در انتهای کار من دستور i r eax رو زدم تا ببینم مقدار بازگشتی تابع getNextMove چی هست که هونجور که میبینید 2 برگردونده که این یعنی به خطا خورده که خب با تحلیلی که بالا انجام دادیم میفهمیم که چرا 2 برگردونده. چون اصن DNS سروری نداریم که بخواد جواب بده.
خب بعد هم اومدیم با دستور c یا همون continue به gdb گفتیم ادامه بده کارو که خب با خطای بازی مواجه میشیم. خب حالا من فهمیدم که این a1 صفره ولی آیا همیشه صفره؟؟ نمیدونیم . ما حداقل باید بتونیم دوتا حرکت انجام بدیم تا ببینیم این a1 چه تغییری میکنه. خب من برا اینکه بفهمم این مقدار A1 یا همون آرگومان اول تابع getNextMove چه جوری تولید میشه باید برم همون جایی که تابع getNextMove صدا زده میشه توی فایل ChessUI و ببینیم این مقدار چه جوریه.
خب دوباره آیدا رو باز میکنم و این بار فایل ChessUI رو داخلش میبرم و میرم همون جایی که تابع getNextMove فراخوانی میشد. که خب بالاتر اگه یادتون باشه اونجا رو پیدا کرده بودیم. همون جایی که متغیر d0b8 رو فراخوانی میکرد.
خب ببینید الان اینجا همونجاس که توی برنامه ChessUI ، تابع getNextMove فراخوانی میشد. همونجور که گفتیم آرگومان اول همیشه توی edi میره که خب الان یه متغیر رفته داخل edi به اسم D120 که توی عکس با فلش آبی مشخص کردم. خب ما میخوایم ببینیم از این متغیر دیگه کجاها استفاده شده. خب طبق چیزی که قبلا گفتم روش کلیک میکنیم و دکمه x رو میزنیم همونطور که میبینید 3 جا از این متغیر استفاده شده. از همین جا مشخصه چه خبره. ببینید اولی که اومده و مقدار 0 رو ریخته تو این متغیر. دومی هم که همین جاییه که الان هستیم. سومی جالبه. ببینید اومده این متغیر رو با 1 جمع کرده. این یعنی چی؟؟ یعنی اینکه با هر حرکت یه واحد به این متغیر اضافه میشه. یعنی مثلا الان من سرباز رو تکون دادم، مقدار این متغیر، صفر بود حرکت بعدی یه واحد بهش اضافه میشه و میشه 1 و حرکت بعدی 2 و همینجور تا آخر. خب الان پس فهمیدیم که این متغیر از صفر شروع میشه و هر بار بهش یه واحد اضافه میشه.
خب حالا اینهمه حرف زدیم از همه جا گفتیم. استاتیک رفتیم، داینامیک رفتیم، IP آنالیز کردیم. خب تهش که چی؟؟ الان دقیقا باید با اینهمه چیزی که فهمیدیم چیکار کنیم؟؟ الان بیایم IP تولید کنیم طبق این الگورتیمی که فهمیدیم؟؟ خیلی خسته کننده شده. و واقعا اینجاس که شما ممکنه بپرسی اینا رو من از کجا باید بفهمم؟؟ مساله اینه که شما وقتی داری reverse میکنی باید به هر دری بزنی. یعنی هر ایده ای میاد تو ذهنت رو باید به کار بگیری و ببینی چه جوابی میگیری.
خب من اینو بهتون بگم که من اومدم و طبق این الگوریتمی که بالا برا تولید IP پیدا کردیم، هرچی IP میشد رو ساختم ولی بازم به نتیجه نرسیدم. چرا؟ چونکه بعد از اینکه ما IP رو ساختیم، باید شروع کنیم به بازی کردن. بعد میدونید چند حالت ممکنه رخ بده؟ ما باید بتونیم بازی رو ببریم یعنی کیش و مات کنیم. سوال اینجاس فرض کنید اصن شطرنج بلد نباشیم، چه جوری میخوایم بازی کنیم؟ پس راه درست این نیست که بیایم IP تولید کنیم و بذاریم توی dns لینوکسمون. من یه راه دیگه رفتم و البته یه راه بهترم هست که در آخر بهتون میگم که ببینید با یه ذره دقت چقد راحت تر میشد اینو حل کرد.
خب ما الان انقدر غرق شدیم توی انالیز که اصن فراموش کردیم بابا یه فایل دیگه هم داریم که یه ترافیک توشه. توی اون فایل capture.pacp ما حدود 80 تا پکت DNS داریم. این یعنی چی؟؟ یعنی اینکه اون کسی که این بازی رو داشته انجام میداده 40 تا حرکت انجام داده. پس بیایم بریم سراغ اون فایل و ببینیم چه خبره اونجا.
خب ببینید ما الان فایل capture رو که توی wireshark باز کنیم، میبینیم که 80 تا پکت رفته که خب 40 تاش درخواست بوده و 40 تاش قطعا جواب بوده. پس اون کسی که این بازی رو انجام داده توی شرکت fireEyE ، 40 تا حرکت زده با شطرنج. من حدس میزنم که اون کسی که این بازی رو انجام داده تونسته بازی رو ببره. پس با این فرض میایم و این فایل capture.pcap رو بررسی میکنیم که ببینیم تمام این IP هایی که داخلش هست ایا اون 3 تا شرط ما رو پاس میکننن یا نه. خب یه راهش اینه که شما بشینی دستی دونه دونه بررسی کنی یه راهم اینه که از یه اسکریپت کمک بگیری. من اینجا از پایتون استفاده کردم. حقیقتا انتظار نداره کسی از شما که نحوه پارس کردن یه فایل pcap رو با پایتون از حفظ باشید. ولی خب منم بلد نبودم و با یه سرچ ساده تونستم این کد رو بنویسم.
خب ببینید من اومدم این فایل pcap رو باز کردم و تمام IP های داخلش رو ریختم توی یه آرایه و بعد اومدم اون سه تا شرط رو روشون بررسی کردم و هر کدوم از اونا که اون شروط رو پاس کردن، رو چاپ کردم.
خب بریم سراغ کد اول:
import sys
from scapy.all import *
pkts = rdpcap(sys.argv[1])
dns_records = []
ips=[]
part=[]
ips2 = {}
def find_dns(pkts):
print "all dns records:"
for p in pkts:
if p.haslayer(DNSQR) and p.haslayer(DNSRR):
rrname = p.getlayer(DNSRR).rrname
rdata = p.getlayer(DNSRR).rdata
print rdata +' '+ rrname
ips2[rdata]=rrname
print "\n--- matched dns records ---"
for i in range(50):
for ip,addr in ips2.items():
part=ip.split('.')
b=bin((int(part[3])))
if part[0]=='127' and b[len(b)-1]=='0' and (int(part[2]) & 0xf)==i:
print str((int(part[2]) & 0xf))+"-"+ip+' '+addr
find_dns(pkts)
خب ببینید اول اومدم و از کتابخونه SCAPY استفاده کردم که این برا کار با شبکه هست تو پایتون. بعد فایل capture.pcap رو به عنوان ارگومان دادم به اون تابع rdpcap و بعدش دیگه با اون for اول اومدم تمام پکت ها رو بر اساس اون آدرسی که درخواست شده و اون IP که پاسخ داده شده، چاپ کردم رو صفحه. یعنی اول کل پکت ها رو پارس کردم و بعدش اومدم ببینم کدوم از این IP ها اون سه تا شرط رو پاس میکنه.
خب توی حلقه بعدی اومدم و تمام این IP هایی که استخراج کردم رو با اون سه تا شرط چک کردم و هر کدوم اون سه تا شرط رو پاس کردن رو چاپ کردم.
فقط یه سوال پیش میاد. ما فهمیدیم که اون A1 که آرگومان اول بود، از صفر شروع میشه و هر بار یه واحد بهش اضافه میشه. ولی تا کجا ادامه پیدا میکنه؟ یعنی تا چند میخواد اضافه بشه بهش؟ این سوالی بود که من وقتی داشتم اینو حل میکردم برام پیش اومد. من نمیدونستم انتهاش کجاس برا همین من این حلقه تو در تو دومی رو که نوشتم گفتم میذارم تا 50. یعنی فرض رو بر این گذاشتم که 50 تا حرکت باشه. در صورتی که میشه راحت فهمید این عدد تا کجا میره. از کجا میشه فهمید؟ خب ببینید این تمام IP هایی هست که این سه تا شرط رو پاس میکنن:
ببینید من اون شماره ای که پشت IP ها زدم در اصل همون a1 بوده. خب ببینید کلا تا 14 بیشتر نرفته. یعنی چی؟ یعنی کلا از صفر تا چهارده بودن که اون قسمت کم ارزش تیکه سوم IP، باهاشون برابر بوده. که میشه 15 تا. اینو از یه جا دیگه هم میشد فهمید. از کجا؟ از اونجا که قسمت کم ارزش یه بایت، میشه 4 بیت. که 4 بیت نهایتا میتونه از صفر تا پونزده رو تولید کنه. پس یعنی خود شرط سوم رو اگه بیشتر بهش دقت میکردیم میفهمیدیم که کلا این بازی رو میشه با 15 تا حرکت برنده شد. چون شرطیه که خودشون گذاشتن. خب حالا ترتیب هم مهمه دیگه. چون اون a1 از 0 شروع میشه، پس ما باید حواسمون به ترتیب این حرکاتی که میزنیم هم باشه. به خاطر همین من از صفر تا 14 اینارو مرتب کردم. خب حالا کافیه که خروجی این اسکریپت رو دقیقا کپی کنیم توی فایل /etc/hosts. البته بدون اون اعداد پشتش و اون نقطه های آخر. این فایل در اصل یه dns محلی براتون درست میکنه بعد بازی رو شروع کنیم و به ترتیب همین حرکاتی که نوشتیم رو از بالا به پایین بازی کنیم تا بتونیم پیروز بشیم. امیدوارم متوجه شده باشید ولی اگر متوجه نشدید اشکال نداره، سوال بپرسید من جواب میدم هرجاییش که خوب متوجه نشدید.
یادتون باشه که اینترنت قطع باشه از ماشینتون و اینکه اون خطی که اول پست گفتم رو توی فایل resolv.conf بنویسید حتما و بعد بازی رو اجرا کنید.
خب بریم بازی. اولین حرکت همون pawn-c2-c4 هست یعنی سرباز از c2 بره به c4 خب و در ادامه بقیه رو هم انجام میدیم.
Knight همون اسب خودمونه. Bishop هم همون فیله و queen هم که دیگه ملکه یا همون وزیره.
خب میبینید که بازی داره انجام میشه و هیچ خطایی در کار نیست و اینه پیروزی. شما الان کامل تونستید معماری یه برنامه رو از صفر تا صد بفهمید و reverse کنید.
خب اینم رمز این مرحله.
باورتون میشه اگه من بگم رمز جلو چشممون بوده ولی ما ندیدیم؟ بیاین بریم تا بهتون بگم کجا میتونستیم الگوریتم تولید رمز رو بفهمیم.
حل مساله با راه حل دوم:
خب یادتونه موقعی که داشتیم string های ChessAI رو بررسی میکردیم، دقیقا به یه رشته ای رسیدیم که @flare-on.com بود؟ که خب ما گفتیم تمام سه تا مرحله قبلی رمزشون، تهش این عبارتو داشت. خب بیاین بریم ببینیم این رشته کجا استفاده میشه. من عکس اینو دوباره میزارم که بهتر متوجه بشید.
خب ببینید تو عکس با سبز دورش خط کشیدم. روش کلیک میکنیم، تا آیدا ما رو ببره جایی که این رشته وجود داره. که خب اون قسمت data برنامه هست.
خب ببینید این رشته به صورت تیکه تیکه اومده اینجا. یعنی کامل سرهم نیست و خب بالای این رشته هم یه یه سری صفر میبینید. یه کم که بریم بالا یه همچین چیزی میبینید:
ببینید یه اسم نوشته byte_4060 و بعدش این صفرها شروع شدن و آخرش هم اون flare-on.com اومده . این نشون دهنده اینه که اینجا ما یه آرایه داریم. اگه دقت کنید الان متوجه میشید که در حقیقت اون صفرها جای خالی رمز عبور هستن یعنی قراره رمز عبور بیاد اینجا جای صفرا بشینه و تهشم یه @flare-on.com داره. خب بیاین ببینیم از این آرایه کجا استفاده شده. همونجور که گفتیم روی اسم آرایه کلیک میکنیم و x رو میزنیم.
خب ببینید کجا از این استفاده شده؟ توی تابع getNextMove. خب میریم اونجا. من توضیحشو توی شبه کد میدم که راحت تر باشه فهمش. خب همونجور که میبینید اینجا زمانی که آی پی اون سه تا شرط رو پاس میکنه، میاد این قسمت و دونه دونه خونه های آرایه byte_2020 رو با V10[1] که همون تیکه دوم آی پی هست، xor میکنه و میریزه داخل یکی از خونه های byte_4060. البته میبینید که تو خط اول اومده index آرایه رو 2*a1 گذاشته و تو خط دوم 2*a1+1 گذاشته که خب مشخصه اولی برا خونه های زوجه آرایه هست و دومی برا خونه های فرد. و اینکه اومده از همون A1 که قبلا در موردش صحبت کردیم هم استفاده کرده. یعنی آرگومان اول تابع که هر بار یه واحد بهش اضافه میشد.
خب حالا بریم ببینیم اون آرایه byte_2020 چیه که داره عملیات xor روش انجام میشه. روش که کلیک کنیم میریم توی قسمتی که این تعریف شده.
خب ببینید دقیقا اسمش رو برامون اینجا اورده و خود آیدا تشخیص داده که این یه آرایه 30 عضوی هست. اونجا که با رنگ قرمز مشخص کردم. خب من یه نکته بگم. الان ببینید این قسمتی که با سبز مشخص کردم. همه آدرس ها یکیه. این به خاطر اینه که آیدا یه کم گیج شده تو تشخیص این آرایه. برا اینکه بهتر بتونیم این آرایه رو ببینیم روی اون اسمش کلیک میکنیم، و دکمه d رو هی میزنیم تا این آرایه رو برامون به حالت های مختلف byte، word، qword تبدیل کنه و بعد روی byte میزاریم بمونه. ببینید میشه مثه عکس پایین:
خب این آرایه همونجور که میبینید، یه سری بایت بی معنی هستن. که خب مشخصه همشون یه سری عدد hex هستن. خب ببینید اون بالا توی کد دیدم که این آرایه داره با اون تیکه دوم آی پی xor میشه. پس من اینجا میتونم بفهمم که این آرایه الان که یه مشت عدد بی معنی هست، بخاطر اینه که رمز شده و اونجایی که داره xor میشه در حقیقت داره رمز گشایی میشه.
خب من میتونم خودم الان این رمزگشایی رو پیاده سازی کنم. چون هم آی پی های معتبر رو داریم( یادتونه دیگه با اون اسکرسپت پایتونی که نوشتیم) و هم الان الگوریتم رمزگشایی رو داریم.
خب بریم. فقط کافیه تو همون اسکریپت پایتون قبلی، یه تیکه کد اضافه کنید. اول ما باید این آرایه byte_2020 رو کامل ببریم توی اسکریپت پایتون. که خب توی کدی که پایین نوشتم میبینید. یعنی باید همین عکس بالا رو که اعضای این byte_2020 رو نشون میده رو ببریم توی یه آرایه توی پایتون.
بعد بیام دقیقا همین الگوریتم xor ی که توی getNextMove دیدیم رو عینا روی این آرایه ای که داریم و اون آی پی هایی که اون سه تا شرط رو پاس میکردن، بزنیم و در آخر میرسیم به رمز.
خب ببینید من فقط اومدم دقیقا همون چیزی که توی تابع getNextMove بود رو نوشتم اینجا و بعدش هم اون پایین یه حلقه نوشتم و دونه دونه اون آرایه 4060 رو چاپ کردم جاهایی که به کد اضافه کردم با فلش مشخصه. خب این اسکریپت رو اجرا کنیم و نتیجه رو ببینیم.
خب اینم از رمزی که خودمون پیداش کردیم بدون نیاز به بازی کردن.