قسمت دوم بررسی استراکچرها در زبان C - فهمایش در سطح دیزاسمبلی
در تصویر 7، خروجی کپی مقادیر CC به درون آدرسی که توسط EDI مورد ارجاع قرار گرفته است، قابل نمایش است.
تصویر 7: کپی مقدار CC به درون آدرس مورد ارجاع توسط EDI
دستوراتی که در ادامه آورده شدهاند، مربوط به فلگ GS کامپایلر هستند که مفهوم قناری در پشته را به درون طرح پشته اضافه میکند. ابتدا یک مقدار شبه رندوم که در ثابت __security_cookie قرار دارد توسط کامایلر بازیابی شده و در رجیستر EAX ذخیره میشود. سپس بر روی مقدار درون رجیستر EAX با مقدار درون EBP یک عملیات XOR انجام میشود و در نهایت، خروجی عملیات XOR در آدرس [ebp-4] ذخیره میشود. مقدار نهایی که در این آدرس قرار میگیرد، به منظور بررسی عدم تخریب حافظه Stack مورد بررسی قرار خواهد گرفت. در نهایت تابع CheckForDebuggerJustMyCode فراخوانی شده است که به دلیل فعال سازی فلگ JMC به کد اضافه میشود. در تصویر 8، خروجی دیزاسمبلی این تابع در حالت Release درون IDA Pro نمایش داده شده است. همانطور که قابل مشاهده است، بخش زیادی از کدهای دیزاسمبلی که در حالت Debug قابل مشاهده است، هنگامیکه باینری در مُد Release تولید میشود، آن اطلاعات اضافی وجود ندارد.
تصویر 8: خروجی دیزاسمبلی باینری مُد Release درون IDA Pro
با این حال، همانطور که در تصویر 9 نمایش داده شده است، بعد از اینکه ما یک Struct تعریف میکنیم، و اولین ممبر آن را مقداردهی میکنیم، دستور mov dword ptr آورده شده است. هنگامیکه در خروجی لیست دیزاسمبلی با dword رو به رو میشویم، به این معنا است که با یک متغیر 32 بیتی رو به رو هستیم. از آنجایی که اولین عضو Struct ما از نوع int بوده است، در اینجا عمل mov بر روی یک آدرس 32 بیتی صورت گرفته است. ولی در ادامه به جای o_structure در سطح اسمبلی کامپایلر از رجیستر ebp به منظور دسترسی به اعضای استراکچر Disassembly استفاده کرده است. مثلا در گام دوم، برای کپی مقدار اسکی 14h به درون عضو m_char از رجیستر ebp به همراه آفستی که آن عضو درون پشته قرار دارد، استفاده کرده است تا مقدار 14h را به درون آن منتقل کند. در ادامه همین مسئله مجدد رخ داده است و تنها اندازه آفست دستورالعمل mov تغییر کرده است. همچنین در نهایت به دلیل اینکه یک مقدار Floating-Point مورد استفاده قرار گرفته است، در سطح اسمبلی شاهد استفاده از رجیسترهای XMM به همراه دستور movss هستیم. هنگامیکه در معماری x86 با یک نوع داده float رو به رو هستیم، از دستورالعمل movss و dword ptr استفاده شده است، اما هنگامیکه با یک نوع داده double رو به رو هستیم، از دستورالعمل movsd و mmword ptr استفاده شده است.
تصویر 9: مقداردهی اعضای Struct در زبان C
در ادامه آرایه کاراکتری که درون Struct تعریف شده است، با استفاده از تابع strncpy مقداردهی شده است. همانطور که در تصویر 10 قابل مشاهده است، دستور mov esi, esp مقدار جاری پشته را در ثبات esi قرار میدهد. این دستور معمولاً برای ذخیره کردن مقدار پشته در یک ثبات استفاده میشود. در ادامه دستورالعمل push offset string "Milad" آدرس رشته "Milad" را در پشته قرار میدهد. این دستور برای پاس دادن آرگومانها به توابع در Calling Convention زبان C استفاده میشود. در ادامه مجدد یک دستور push آورده شده است که این دستور مقدار 400 به صورت عددی را در پشته قرار میدهد. دستور lea eax, [ebp-40Ch] آدرس ebp-40C را در eax قرار میدهد. دستور lea برای محاسبه آدرس یک متغیر استفاده میشود. سپس مجدد مقدار درون این رجیستری با استفاده از دستور push eax در پشته قرار میدهد. در نهایت وقتی پارامترهای مورد نیاز strcpy_s به درون پشته کپی شد، این تابع فراخوانی می شود. تابع strcpy_s برای کپی کردن یک رشته به رشته دیگر استفاده میشود. دستورالعمل بعدی که فراخوانی شده است add esp, 0Ch مقدار 0Ch (12 در مبنای 16) را به esp اضافه میکند. این دستور برای تعیین موقعیت صحیح پشته پس از فراخوانی تابع استفاده میشود. در نهایت با فراخوانی دستورالعمل مقدار درون رجیستر esi و esp با دستورالعمل cmp مورد مقایسه قرار خواهند گرفت. این دستور برای بررسی صحت موقعیت پشته استفاده میشود. دستورالعمل نهایی که به دلیل فلگ RTC1 به باینری اضافه شده است، تابع __RTC_CheckEsp را فراخوانی میکند. این تابع برای بررسی صحت موقعیت پشته استفاده میشود. در کل، این کد اسمبلی یک رشته به نام "Milad" را با استفاده از تابع strcpy_s کپی میکند و سپس موقعیت پشته را بررسی میکند. در تصویر 10، خروجی همین ساختار را در IDA Pro قابل مشاهده است:
تصویر 10: خروجی دیزاسمبلی باینری در مُد Release
یکی از مهمترین تفاوتهایی که در خروجی تولید شده توسط IDA Pro نسبت به خروجی تصویر 9 وجود دارد، مقداردهی تمامی اعضای استراکچر به صورت یکجا است. متغیرها با استفاده از آدرس پایه که توسط رجیستر esp مورد ارجاع قرار گرفته است، و آفستهایی که در تصویر 10 قابل مشاهده است، تمامی اعضای استراکچر مقداردهی اولیه شدهاند. شایان ذکر است، قبل از اینکه تابع strcpy_s فراخوانی شود، پارامترهای آن درون پشته PUSH شده است. شایان ذکر است، دستور and esp, 0FFFFFFC0h اشارهگر به پشته یا ESP را تراز میکند و دستور sub esp, 440h فضایی برای متغیرهای محلی رزرو میکند. این مراحل تضمین میکنند که مدیریت صحیح پشته انجام شده و محیط یکنواختی برای اجرای تابع فراهم میکنند. سپس در ادامه تمامی این مقادیر با عبور به تابع printf نتیجه آنها برای کاربر نمایش داده خواهند شد.
تصویر 11: عبور مقادیر اعضای استراکچر به تابع printf
0 دیدگاه
نظرهای پیشنهاد شده
هیچ دیدگاهی برای نمایش وجود دارد.