На чому ти написана, радість моя?.

Коли бачиш добре, і навіть не просто добре, чудово зроблену програму, теж виникає бажання дізнатися, як саме вона розроблена. І якщо з open-source програмами це не становить жодних труднощів, то зробити це у випадку комерційних розробок - велика проблема.


Частина перша. Шпигуємо за віконними класами

Скажіть, будь ласка, у Вас ніколи не виникало бажання у ресторані дізнатися рецепт сильно сподобався Вам страви? Питали? І що у відповідь? "Ах, не можна? Яка жалість! Ну тоді хоча б скажіть інгредієнти ... Що, серйозно, тільки цибуля, картопля і майонез?! Не може бути ..."

Коли бачиш добре, і навіть не просто добре, чудово зроблену програму, теж виникає бажання дізнатися, як саме вона розроблена. І якщо з open-source програмами це не становить жодних труднощів, то зробити це у випадку комерційних розробок - велика проблема. Втім, кожен програміст знає, що існують такі речі, як отладчики і дизасемблери. З їх допомогою будь-яку програму, написану для платформи Windows, можна представити у вигляді ассемблерних кодів. Дія це відносно чужих програм не вітається, і навіть, скажімо прямо, є караним відповідно до міжнародного законодавства. Хоча хіба це зупинить одержимого цікавістю дослідника? .. Та й не будь-яку програму вийде так "розкласти по базису": якщо написана вона, наприклад, на Java, то звичайним Windows-дизассемблером її не візьмеш. Те ж стосується і тих програм, які створені для платформи Microsoft. NET Framework.

Втім, не завжди є сенс дослідити програму детально, з дизассемблирования. Іноді просто цікаво дізнатися, за допомогою якого кошти вона розроблена. І саме цим ми сьогодні з вами і займемося - будемо пробувати дізнаватися, на чому написана та чи інша програма. Способів визначити це, не порушуючи закон, існує велика кількість.

Сьогодні ми розглянемо тільки один спосіб розпізнавання інструменту, за допомогою якого створено програму. Тільки один тільки з-за обмежень в обсязі, властивому газетних статтях. Я назвав би його "шпигує за віконними класами". Він, звичайно, не ідеальний, оскільки застосовується лише до тих програм, які мають стандартний користувальницький інтерфейс Windows. Якщо програма запускається в консольному режимі (тобто не має графічного інтерфейсу як такого), то цей спосіб не спрацює. Якщо інтерфейс програми оформлюється з допомогою т. зв. "Скінів", то спосіб теж працює не завжди.

Кожен елемент керування, будь то вікно, кнопка, панель інструментів або що-небудь ще, при створенні реєструється в системі. При цьому він отримує унікальний дескриптор (handle), який потрібний для того, щоб програма могла точно встановити, з яким саме елементом управління користувач в даний момент взаємодіє. При реєстрації вікна (а з точки зору системи кнопка таке ж вікно, як і те вікно, на якому вона розташована) завжди вказується назва віконного класу цього елемента керування. Це зазначається саме для того, щоб відрізняти кнопку від панелі завдань, а панель завдань - від рядка пошуку в Internet Explorer. При цьому, як відомо, більшість програм використовують інтерфейс, створений за допомогою спеціалізованих бібліотек. Таких бібліотек багато - VCL, MFC, Windows Forms ... Кожна з них має свої особливості іменування таких класів. Саме цією властивістю графічного інтерфейсу Windows-додатків ми і скористаємося.

Отже, приступимо до досліджень. По-перше, нам потрібен якийсь інструмент для того, щоб дізнаватися імена віконних класів тих чи інших елементів управління. Такі інструменти є, і їх існує не так вже й мало, проте я зазначу лише два, від самих популярних виробників - Microsoft Spy + +, що входить до складу Visual Studio, і Borland WinSight, що входить в постачання Delphi і C + + Builder. Особисто я працював саме з WinSight (його можна знайти в папці DELPHI \ BIN \ WS32.EXE), і, відповідно, розповідь буде саме про нього. Втім, Spy + + працює аналогічно, і щоб розібратися з ним, достатньо лише деякий час уважно почитати довідку.

