وبلاگی برای دوست‌داران کامپیوتر
شل کدینگ 2
سه‌شنبه ۱٦ آبان ۱۳۸٥ ساعت ٩:٢۸ ‎ب.ظ | نوشته ‌شده به دست علی اسماعیلی | ( نظرات )
Heap ها
وقتی یه DLL بارگذاری میشه، تابع آغازگر رو فراخوانی میکنه. این تابع معمولاً کپه (Heap) مخصوص خودش رو با استفاده از تابع HeapCreat() ایجاد مکنه و یه متغیر عمومی رو بعنوان اشاره گر به کپه ی ایجاد شده، ذخیره میکنه. اینطوری تو کارهای جایگزینی بعدی میتونه از این کپه، به جای کپه ی پیش فرض استفاده کنه. خیلی از DLL ها یه بخش .data دارن که متغیر های عمومی رو توی حافظه ذخیره میکنه و همیشه میشه تو این ناحیه ساختار های داده و اشاره گر توابع مفیدی پیدا کرد. چون DLL های زیادی بارگذاری میشن، کپه های زیادی هم وجود داره. با این همه کپه، البته ردگیری حملات تخریب کپه، کار خیلی سختیه. توی لینوکس، یک کپه هست که میتونه خراب بشه، ولی توی ویندوز چندین کپه میتونن در آن واحد تخریب بشن که شرایط رو خیلی پیچیده میکنه. وقتی کاربری malloc() رو فراخوانی میکنه، در واقع از تابعی استفاده میکنه که توسط msvcrt.dll فراهم شده و اونم HeapAllocate() رو با کپه ی خصوصی msvcrt.dll فراخوانی میکنه. برای اینکه از وضعیت تخریب کپه خبردار بشید، باید تابع HeapValidation() رو فراخوانی کنید، ولی این تابع نیز کار چندان مفیدی انجام نمیده.
مساله ی گیج کننده زمانی پیش میاد که اکسپلویت کردن یه سرریز کپه رو تموم کردید و میخواید یه تابع Win32 API رو با شل کد خودتون فراخوانی کنید. بعضی از توابع شما کار میکنن و بعضیاشون هم باعث ایجاد خطای دسترسی درون RtlHeapFree() یا RtlHeapAllocate() میشن. اینطوری ممکنه پردازه ی شما قبل از اینکه بتونید کنترل رو بدست بگیرید، خاتمه پیدا کنه. تابع WinExec() و توابع مشابه رو نباید با کپه های تخریبی استفاده کرد.
هر پردازه یه کپه ی پیش فرض داره. کپه ی پیش فرض رو میشه با تابع GetDefaultHeap() پیدا کرد. مساله ی مهمی که اینجا وجود داره اینه که کپه ها میتونن توی سگمنت ها رشد کنن. برای مثال، اگه داده های کافی به IIS بفرستید، متوجه میشید که این پردازه از سطوح سطح بالای حافظه استفاده میکنه و همونجا داده ها رو ذخیره میکنه. این یه ترفند مفید برای رهایی از ذخیره سازی داده ها تو آدرس های حافظه ی پایین و کپه های پیش فرضه. به همین علت، نشت حافظه و خطای آدرس دهی داده ها توی برنامه ها میتونه برای ما خیلی مفید باشه. چون میتونیم کد های خودمون رو تو این قسمت های حافظه وارد کنیم.
سرریز کپه تو ویندوز درست به راحتی سرریز توی یونیکسه. از همون تکنیک های ابتدایی اکسپولیت هم میتونید استفاده کنید. البته با دقت. و حتی میتونید بیشترا ز یه سرریز کپه ایجاد کنید که کار اکسپلویت کردن رو برای شما خیلی راحت تر میکنه.

Threading
ویندوز رشته ها (پروفسور های دانشگاه بهش میگن ریسمان) رو طوری پشتیبانی میکنه که لینوکس تا انتشار کرنل 6/2 قادر به این کار نبود. تریدینگ به یه پردازه امکان میده تا چندین کار رو انجام بده و در عین حال از یه ناحیه ی حافظه استفاده کنه. کرنل ویندوز قسمتی از زمان پردازنده رو به رشته ها اختصاص میده، نه پردازه ها. لینوکس کارها رو از طریق مدل « پردازه ی سبک وزن» انجام میده که البته خیلی ضعیفه. رشته ها توی لینوکس البته به عللی به مهمی مدل برنامه نویسی نیستن و این علل با تشریح ساختار امنیتی NT روشن تر خواهد شد.
تریدینگ علت ایجاد HRESULT هست. HRESULT که اساساً یه عدد صحیحه، تقریباً توسط تمام فراخوانی های Win32 API ایجاد میشه. HRESULT میتونه یه مقدار خطا یا نشانگر صحت باشه. اگر این مقدار یه کد خطا باشه، میتونید خطای ایجاد شده رو با تابع GetLastError() پیدا کنید که مقدار خودشو از محل ذخیره سازی محلی رشته میگیره. اگر مدل یونیکس رو در نظر دارید، روشی برای تشخیص شماره خطای رشته ها وجود نداره. Win32 از اول طوری طراحی شده که یک مدل رشته ای باشه.
ویندوز تابع fork() (توی لینوکس برای تولید مثل پردازه ها استفاده میشه) رو نداره. در عوض تابع CreatProcess() رو داره که برای ایجاد یه پردازه ی جدید ازش استفاده میشه که البته این پردازه آدرس حافظه ی مخصوص خودشو داره. این پردازه میتونه هر گیره ای رو که والدش بعنوان وراثتی تعیین کردنة به ارث ببره. به هر حال، والد باید بعداً این گیره ها رو به فرزندش بده و یا فرزند رو مجبور به تخمین مقدار اونا بکنه. (گیره ها معمولاً اعداد صحیح کوچکی هستن).

برچسب‌ها: شل‌ کدینگ, هیپ, ترید

 
لینک دوستان
دیگر موارد