مقدمه

خیلی وقت‌ها پیش میاد که برنامه‌ای رو اجرا می‌کنیم اما به دلیل اینکه یه فایلی وجود نداره درست اجرا نمیشه، یا مثلا یه برنامه‌ای رو با محیط‌هایی مثل Visual Studio یا QT Creator نوشتیم ولی فقط وقتی از داخل همون محیط اجراش می‌کنیم اجرا میشه و وقتی فایل EXE خروجی رو کپی می‌کنیم توی یه مسیر دیگه، درست اجرا نمیشه و خطاهایی میده که نشون از عدم وجود بعضی فایل‌ها داره.

تو اکثر مواقع این فایل‌ها، فایل‌های DLL هستن که وقتی از محیط‌هایی مثل QT Creator اجرا میشن، چون خود اون محیط آدرس درست این فایل‌ها رو داره، میره و از همون آدرس اونا رو صدا میزنه ولی وقتی ما فایل خروجی خودمون رو جا به جا می‌کنیم دیگه موقع اجرا، فایل ما نمیدونه کجا دنبال این وابستگی‌ها بگرده.

خب شاید تو مرحله اول راه درست این باشه که بریم و نحوه درست Deploy کردن نرم‌افزار روی پلتفرم نهایی مثلا ویندوز رو بخونیم و راه اصولیشو بریم ولی همیشه هم اینطور نیست و بعضی وقت‌ها پیش میاد برنامه‌های دیگه‌ای که خودمون ننوشتیم به دستمون میرسه و این مشکل رو دارن.

واسه همین هم ابزارهایی ساخته شدن که بتونن کمکمون کنن. یکی از معروف‌ترین‌ها Dependency Walker هست که میتونه فایل‌هایی که برنامه بهش وابسته هست رو نشون بده.

این ابزار میتونه از جدول ایستای مربوط به فایل‌های DLL/EXE ، فایل‌ها مربوطه رو بخونه و نشون بده، که این خودش خوبه اما کافی نیست. چون ممکنه برنامه‌ها حین اجرا به صورت داینامیک یه DLL رو فراخونی کنن. به خاطر همین هم این ابزار یه قابلیتی داره به اسم Profiling که میتونه این مشکل رو هم رفع کنه.

تو این یادداشت میخوام آموزش هر دو قسمت رو بنویسم. منبع اصلی این آموزش هم پایگاه مدیریت دانش QT هست.

البته بجز ابزار Dependency Walker ابزار دیگه‌ای به اسم Process Monitor وجود داره که اون هم به شدت تو این زمینه قویه و میشه بدون دانش تخصصی زیاد ازش استفاده کرد. نحوه استفاده از اون ابزار توی یادداشت آنالیز جزئیات رفتار نرم‌افزارها با Process Monitor اومده.

البته ابزار راحت‌تری هم هست به اسم Process Explorer که اندازه Process Monitor قوی نیست ولی کار باهاش خیلی راحت‌تره و گرافیک ساده‌ای داره. آموزشش توی یادداشت نمایش لیست DLL های لود شده در یک پروسس با Process Explorer اومده.

بجز این ابزار، ابزار بسیار قوی‌تری به اسم Windbg هست که دانش تخصصی بیشتری لازم داره و امکانات بسیار بسیار بیشتری در اختیار کاربر میذاره. استفاده از این نرم‌افزار نیاز به آموزش‌های خیلی قوی‌تری داره.

خب با این توضیحات بریم سراغ Dependency Walker: طبق تعریف خود سایت سازنده، این ابزار یک ابزار رایگان برای اسکن هر ماژول ویندوزی 32 یا 64 (شامل exe، dll، ocx، sys و …) میشه که یه دیاگرام درختی سلسله مراتبی از همه ماژول‌های وابسته میسازه.

این ابزار حتی امکان شناسایی اینکه چه کامپایلری (و در بعضی موارد چه ورژنی از اون کامپایلر) برای کامپایل کردن استفاده شده رو هم نشون میده.

تحلیل ایستا

با اجرای برنامه پنجره زیر نمایش داده می‌شود

سپس از منوی File > Open فایل هدف را باز کنید.

[!صرفا جهت اطلاع] ممکنه موقع باز کردن Dependency Walker یه پنجره دیالوگی مبنی بر خطای پردازش، نشون بده که میتونین نادیده بگیرینش

همونجور که تو تصویر بالا مشخصه، بعد از باز کردن فایل هدف، وابستگی‌ها توی چند لایه لیست میشن. برای اینکه دید بهتری داشته باشیم میتونیم لایه‌های زیرین رو ببندیم و فقط لایه اول باقی بمونه:

اینجا میتونیم کاری کنیم که مسیر کامل اون وابستگی نمایش داده بشه تا مطمئن شیم داره از فایل درستی استفاده می‌کنه (مثلا از ورژن قدیمی DLL که توی یه مسیر دیگه‌ست استفاده نمی‌کنه). برای فعالسازی این قابلیت روی هر کدوم کلیک راست می‌کنیم و Full Paths رو انتخاب می‌کنیم:

تا به این شکل در بیان:

به این صورت می‌تونیم وابستگی‌های برنامه رو بررسی و در صورت نیاز عیب‌یابی کنیم.

در ضمن خروجی این گزارش میتونه ذخیره بشه و مثلا برای فرد متخصص دیگه‌ای برای بررسی ارسال بشه به این صورت:

بررسی ایمپورت‌های گم‌شده (Missing Imports) و سمبل‌های ایمپورت شده

اطلاعات مربوط به ایمپورت‌های گم‌شده در قسمت “Parent Import Function List View” قابل رویته:

از اونجایی که اسکرول کردن بین این همه گزینه میتونه کار سخت و زمانبری باشه راه بهترش اینه که از طریق File > Save as خروجی رو توی یه فایل txt ذخیره کنیم و با یه ادیتور خوب مثل Notepad++ بازش کنیم چون حجمش زیاده:

بعد اسم یکی از ماژول‌هایی که گم‌شده و علامت زرد یا قرمز کنارش بوده و رو سرچ کنیم از روی علامت‌هایی که کنارش نوشته شده مثل “[CE ]” یا “[E+]” و از این قبیل علائم، دنبال موارد مشابه بگردیم.

از این طریق میتونیم ساده‌تر به مواردی که گم شدن دست پیدا کنیم.

آنالیز زنده (Runtime analysis) / Profiling

برای آنالیز زنده یا همون آنالیز زمان اجرا به این طریق اقدام می‌کنیم:

  • فایل .exe مربوط به رو از طریق File > Open لود می‌کنیم
  • از منوی Profiling بر روی Start Profiling کلیک می‌کنیم.

برای راهنمایی بیشتر به یادداشت استفاده از Profiling در Dependency Walker جهت یافتن وابستگی‌های داینامیک مراجعه کنین.

تشخیص کامپایلر

وابستگی‌های مستقیم یک فایل اجرایی (DLLهایی که مستقیماً توسط فایل اجرایی استفاده میشن) می‌تونن نشون بدن که برنامه با کدوم کامپایلر (و گاهی با کدوم نسخه از آن کامپایلر) ساخته شده است: به عنوان مثال :

VersionCompilerDependent DLL
n/aMinGWMINGWM10.DLL
MSVC6, Visual C++/Studio 6MSVC6MSVCRT.DLL
MSVC9, Visual Studio 2008MSVC7MSVCRT7.DLL
MSVC8, Visual Studio 2005MSVC8MSVCR8.DLL
MSVC9, Visual Studio 2008MSVC9MSVCR9.DLL
MSVC10, Visual Studio 2010MSVC10MSVCRT10.DLL
بنابراین با بررسی اینکه به کدوم DLL وابسته هست میشه فهمید با چه ابزار و محیطی ساخته شده.

یافتن اطلاعات

اطلاعات مختلفی از طریق Dependency Walker قابل استخراجه از جمله :

مورد #1 کتابخانه‌های زمان اجرای کامپایلر (Runtime Libraries of Compiler) - این بخش می‌تونه بگه برنامه با کدوم نسخه از کامپایلر ساخته شده، مثلاً MSVC6، MSVC7، MSVC8، MSVC9، MSVC10 و غیره. مورد #1 نوع بیلد - آیا برنامه به صورت Release ساخته شده یا Debug؟
معمولاً اگه Debug باشه، یه “d” به انتهای اسم فایل‌های DLL مربوط به Qt اضافه می‌شه، مثل QT5CORED.DLL یا DLLهای runtime ویژوال سی‌پلاس‌پلاس مثل MSVCP90D.DLL.

برای مثلا اگه می‌خوای برنامه‌ی Qt رو به صورت Debug بیلد کنی، باید نسخه Debug بسته‌ی Squish for Qt رو هم داشته باشی.

مورد #2 سیمبل‌های اکسپورت‌شده مثلاً اگه بعد از انتخاب QtCore4.dll ببینی که QObject::setName(...) داخلش لیست شده، یعنی کتابخانه Qt با ماژول Qt3Support فعال شده و کانفیگ شده.

مورد #3 اندازه Word: اگه x86 نوشته باشه یعنی برنامه ۳۲ بیتی هست،
و اگه x64 باشه یعنی ۶۴ بیتی.

مورد #4 ورژن فایل مربوطه مثلا در عکس مربوطه، ورژن مربوطه به کتابخانه QT ذکر شده است.