Подивіться на скріншот, де видно зовнішній вигляд WinSight. Верхня половина вікна цієї утиліти - дерево віконних елементів управління, зареєстрованих на поточний момент в системі. Там відображаються всі вікна, а не тільки ті, які видно користувачеві, у тому числі всі системні. Тому, власне кажучи, їх там і так багато. Нижня половина - черга повідомлень Windows, які відносяться до виділеного у верхній половині вікна, втім, зараз нас нижня половина не надто цікавить. У зв'язку з великою кількістю вікон у дереві виникає проблема: як дізнатися в списку саме те вікно, яке нас в даний момент цікавить? Робити вручну це не завжди просто, тому краще скористатися вбудованими в WinSight можливостями. Для цього в меню "Spy" потрібно вибрати (відмітити галочкою) пункт "Follow Focus". Тепер, коли він відзначений, досить зробити активним на екрані потрібне вікно, а після переключитися на WinSight по комбінації клавіш Alt + Tab. WinSight самостійно виділить в дереві потрібне вікно, так що нам залишається лише дослідити його.

Інформація про вікно в WinSight представлена ??в наступному вигляді: Tree Handle {Class} Module Position "Title". Tree - це ідентифікатор типу вікна: Icon і Overlapped - головне вікно, Child і Popup - йому підлеглі. Handle - це той самий унікальний дескриптор, який отримує віконний елемент при реєстрації в системі. Він представлений у вигляді числа в шістнадцятковій формі запису (наприклад, 004201DA). Class, який записаний у фігурних дужках, це і є той самий віконний клас, заради якого і робиться вся це катавасія. Module - ім'я виконуваного файлу, до якого відноситься дане вікно, Position - екранні координати вікна, а Title - заголовок вікна. Але нас, як я вже говорив, цікавить зараз в першу чергу атрибут Class.

Тепер давайте візьмемо кілька програм і повивчати їх за допомогою WinSight. Особисто я вибрав кілька, свідомо написаних за допомогою різних бібліотек - Total Commander, NUnit, Microsoft HTML Help Workshop, WinRAR, QuickHTML Suite і Hexapad.

Головне вікно Total Commander має клас TTOTAL_CMD, а назви класів всіх дочірніх вікон починаються з префікса "T" (TDrivePanel, TButtonBar, TMyPanel, TComboBox). Як написано в довідці до Total Commander, "Total Commander розроблений з використанням Borland Delphi 1.0 (16 біт) і 2.0 (32 біт)". Тобто програми, розроблені з використання бібліотеки Visual Components Library (VCL), застосовуваної в Delphi, мають у назвах віконних класів префікс "T". На жаль, по одному цією ознакою ідентифікувати напевно мова розробки не вдасться, так як ця бібліотека використовується і при розробці програм у Borland C + + Builder. Програмісти, що використовують VCL, напевно, звернули увагу на те, що назва віконного класу збігається з назвою класу компонента в IDE.

Тепер давайте подивимося на Hexapad, розроблений також з використанням Delphi. Тільки замість VCL розробником застосовувалася KOL - альтернативна об'єктна бібліотека. Як видно, назви всіх віконних класів починаються з "obj_". Оскільки версії KOL для C + + Builder не існує, можна з упевненістю стверджувати при вигляді додатку, віконні класи елементів якого починаються з "obj_", що воно написано на Delphi.

А зараз, шановні, ми подивимося в сторону WinRAR. Віконні класи елементів управління цієї програми мають такі імена: WinRarWindow, ComboBoxEx32, ComboBox, Edit, ToolbarWindow32, msctls_statusbar32, SysListView32, SysHeader32 та ін Ті, хто коли-небудь працював з діалогами у вигляді ресурсів, знає, що більшість імен цих класів у точності відповідають визначеним у системі класам. Оскільки програмісту на Delphi або C + + Builder зазвичай немає необхідності використовувати прямо Windows API, то можна з певною часткою упевненості вважати, що ця програма написана на мові C + + без використання будь-яких сторонніх бібліотек (або, що менш імовірно, на Delphi, але без VCL ). Втім, як показує дослідження HTML Help Workshop, інтерфейс якого створений за допомогою Microsoft Foundation Classes (MFC), такі ж імена в класів будуть при використанні цієї бібліотеки. Втім, для додатків використовують MFC, і написаних, відповідно, за допомогою Microsoft Visual C + +, характерна наявність віконних класів, назви яких починається з "Afx". Хоча їх може і не бути - наприклад, в тому ж HTML Help Workshop таких класів набагато менше тих, що мають стандартні імена. І ще варто відзначити, що MFC можуть використовувати і розробники, що працюють з іншими компіляторами C + + і в інших середовищах розробки.

Так що в загальному випадку при зустрічі з подібними іменами класів (на кшталт msctls_statusbar32, SysListView32, BUTTON, EDIT і т. д.), нам стає ясно, що ... нічого, власне, і не ясно.




