یک سوالی یکی از دانشجویان پرسید، در مورد فراخوانی DLLها یا همان کتابخانه‌های پیوندی پویا به صورت Explicit که در این پست می‌خوام یک مقدار آن را توضیح بدهم. 

ببینید نحوه نوشتن یک DLL که یک عمل بسیار ساده و پیش پا افتاده است و شامل مباحث و مسائل سخت و دشوار نمی‌شود. دلیل استفاده از DLL هم که مشخص است، کاهش سایز برنامه و افزایش پرفورمنس نگهداری کد، به روزرسانی توابع، ماژولار ساختن معماری پروژه و ...

در دوره امنیت سامانه‌های کنترل صنعتی، بخش برنامه‌نویسی سیستمی و اسمبلی هم من نحوه ریزالو شدن آدرس‌های توابع را توسط لودر سیستم‌عامل توضیح دادم. 

در آن‌جا بررسی کردیم که لودر سیستم‌عامل چطور به واسطه اطلاعات درون جداول Export Name Table، Export Ordinal Table و Export Address Table آدرس تابع Export شده را به دست می‌آورد و در جدول Import Address Table قرار می‌دهد. 

در آنجا هم اشاره کردیم که نحوه دسترسی به جداول ENT، EOT و EAT از طریق ممبرهای AddressOfNames، AddressOfNameOrdinal و AddressOfFunctions در ساختار PE قابل دسترس است. 

در مورد Code Caving و تزریق دستورات دلخواه به یک فایل Executable و تغییر OEP به کد تزریق شده ما هم صحبت کردیم. اما مسئله‌ای که در آن ویدیوها در مورد آن‌ها صحبت نکردیم نحوه لود شدن کتابخانه‌های پیوندی پویا به صورت Explicit بود. 

البته من در مورد این مسائل و مباحث در دوره ویندوز اینترنالز و برنامه‌نویسی سیستمی ویندوز قبلا صحبت کرده بودم (البته ویدیوهای آن در دسترس نیست، چون ضبط نشد).

در این پست قصد دارم این مسئله را دوباره توضیح بدهم. در حالت کلی ما می‌توانیم در ویندوز به دو صورت Implicit و Explicit توابع درون کتابخانه‌های پیوندی پویا را فراخوانی کنیم (مبحث DLL درون ویندوز با مبحث Shared Object لینوکس متفاوت است، خلط مبحث نکنید). 

در مورد Implicit که صحبت نمی‌خواهم کنم، چون در اینجا برای من موضوعیت ندارد، اما مبحث Explicit مهم است. تصور کنید که شما یک DLL دارید که حاوی مجموعه‌ای از توابع است. 

حال من قصد دارم از تابعی درون آن DLL به صورت Explicit استفاده کنم، یعنی اینکه قرار نیست این کتابخانه توسط لینکر در زمان لینک به صورت خودکار به درون فایل Executable من ترسیم و در نهایت آدرس توابع ریزالو شود. 

تصور کنید، یک فایل DLL دارید که درون آن مثلا تابع Add وجود دارد (با Dependency Walker می‌توانید توابع اکسپورت شده یک DLL را مشاهده کنید)، چطور می‌توانید مستقیما این کتابخانه را در پروسه خود بارگذاری کنید و تابع آن را فراخوانی کنید؟

برای انجام این کار، شما از تابع LoadLibrary برای بارگذاری فایل Dll درون فضای آدرس پروسه خود استفاده می‌کنید، در گام بعد وقتی DLL با موفقیت به درون پروسه شما بارگذاری شد، آدرس تابع مورد نظر خود را در کتابخانه مذکور با تابع GetProcAddress به دست می‌آورید و در یک فانکشن پوینتر (Function Pointer) قرار می‌دهید که البته باید دارای سیگنیچر مشابه با تابع مورد فراخوانی باشد.

 به این نوع فراخوانی توابع درون کتابخانه‌های پیوندی ویندوز، فراخوانی Explicit گویند. فراخوانی Implicit هم که بسیار ساده است، کافی است فایل DLL را به درون پروژه خود Include کنید، و در گام بعد توابع آن را فراخوانی ‌کنید.

یک نکته دیگر، زمانی که شما به صورت Explicit تابعی را از درون یک DLL فراخوانی می‌کنید، باید نسبت به مسئله Export Forwarding هم کاملا آگاه باشید. 

خیلی مواقع شما در ویندوز به عنوان مثال یک API مانند EnterCriticalSection را از کتابخانه مثلا Kernel32.dll فراخوانی می‌کنید، که این کتابخانه ممکن است ntdll.dll را فراخوانی کرده باشد و API مورد نظر شما در حقیقت یک ورپر ساده برای RtlEnterCriticalSection درون ntdll.dll باشد.

لذا اگر این دو کتابخانه به درون پروسه ترسیم نشوند، برنامه شما در نهایت دچار مشکل خواهد شد. برای همین می‌گویند، بهتر است به صورت Implicit کتابخانه بارگذاری و توابع فراخوانی شوند. چون در این شرایط لینکر تمام کارها را خودکار انجام می‌دهد و در حالت کلی برنامه Robust خواهد بود. 

در مورد مبحث Delay Load Dll هم در یک پست دیگر صحبت خواهم کرد. در مثال پایین، پیاده‌سازی استانداردسازی شده کد (مثال) بالا را مشاهده می‌کنید. 

@miladkahsarialhadi