ساختار برنامه های اجرایی در حافظه RAM – قسمت اول
در این پست قصد داریم تا به صورت مختصر با نحوه قرارگیری برنامه ها در حافظه RAM آشنا شویم . به عنوان یک متخصص امنیت نیاز دارید تا از نحوه قرارگیری برنامه ها در RAM و عملکرد توابع و حافظه استک اطلاع داشته باشید چرا که در هنگام تحلیل آسیب پذیرها به دانش زیرپایه در این مورد نیاز خواهید داشت.
همان طور که میدانیم در سیستم عامل های امروزی موضوعی با عنوان virtual address space مطرح می شود که به آن حافظه مجازی گفته می شود. در تکنولوژی حافظه مجازی از حافظههای جانبی ارزان قیمت نظیر هارد دیسک استفاده میگردد. در چنین حالتی اطلاعات موجود در حافظه اصلی که کمتر مورد استفاده قرار گرفتهاند، از حافظه خارج و در محلی خاص بر روی هارد دیسک ذخیره میگردند. بدین ترتیب بخشی از حافظه اصلی آزاد و زمینه استقرار یک برنامه جدید در حافظه فراهم خواهد شد. عملیات ارسال اطلاعات از حافظه اصلی بر روی هارد دیسک بصورت خودکار انجام میگیرد.
در یک سیستمعامل 32 بیتی مثل نسخههای 32 بیتی ویندوز 2003 از یک حافظه مجازی (Virtual memory) برای انجام پردازشهای مختلف استفاده میشود. این حافظه مجازی که حداکثر 4 گیگابایت میتواند ظرفیت داشته باشد به دو قسمت تقسیم میشود. یک قسمت 2 گیگابایتی آن به وسیله برنامه در حال اجرا اشغال شده و 2 گیگابایت دیگر در اختیار سیستمعامل قرار میگیرد. سپس برای map کردن آدرس ها از حافظه مجازی به حافظه فیزیکی از page table استفاده می شود که به وسیله کرنل سیستم عامل مدیریت می شود.در سیستم عامل های multi task ، هر پردازش به صورتی اجرا میشود که انگار در یک محیط ایزوله شده اجرا می شود و آدرس های پردازش ها با یکدیگر تداخل نمیکند چرا که هر کدام page table خود را دارند و اینطور به نظر میرسد که تنها یک برنامه در RAM در حال اجرا است. در شکل زیر، نحوه اختصاص حافظه به پردازش ها و کرنل را در سیستم عامل های Linux و Windows مشاهده می کنید.
حال در سیستم عامل 64 بیتی ویندوز قضیه کمی متفاوت می شود. سیستمعامل 64 بیتی ویندوز 2003 که با استفاده از قدرت پردازندههای 64 بیتی جدید قادر بود از یک سیستم آدرسدهی 40 بیتی استفاده کند، میزان حافظه مجازی قابل دسترسی سیستم از 4 گیگابایت به 16 ترابایت (هزار گیگابایت) افزایش یافت.
بدینترتیب 8 ترابایت از این ظرفیت در اختیار برنامههای در حال اجرا و 8 ترابایت دیگر در اختیار سیستمعامل قرار گرفت.
همان طور که گفتیم ، هر برنامه با استفاده از تکنیک حافظه مجازی طوری اجرا می شود که به نظر میرسد به تنهایی در حال استفاده از حافظه فیزیکی است .در شکل زیر نحوه سوئیچ کردن CPU بین برنامه ها و شکل حافظه از منظر آنها را مشاهده می کنید.
در این شکل نواحی آبی ، مناطقی هستند که به حافظه فیزیکی map شده اند و برنامه در حال استفاده است که در این شکل مرورگر فایرفاکس بخش عمده ای از حافظه اختصاص داده شده به خود را استفاده کرده است. البته حافظه به این سادگی نیست و به بخش های مختلف مانند Stack ، Heap و ... تقسیم می شود که هر کدام موارد استفاده خود را دارند. عمده ترین مورد کاربرد حافظه Stack برای فراخوانی توابع و متغیرهای آنها است. در شکل زیر نحوه تقسیم بندی حافظه فیزیکی به بخش های مختلف را از منظر سیستم عامل لینوکس مشاهده می کنید.
توجه داشته باشید که این ساختار تقریبا برای همه پروسس ها یکسان است و آدرس دهی نیز دقیقا به همین شکل انجام می شود این مسئله باعث می شود که نویسندگان کدهای مخرب ( به خصوص اکسپلویت ها) ، مسیر راحت تری پیش رو داشته باشند و از یک آدرس دهی یکسان در کدهای خود استفاده کنند. برای جلوگیری از این عمل ، تکنیک ASLR در سیستم عامل ها معرفی می شود. دانستن این ساختار ، برای تحلیل کدهای مخرب و اکسپلویت ها بسیار اساسی است. عمده ترین آسیب پذیری هایی که برای نرم افزارها گزارش می شود ، آسیب پذیری های مربوط به حافظه Stack است. در شکل بالا همان طور که ملاحظه میکنید آدرس های استک همیشه رو به آدرس های پایین تر رشد میکنند. در یک برنامه آسیب پذیر اگر مهاجم بتواند کدهای خود را در stack تزریق کند و سپس به نحوی کنترل اجرای برنامه (EIP) را به کدهای مخرب هدایت کند ، آنگاه موفق به اجرای آنها می شود که برای جلوگیری از این مورد نیز تکنیک DEP مطرح می شود که به صورت سخت افزاری و نرم افزاری قابل پیاده سازی است. به عنوان مثال در ویندوز 7 ، میتوانید مشاهده کنید که آیا سخت افزار شما از قابلیت DEP پشتیبانی میکند یا خیر ، در صورت پشتیبانی نکردن ، ویندوز 7 آن را به صورت نرم افزاری پشتیبانی میکند.
در این آدرس میتوانید یک منبع بسیار عالی از عملکرد توابع و چگونگی فراخوانی ها و مدیریت آنها در حافظه stack را پیدا کنید. با توضیحات ذکر شده در آدرس بالا ، به صورت دقیق متوجه خواهید شد که یک تکه کد آسیب پذیر چگونه عمل فراخوانی را انجام میدهد، پارامترها چگونه و در کجا قرار میگرند و آدرس بازگشت به چه صورت مدیریت میشود. همچنین با توجه به شکل حافظه که در بالا آورده ایم متوجه خواهید شد که چگونه توابع از Stack استفاده میکنند.برای محافظت از Stack متدهای متفاوتی مطرح شده است که به DEP اشاره کردیم. تکنیک canary نیز محبوبیت خاص خود را دارد که در یک پست به صورت مفصل در مورد آن شرح خواهم داد.
ممنون از مطالب خوب ومفیدتان