Трохи краще йдуть справи з додатками для. NET Framework. Я спеціально вибрав для розгляду NUnit, який точно написаний на C # і поставляється з вихідними текстами. До речі, саме його віконні класи в основному і потрапили на скріншот. Як бачите, вони мають вигляд "WindowsForms10.XXXXXXX". Частина після точки може бути будь-який, але це початок - "WindowsForms10" відмітна ознака. NET-додатків. Втім, питання про мову, за допомогою якого розроблено це програма, все одно залишається відкритим.

QuickHTML Suite написана на Visual Basic 6-ї версії. Відповідно WinSight показує безліч віконних класів даної програми, в імені яких міститься набір символів "RT6". Цей набір символів і можна вважати розпізнавальним для програм, створених за допомогою Visual Basic 6.

Такі от справи. Думаю, трохи "подлубавшись" з іншими середовищами розробки, можна з'ясувати, який відбиток накладають вони на віконні класи створюються за їх допомогою додатків. Проте, як бачите, цей метод дослідження програм має багато мінусів, серед яких - низька точність у виконанні програм, написаних на "голому" WinAPI або з використанням Microsoft Foundation Classes. Тому наступного разу я розповім про інші способи дослідження програм з метою з'ясувати, на чому вони були написані.

Частина друга. "Почерк" компілятора

У першій частині статті ми з вами, шановні читачі, намагалися з'ясувати, на чому написана та чи інша програма, аналізуючи назви віконних класів її елементів управління. І прийшли до висновку, що такий аналіз не відрізняється високою точністю результатів. Крім того, залишалося нез'ясованим питання про консольних програмах, DLL-файлах і ActiveX-елементах (OCX). Тому сьогодні ми продовжимо досліджувати виконувані файли на предмет з'ясування, яким саме засобом розробки користувалися програмісти при їх створенні.

Як відомо, всі програми для Windows існують у вигляді EXE або DLL-файлів. Всі інші типи (ті ж самі OCX, наприклад) представляють собою особливий різновид одного з цих двох. Будь-який 32-бітний виконуваний файл в цій операційній системі має формат PE, що значить Portable Executable. Portable ("Portable" - переносимий (англ.)) він у тому сенсі, що буде запускатися на будь-якому "залізі", на якому погодиться працювати Windows. Усередині PE-файлу знаходяться не тільки команди, які система передає процесору, але і сама різна службова інформація: використовувані DLL-бібліотеки, що містяться всередині COM і ActiveX-об'єкти, інформація про версії, різні ресурси - картинки, значки, таблиці рядків і інші використовувані програмою дані, звані в Windows ресурсами. Крім того, серед службової інформації записується версія компонувальника (програми, яка здійснює компонування машинних кодів у формат PE) і деякі інші відомості, які ми зможемо використовувати в нашому дослідженні.

Як і в першому дослідженні, нам знадобляться спеціалізовані інструменти. Їх в Інтернеті зустрічається чимало, але, переглянувши деякі з них, я прийшов до висновку, що більшість мало підходять для цілей, які ми переслідуємо в цій статті. А найбільш підходящим з них виявився FileInfo - плагін до Total Commander. Сподіваюся, любителі Far та інших файлових менеджерів не образяться?

Працювати з FileInfo дуже легко - достатньо завантажити його з сайту автора (розмір зовсім невеликий, нескладно буде скачати її навіть тим, у кого Dial-Up) і встановити. Тепер, виділивши у вікні Total Commander який-небудь виконуваний файл, натисніть F3, і перед Вами з'явиться точно таке вікно Lister'а, як те, яке Ви бачите на скріншоті до статті. Перша вкладка - інформація про версію файлу, друга - службова інформація, третя і четверта - дерево бібліотек і список використовуваних функцій кожної бібліотеки відповідно. Останні дві вкладки зараз не такі цікаві. Загалом-то, функціональність третьої і четвертої вкладок можна легко замінити утилітою Depends з Microsoft Visual Studio, але я все ж рекомендую завантажити і встановити FileInfo, оскільки в нашому сьогоднішньому дослідженні це - наш практично ідеальний помічник.

Хоча список динамічно підключаються бібліотек (DLL), що використовуються більшістю Windows-додатків, практично ідентичний, деякі нюанси все-таки присутні. Причому в ряді випадків ці самі нюанси можуть відразу видати компілятор, що породив цю програму. Наприклад, якщо в дереві використовуваних бібліотек (третя вкладка вікна FileInfo) зустрінеться MSVBVM60.DLL, знайте, що ця програма написана на Visual Basic 6. Відповідно, для п'ятої та четвертої версій цього середовища розробки назви бібліотек будуть MSVBVM50.DLL і MSVBVM40.DLL. Як відомо, програми, написані на Visual Basic, потребують наявності цієї DLL-бібліотеки, так як вони перетворюються компілятором не в машинний код безпосередньо, а в певний проміжний псевдокод (так званий P-Code), який і виконує віртуальна машина, що міститься в цієї DLL'ке.

До речі, Visual Basic 4, 5 і 6 - не єдині компілятори, яких видає список бібліотек, використаних програмою. Якщо в списку зустрінеться MFCxx.DLL, де xx - будь-які цифри, що позначають номер версії, знайте, що ця програма написана на Microsoft Visual C + +. Цей же компілятор (і, відповідно, однойменну середовище розробки) видає присутність бібліотеки MSVCRT.DLL. Втім, якщо з першою бібліотекою все однозначно, ніде, крім Visual C + +, MFC у вигляді DLL не використовується, то MSVCRT.DLL може використовуватися і програмами, скомпільований з допомогою MinGW Compiler System. Втім, мова (C + +) все одно визначається по присутності цієї бібліотеки однозначно.

Програми для Microsoft. NET Framework містять у списку використовуваних бібліотек одну-єдину MSCOREE.DLL, однак, яким чином визначити, що за компілятор цю програму згенерував, я поки що не придумав.

Досліджуючи EXE-файли, Ви, може бути, помітили, що вони, на відміну від DLL, як правило, не експортують ніяких функцій, тобто список внизу вікна при активній четвертої вкладці FileInfo залишається порожнім. Так буває завжди, але далеко не завжди. Самі програмісти практично ніколи не додають функції, що експортуються в EXE-файл, тому що знають, що система сама не дозволить звернутися до них з іншої програми - для експорту існують DLL-бібліотеки. Однак є компілятор, який завжди додає в збирану програму таблицю експорту. Це Borland C + +. Подивіться на скріншот (або відкрийте в FileInfo файл WinRAR.EXE). У списку експортованих функцій знаходиться дві _CPPDebugHook і _GetExceptDLLInfo. Першу функцію Borland C + + додає завжди і у всі файли. У більш старих версіях компілятора вона називається _DebuggerHookData. Друга зустрічається не у всіх файлах, створених за допомогою Borland C + +, а лише починаючи з 5-ї версії цього компілятора. Причому, як Ви, можливо, пам'ятаєте, досліджуючи віконні класи WinRAR, ми прийшли до висновку, що інтерфейс його написаний на MFC або з використанням "чистого" Windows API. Список експортованих функцій це підтверджує. Справа в тому, що для програм, створених з використанням VCL, кількість експортованих функцій нерідко становить кілька тисяч. Переглянувши їх імена, можна зробити висновок, що компілятор додає методи всіх використовуваних класів і компонентів VCL. Відбувається це, по всій видимості, внаслідок спільної роботи компіляторів мов Delphi (Object Pascal) і C + + при розробці програм з використанням VCL в середовищі Borland C + + Builder.

Сам Delphi виявити складніше, оскільки ніяких автоматично експортуються функцій компілятор не додає і ніякими додатковими DLL-бібліотеками програму не навантажує. Можна, звичайно, встановити, що написана програма саме на Delphi, комбінуючи дослідження віконних класів з вивченням списку експортованих функцій, проте можна не кликати на допомогу WinSight або Spy + +, обійшовшись тільки FileInfo. Для цього потрібно перейти у вікні FileInfo на другу від початку вкладку і вивчити вміст поля Time Date Stamp в групі "FILE HEADER" (виділено темним на скріншоті). Перевірено, що для всіх програм, написаних на Delphi версій з другої по десяту значення цього поля дорівнює "2A425E19h -> 20/06/1992 1:22:17". Здійснити контрольну перевірку можна за значенням поля Linker Version з групи OPTIONAL HEADER: для програм, написаних на Delphi, воно завжди дорівнює 2.25.

На жаль чи на щастя, але набором Visual Basic, Visual C + +, Borland Delphi і Borland C + + різноманіття сучасних компіляторів не обмежується. Хоча для Windows це найпоширеніші компілятори, цілком можна зіткнутися і з тим, що зацікавила Вас програма створена з використанням якого-небудь менш популярного в наші дні засоби. Дуже просто.