ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.3 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://xakep.ru/2025/09/10/done-ex-reverse/ |
| Last Crawled | 2026-03-29 18:51:07 (8 days ago) |
| First Indexed | 2025-09-10 15:43:44 (6 months ago) |
| HTTP Status Code | 200 |
| Meta Title | Ломаный Excel. Обходим защиту VBA-скриптов в DoneEx Compiler — Хакер |
| Meta Description | null |
| Meta Canonical | null |
| Boilerpipe Text | Сегодня мы разберемся с тем, как устроена «непробиваемая» защита VBA-скриптов в Excel, предлагаемая компилятором DoneEx VBA Compiler. Мы посмотрим, как этот инструмент компилирует макросы в нативные DLL, какие трюки использует для контроля целостности, и шаг за шагом покажем, как обходить проверки и восстанавливать исходный код из скомпилированных модулей.
Ты, вероятно, обращал внимание на забавный эффект: как только нуб выучит какой‑нибудь простецкий язык в достаточной степени, чтобы самому писать скрипты, его охватывает всепоглощающее чувство собственного величия, переходящее в желание продавать свои поделки окружающим. Этому обычно сопутствует опасение, как бы эту бесценную интеллектуальную собственность не украли. Ничего плохого в этом нет, поскольку такой страх дает работу целому сегменту программистов, пишущих защиты для скриптов разной степени упоротости.
Я уже писал статьи про подобные защиты, разработанные на JavaScript, Python, PHP и даже AutoIT. Сегодня у меня наконец‑то дошли руки до темы защиты экселевских VBA-скриптов.
Недавно я наткнулся на известный в очень узких кругах компилятор
DoneEx VBA Compiler
. Он позиционируется ни много ни мало, как полноценный компилятор Excel VBA в нативный код со встроенной защитой. Сразу предупреждаю: это поделие достаточно кривое — лично мне, чтобы скомпилировать на нем хоть какой‑то более‑менее работоспособный пример, понадобилось гораздо больше времени, чем разобраться, как снимать саму защиту. Однако ее описание изобилует громкими претенциозными заявлениями вроде «код VBA не может быть скопирован или восстановлен и имеет самый высокий уровень защиты от пиратства». Давай попробуем оспорить это утверждение.
К слову сказать, эти ребята еще и
«компилятор» электронных книг XLS в EXE-модуль запилили
, который, правда, без установленного Excel не запускается, но это совсем другая история, которой мы сегодня касаться не будем.
Итак, предположим, что нам в руки попал необычный экселевский файл. К нему прилагается одна (или две) DLL-библиотека с тем же именем, но возможны суффиксы
*_64
или
*_32
в зависимости от разрядности. Если натравить на них Detect It Easy, программа показывает компилятор
MinGW(
GCC: (
GNU)
)
, однако ординалы из них экспортируются довольно подозрительные.
Попробуем открыть защищенный документ. На экране появляется весьма раздражающее окно с бегущим ползунком, а затем выскакивает предложение о регистрации.
Пока оно висит, откроем наш любимый отладчик x64dbg и приаттачимся к процессу Excel. Принудительно прервав его выполнение, мы видим занятный стек вызовов.
Из него как на ладони видна последовательность вызовов, порождающих это окно. Вначале непосредственно из VBA-кода вызывается функция
SetThisWorkbook
, экспортируемая из нашей скомпилированной библиотеки
testvba1_xlsm_64.
dll
. Эта функция вызывает функцию
DummyFunc05
некоей загадочной библиотеки
cbinrtl.
dll
, отсутствующей в каталоге макроса и вообще непонятно откуда взявшейся. А уже она выкидывает окно предупреждения, реализованное через функцию
DialogBoxIndirectParamW
.
При детальном рассмотрении мы обнаруживаем эту библиотеку в подкаталоге
v6n3vk66ej
(название при каждом вызове случайное) временной папки Windows. Скомпилированный модуль
testvba1_xlsm_64.
dll
сохраняет ее туда из соответствующего собственного ресурса при вызове
SetThisWorkbook
, а затем подчищает за собой при отработке. Собственно, скомпилированный модуль практически целиком и состоит из библиотеки
cbinrtl.
dll
, хранящейся в нем в явном незашифрованном виде, так же как и в самом модуле компилятора
vbaclr4e.
exe
, от которого ее и получает. Это дает надежду на убиение двух зайцев патчем файла
testvba1_xlsm_64.
dll
— можно патчить код и библиотеки
testvba1_xlsm_64.
dll
, и порождаемой ею библиотеки
cbinrtl.
dll
.
Попробуем это реализовать. Сразу напрашивается гипотеза, что защита сосредоточена в функции
DummyFunc05
, — ведь именно ее вызов и выводит сообщение о незарегистрированной версии. Однако ее нельзя просто так взять и закоротить — Excel при этом падает с ошибкой. При ближайшем рассмотрении мы видим ее вызовы в IDA. Почему так происходит? Эта функция заполняет некую жизненно важную для программы структуру
qword_62FC9180
.
Значит, придется копать вглубь кода
DummyFunc05
, благо основные вызовы у нас уже размечены на стеке. Довольно быстро мы натыкаемся на развилку в коде
cbinrtl.
dll
, которая ведет к заполнению структуры
qword_62FC9180
(на следующем скриншоте она обозначена как
a2
, поскольку передается вторым параметром в процедуру).
Функция
sub_180047A20
в незарегистрированной версии выкидывает окна c предупреждениями, однако, если скомпилировать модуль без защиты, эта функция просто возвращает 1 без лишних слов. Если в отладчике закоротить ее на
return
1
, все тоже работает безо всяких предупреждений, но при попытке патча модуля
testvba1_xlsm_64.
dll
нас ждет сюрприз. Находим во вложенном в файл
testvba1_xlsm_64.
dll
модуле
cbinrtl.
dll
место, соответствующее
sub_180047A20
, и патчим его нужным образом.
Однако патченный файл упорно отказывается загружаться, хотя, как я уже говорил, при патче непосредственно в отладчике все работает корректно. Налицо встроенный контроль целостности. Попробуем его открутить.
Первое, что бросается в глаза, — проверка 128-битного хеша SHA-1 непосредственно перед загрузкой
cbinrtl.
dll
. Обрати внимание на верхнюю часть скриншота — загрузка модуля происходит только тогда, когда функция
sub_62FC28D4
дает добро.
Внутри она реализована так.
Функция
sub_62FC27F7
читает весь модуль,
sub_62FC2095
считает его хеш, который затем сравнивается с тестовым значением при помощи memcmp (его возвращает
sub_62FC1720
). Эту проверку легко можно закоротить, однако ей дело не ограничивается. Если мы это сделаем, то модуль
cbinrtl.
dll
загружается, патченная функция
DummyFunc05
корректно отрабатывает, однако в самом конце
SetThisWorkbook
вылетает по эксепшену при вызове некоего безымянного callback из того же
cbinrtl.
dll
.
В непатченном варианте указатель на функцию
qword_62FC90B0
содержит совершенно другой адрес, который отрабатывает нормально. Помнишь, в начале нашего повествования я упоминал некую жизненно важную структуру
qword_62FC9180
, заполняемую в
DummyFunc05
? Она как раз и содержит этот адрес и, если модуль пропатчен, заполняется некорректно. Разработчики решили поумничать и максимально запутать этот путь, но мы хитрее их и поэтому поищем обходную тропинку.
Нам известно, что существует как минимум еще одна проверка целостности, помимо
sub_62FC28D4
, которая заново перечитывает файл
cbinrtl.
dll
(все данные, считанные функцией
sub_62FC28D4
, остаются локально внутри нее). Поэтому мы сразу по отработке
sub_62FC28D4
ставим точку останова на ядерную функцию
ReadFile
, и — о чудо! — она тут же срабатывает на новом чтении файла
cbinrtl.
dll
. Снова смотрим на стек вызовов.
Очень интересно: выходит, на этот раз новорожденная
cbinrtl.
dll
перепроверяет сама себя на невинность. Двигаясь по стеку вызовов вверх, мы обнаруживаем саму процедуру подсчета хеша.
На скриншоте функция
cbinrtl.
7FF9985145B0
возвращает в регистре
RAX
адрес указателя на 512-битный хеш Whirlpool от модуля
cbinrtl.
dll
(выделен в дампе). В этом случае запатчить проверку не так просто, в отличие от предыдущего случая, где хеши тупо сравнивались при помощи
memcmp
. Разработчики решили заморочиться по максимуму, проделывая над полученным хешем множество мудреных манипуляций, которые в итоге и приводят к неочевидному перемешиванию данных в структуре
qword_62FC9180
. |
| Markdown | 
Временная скидка 60% [на годовую подписку](https://xakep.ru/about-magazine/)\!
[Вход](https://xakep.ru/login)
## [](https://xakep.ru/)
- [Взлом](https://xakep.ru/category/hack/)
- [Приватность](https://xakep.ru/category/privacy/)
- [Трюки](https://xakep.ru/category/tricks/)
- [Кодинг](https://xakep.ru/category/coding/)
- [Админ](https://xakep.ru/category/admin/)
- [Geek](https://xakep.ru/category/geek/)
- [Магазин](https://xakep.shop/)
[Подписаться на материалы](https://xakep.ru/wp-admin/users.php?page=paywall_subscribes&from=paywall_subscribe&subscribe=12_months)
- [Windows](https://xakep.ru/tag/windows/)
- [Linux](https://xakep.ru/tag/linux/)
- [Android](https://xakep.ru/tag/android/)
- [Железо](https://xakep.ru/tag/zhelezo/)
- [Python](https://xakep.ru/tag/python/)
- [AI](https://xakep.ru/tag/iskusstvennyj-intellekt/)
- [Новичкам](https://xakep.ru/tag/knowledge/)
- [Кибердипломатия](https://bit.ly/4sktxG2)
- [Все выпуски «Хакера»](https://xakep.ru/issues/xa/)
- [Реклама на «Хакере»](https://xakep.shop/advert)
Выпуски
[ Годовая подписка на **Хакер** ](https://xakep.ru/about)
\-60%
[](https://xakep.ru/issues/xa/323)
Хакер \#323. Беспроводной самопал
[](https://xakep.ru/issues/xa/322)
Хакер \#322. Белый хакер
[](https://xakep.ru/issues/xa/321)
Хакер \#321. Железо для хешкрекинга
[](https://xakep.ru/issues/xa/320)
Хакер \#320. Королевство граблей
[](https://xakep.ru/issues/xa/319)
Хакер \#319. Атаки на банкоматы
[Взлом](https://xakep.ru/category/hack/)
[Ломаный Excel. Обходим защиту VBA-скриптов в DoneEx Compiler](https://xakep.ru/2025/09/10/done-ex-reverse/)
[JaboHack](https://xakep.ru/author/jabohack/ "Записи JaboHack")
10\.09.2025
[Комментарии](https://xakep.ru/2025/09/10/done-ex-reverse/#postbottom)
7,535

[](https://cyber-ed.ru/apentester-hacker/?utm_source=hacker_tab&utm_medium=hacker&utm_campaign=hacker_50k&erid=2SDnjdo2JvT) [](https://bit.ly/4r3wuJ3)
Сегодня мы разберемся с тем, как устроена «непробиваемая» защита VBA-скриптов в Excel, предлагаемая компилятором DoneEx VBA Compiler. Мы посмотрим, как этот инструмент компилирует макросы в нативные DLL, какие трюки использует для контроля целостности, и шаг за шагом покажем, как обходить проверки и восстанавливать исходный код из скомпилированных модулей.
Ты, вероятно, обращал внимание на забавный эффект: как только нуб выучит какой‑нибудь простецкий язык в достаточной степени, чтобы самому писать скрипты, его охватывает всепоглощающее чувство собственного величия, переходящее в желание продавать свои поделки окружающим. Этому обычно сопутствует опасение, как бы эту бесценную интеллектуальную собственность не украли. Ничего плохого в этом нет, поскольку такой страх дает работу целому сегменту программистов, пишущих защиты для скриптов разной степени упоротости.
Я уже писал статьи про подобные защиты, разработанные на JavaScript, Python, PHP и даже AutoIT. Сегодня у меня наконец‑то дошли руки до темы защиты экселевских VBA-скриптов.
Недавно я наткнулся на известный в очень узких кругах компилятор [DoneEx VBA Compiler](https://vbacompiler.com/). Он позиционируется ни много ни мало, как полноценный компилятор Excel VBA в нативный код со встроенной защитой. Сразу предупреждаю: это поделие достаточно кривое — лично мне, чтобы скомпилировать на нем хоть какой‑то более‑менее работоспособный пример, понадобилось гораздо больше времени, чем разобраться, как снимать саму защиту. Однако ее описание изобилует громкими претенциозными заявлениями вроде «код VBA не может быть скопирован или восстановлен и имеет самый высокий уровень защиты от пиратства». Давай попробуем оспорить это утверждение.
К слову сказать, эти ребята еще и [«компилятор» электронных книг XLS в EXE-модуль запилили](https://doneex.com/excel-compiler/), который, правда, без установленного Excel не запускается, но это совсем другая история, которой мы сегодня касаться не будем.
Итак, предположим, что нам в руки попал необычный экселевский файл. К нему прилагается одна (или две) DLL-библиотека с тем же именем, но возможны суффиксы `*_64` или `*_32` в зависимости от разрядности. Если натравить на них Detect It Easy, программа показывает компилятор `MinGW(GCC: (GNU))`, однако ординалы из них экспортируются довольно подозрительные.

Попробуем открыть защищенный документ. На экране появляется весьма раздражающее окно с бегущим ползунком, а затем выскакивает предложение о регистрации.

Пока оно висит, откроем наш любимый отладчик x64dbg и приаттачимся к процессу Excel. Принудительно прервав его выполнение, мы видим занятный стек вызовов.

Из него как на ладони видна последовательность вызовов, порождающих это окно. Вначале непосредственно из VBA-кода вызывается функция `SetThisWorkbook`, экспортируемая из нашей скомпилированной библиотеки `testvba1_xlsm_64.dll`. Эта функция вызывает функцию `DummyFunc05` некоей загадочной библиотеки `cbinrtl.dll`, отсутствующей в каталоге макроса и вообще непонятно откуда взявшейся. А уже она выкидывает окно предупреждения, реализованное через функцию `DialogBoxIndirectParamW`.
При детальном рассмотрении мы обнаруживаем эту библиотеку в подкаталоге `v6n3vk66ej` (название при каждом вызове случайное) временной папки Windows. Скомпилированный модуль `testvba1_xlsm_64.dll` сохраняет ее туда из соответствующего собственного ресурса при вызове `SetThisWorkbook`, а затем подчищает за собой при отработке. Собственно, скомпилированный модуль практически целиком и состоит из библиотеки `cbinrtl.dll`, хранящейся в нем в явном незашифрованном виде, так же как и в самом модуле компилятора `vbaclr4e.exe`, от которого ее и получает. Это дает надежду на убиение двух зайцев патчем файла `testvba1_xlsm_64.dll` — можно патчить код и библиотеки `testvba1_xlsm_64.dll`, и порождаемой ею библиотеки `cbinrtl.dll`.
Попробуем это реализовать. Сразу напрашивается гипотеза, что защита сосредоточена в функции `DummyFunc05`, — ведь именно ее вызов и выводит сообщение о незарегистрированной версии. Однако ее нельзя просто так взять и закоротить — Excel при этом падает с ошибкой. При ближайшем рассмотрении мы видим ее вызовы в IDA. Почему так происходит? Эта функция заполняет некую жизненно важную для программы структуру `qword_62FC9180`.

Значит, придется копать вглубь кода `DummyFunc05`, благо основные вызовы у нас уже размечены на стеке. Довольно быстро мы натыкаемся на развилку в коде `cbinrtl.dll`, которая ведет к заполнению структуры `qword_62FC9180` (на следующем скриншоте она обозначена как `a2`, поскольку передается вторым параметром в процедуру).

Функция `sub_180047A20` в незарегистрированной версии выкидывает окна c предупреждениями, однако, если скомпилировать модуль без защиты, эта функция просто возвращает 1 без лишних слов. Если в отладчике закоротить ее на `return 1`, все тоже работает безо всяких предупреждений, но при попытке патча модуля `testvba1_xlsm_64.dll` нас ждет сюрприз. Находим во вложенном в файл `testvba1_xlsm_64.dll` модуле `cbinrtl.dll` место, соответствующее `sub_180047A20`, и патчим его нужным образом.

Однако патченный файл упорно отказывается загружаться, хотя, как я уже говорил, при патче непосредственно в отладчике все работает корректно. Налицо встроенный контроль целостности. Попробуем его открутить.
Первое, что бросается в глаза, — проверка 128-битного хеша SHA-1 непосредственно перед загрузкой `cbinrtl.dll`. Обрати внимание на верхнюю часть скриншота — загрузка модуля происходит только тогда, когда функция `sub_62FC28D4` дает добро.

Внутри она реализована так.

Функция `sub_62FC27F7` читает весь модуль, `sub_62FC2095` считает его хеш, который затем сравнивается с тестовым значением при помощи memcmp (его возвращает `sub_62FC1720`). Эту проверку легко можно закоротить, однако ей дело не ограничивается. Если мы это сделаем, то модуль `cbinrtl.dll` загружается, патченная функция `DummyFunc05` корректно отрабатывает, однако в самом конце `SetThisWorkbook` вылетает по эксепшену при вызове некоего безымянного callback из того же `cbinrtl.dll`.

В непатченном варианте указатель на функцию `qword_62FC90B0` содержит совершенно другой адрес, который отрабатывает нормально. Помнишь, в начале нашего повествования я упоминал некую жизненно важную структуру `qword_62FC9180`, заполняемую в `DummyFunc05`? Она как раз и содержит этот адрес и, если модуль пропатчен, заполняется некорректно. Разработчики решили поумничать и максимально запутать этот путь, но мы хитрее их и поэтому поищем обходную тропинку.
Нам известно, что существует как минимум еще одна проверка целостности, помимо `sub_62FC28D4`, которая заново перечитывает файл `cbinrtl.dll` (все данные, считанные функцией `sub_62FC28D4`, остаются локально внутри нее). Поэтому мы сразу по отработке `sub_62FC28D4` ставим точку останова на ядерную функцию `ReadFile`, и — о чудо! — она тут же срабатывает на новом чтении файла `cbinrtl.dll`. Снова смотрим на стек вызовов.

Очень интересно: выходит, на этот раз новорожденная `cbinrtl.dll` перепроверяет сама себя на невинность. Двигаясь по стеку вызовов вверх, мы обнаруживаем саму процедуру подсчета хеша.

На скриншоте функция `cbinrtl.7FF9985145B0` возвращает в регистре `RAX` адрес указателя на 512-битный хеш Whirlpool от модуля `cbinrtl.dll` (выделен в дампе). В этом случае запатчить проверку не так просто, в отличие от предыдущего случая, где хеши тупо сравнивались при помощи `memcmp`. Разработчики решили заморочиться по максимуму, проделывая над полученным хешем множество мудреных манипуляций, которые в итоге и приводят к неочевидному перемешиванию данных в структуре `qword_62FC9180`.
### Продолжение доступно только участникам
#### Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! [Подробнее](https://xakep.ru/subscribe/)
#### Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
[Я уже участник «Xakep.ru»](https://xakep.ru/login/) ![]()
[](https://xakep.ru/author/jabohack/)
### [JaboHack](https://xakep.ru/author/jabohack/)
Теги:[DoneEx](https://xakep.ru/tag/doneex/)[Excel](https://xakep.ru/tag/excel/)[VBA](https://xakep.ru/tag/vba/)[Выбор редактора](https://xakep.ru/tag/vybor-redaktora/)[Реверс](https://xakep.ru/tag/revers/)[Реверс-инжиниринг](https://xakep.ru/tag/revers-inzhiniring/)[Статьи](https://xakep.ru/tag/articles/)
#### Check Also
## [Белый хакер. Глава 23. Пентест](https://xakep.ru/2026/03/28/white-hacker-23/)
Настоящая работа хакера начинается даже не с включения компьютера, а с понимания того непр…
[← Ранее Уязвимость Adobe Commerce и Magento позволяет захватить контроль над учетными записями](https://xakep.ru/2025/09/10/sessionreaper/)
[Далее → Бывший сотрудник WhatsApp: 1500 инженеров имели доступ к личной информации пользователей](https://xakep.ru/2025/09/10/baig-lawsuit/)

[Подпишись на наc в Telegram\!](https://t.me/xakep_ru)
Только важные новости и лучшие статьи
[Подписаться](https://t.me/xakep_ru)
[Открыть комментарии](https://xakep.ru/2025/09/10/done-ex-reverse/#respond)
Подписаться
[авторизуйтесь](https://xakep.ru/login/?redirect_to=https%3A%2F%2Fxakep.ru%2F2025%2F09%2F10%2Fdone-ex-reverse%2F)
Пожалуйста, войдите, чтобы прокомментировать
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Загрузить ещё комментарии
Вопросы по материалам и подписке: [support@glc.ru](mailto:support@glc.ru)
Отдел рекламы и спецпроектов: [yakovleva.a@glc.ru](mailto:yakovleva.a@glc.ru)
Контент **18+**
[](https://qrator.net/ru/) Сайт защищен Qrator —
самой забойной защитой от DDoS в мире
[Подписка для физлиц](https://xakep.ru/about-magazine/)
[Подписка для юрлиц](https://xakep.shop/corporate)
[Реклама на «Хакере»](https://xakep.shop/advert)
[Контакты](https://xakep.ru/contact/)
wpDiscuz
Insert |
| Readable Markdown | Сегодня мы разберемся с тем, как устроена «непробиваемая» защита VBA-скриптов в Excel, предлагаемая компилятором DoneEx VBA Compiler. Мы посмотрим, как этот инструмент компилирует макросы в нативные DLL, какие трюки использует для контроля целостности, и шаг за шагом покажем, как обходить проверки и восстанавливать исходный код из скомпилированных модулей.
Ты, вероятно, обращал внимание на забавный эффект: как только нуб выучит какой‑нибудь простецкий язык в достаточной степени, чтобы самому писать скрипты, его охватывает всепоглощающее чувство собственного величия, переходящее в желание продавать свои поделки окружающим. Этому обычно сопутствует опасение, как бы эту бесценную интеллектуальную собственность не украли. Ничего плохого в этом нет, поскольку такой страх дает работу целому сегменту программистов, пишущих защиты для скриптов разной степени упоротости.
Я уже писал статьи про подобные защиты, разработанные на JavaScript, Python, PHP и даже AutoIT. Сегодня у меня наконец‑то дошли руки до темы защиты экселевских VBA-скриптов.
Недавно я наткнулся на известный в очень узких кругах компилятор [DoneEx VBA Compiler](https://vbacompiler.com/). Он позиционируется ни много ни мало, как полноценный компилятор Excel VBA в нативный код со встроенной защитой. Сразу предупреждаю: это поделие достаточно кривое — лично мне, чтобы скомпилировать на нем хоть какой‑то более‑менее работоспособный пример, понадобилось гораздо больше времени, чем разобраться, как снимать саму защиту. Однако ее описание изобилует громкими претенциозными заявлениями вроде «код VBA не может быть скопирован или восстановлен и имеет самый высокий уровень защиты от пиратства». Давай попробуем оспорить это утверждение.
К слову сказать, эти ребята еще и [«компилятор» электронных книг XLS в EXE-модуль запилили](https://doneex.com/excel-compiler/), который, правда, без установленного Excel не запускается, но это совсем другая история, которой мы сегодня касаться не будем.
Итак, предположим, что нам в руки попал необычный экселевский файл. К нему прилагается одна (или две) DLL-библиотека с тем же именем, но возможны суффиксы `*_64` или `*_32` в зависимости от разрядности. Если натравить на них Detect It Easy, программа показывает компилятор `MinGW(GCC: (GNU))`, однако ординалы из них экспортируются довольно подозрительные.

Попробуем открыть защищенный документ. На экране появляется весьма раздражающее окно с бегущим ползунком, а затем выскакивает предложение о регистрации.

Пока оно висит, откроем наш любимый отладчик x64dbg и приаттачимся к процессу Excel. Принудительно прервав его выполнение, мы видим занятный стек вызовов.

Из него как на ладони видна последовательность вызовов, порождающих это окно. Вначале непосредственно из VBA-кода вызывается функция `SetThisWorkbook`, экспортируемая из нашей скомпилированной библиотеки `testvba1_xlsm_64.dll`. Эта функция вызывает функцию `DummyFunc05` некоей загадочной библиотеки `cbinrtl.dll`, отсутствующей в каталоге макроса и вообще непонятно откуда взявшейся. А уже она выкидывает окно предупреждения, реализованное через функцию `DialogBoxIndirectParamW`.
При детальном рассмотрении мы обнаруживаем эту библиотеку в подкаталоге `v6n3vk66ej` (название при каждом вызове случайное) временной папки Windows. Скомпилированный модуль `testvba1_xlsm_64.dll` сохраняет ее туда из соответствующего собственного ресурса при вызове `SetThisWorkbook`, а затем подчищает за собой при отработке. Собственно, скомпилированный модуль практически целиком и состоит из библиотеки `cbinrtl.dll`, хранящейся в нем в явном незашифрованном виде, так же как и в самом модуле компилятора `vbaclr4e.exe`, от которого ее и получает. Это дает надежду на убиение двух зайцев патчем файла `testvba1_xlsm_64.dll` — можно патчить код и библиотеки `testvba1_xlsm_64.dll`, и порождаемой ею библиотеки `cbinrtl.dll`.
Попробуем это реализовать. Сразу напрашивается гипотеза, что защита сосредоточена в функции `DummyFunc05`, — ведь именно ее вызов и выводит сообщение о незарегистрированной версии. Однако ее нельзя просто так взять и закоротить — Excel при этом падает с ошибкой. При ближайшем рассмотрении мы видим ее вызовы в IDA. Почему так происходит? Эта функция заполняет некую жизненно важную для программы структуру `qword_62FC9180`.

Значит, придется копать вглубь кода `DummyFunc05`, благо основные вызовы у нас уже размечены на стеке. Довольно быстро мы натыкаемся на развилку в коде `cbinrtl.dll`, которая ведет к заполнению структуры `qword_62FC9180` (на следующем скриншоте она обозначена как `a2`, поскольку передается вторым параметром в процедуру).

Функция `sub_180047A20` в незарегистрированной версии выкидывает окна c предупреждениями, однако, если скомпилировать модуль без защиты, эта функция просто возвращает 1 без лишних слов. Если в отладчике закоротить ее на `return 1`, все тоже работает безо всяких предупреждений, но при попытке патча модуля `testvba1_xlsm_64.dll` нас ждет сюрприз. Находим во вложенном в файл `testvba1_xlsm_64.dll` модуле `cbinrtl.dll` место, соответствующее `sub_180047A20`, и патчим его нужным образом.

Однако патченный файл упорно отказывается загружаться, хотя, как я уже говорил, при патче непосредственно в отладчике все работает корректно. Налицо встроенный контроль целостности. Попробуем его открутить.
Первое, что бросается в глаза, — проверка 128-битного хеша SHA-1 непосредственно перед загрузкой `cbinrtl.dll`. Обрати внимание на верхнюю часть скриншота — загрузка модуля происходит только тогда, когда функция `sub_62FC28D4` дает добро.

Внутри она реализована так.

Функция `sub_62FC27F7` читает весь модуль, `sub_62FC2095` считает его хеш, который затем сравнивается с тестовым значением при помощи memcmp (его возвращает `sub_62FC1720`). Эту проверку легко можно закоротить, однако ей дело не ограничивается. Если мы это сделаем, то модуль `cbinrtl.dll` загружается, патченная функция `DummyFunc05` корректно отрабатывает, однако в самом конце `SetThisWorkbook` вылетает по эксепшену при вызове некоего безымянного callback из того же `cbinrtl.dll`.

В непатченном варианте указатель на функцию `qword_62FC90B0` содержит совершенно другой адрес, который отрабатывает нормально. Помнишь, в начале нашего повествования я упоминал некую жизненно важную структуру `qword_62FC9180`, заполняемую в `DummyFunc05`? Она как раз и содержит этот адрес и, если модуль пропатчен, заполняется некорректно. Разработчики решили поумничать и максимально запутать этот путь, но мы хитрее их и поэтому поищем обходную тропинку.
Нам известно, что существует как минимум еще одна проверка целостности, помимо `sub_62FC28D4`, которая заново перечитывает файл `cbinrtl.dll` (все данные, считанные функцией `sub_62FC28D4`, остаются локально внутри нее). Поэтому мы сразу по отработке `sub_62FC28D4` ставим точку останова на ядерную функцию `ReadFile`, и — о чудо! — она тут же срабатывает на новом чтении файла `cbinrtl.dll`. Снова смотрим на стек вызовов.

Очень интересно: выходит, на этот раз новорожденная `cbinrtl.dll` перепроверяет сама себя на невинность. Двигаясь по стеку вызовов вверх, мы обнаруживаем саму процедуру подсчета хеша.

На скриншоте функция `cbinrtl.7FF9985145B0` возвращает в регистре `RAX` адрес указателя на 512-битный хеш Whirlpool от модуля `cbinrtl.dll` (выделен в дампе). В этом случае запатчить проверку не так просто, в отличие от предыдущего случая, где хеши тупо сравнивались при помощи `memcmp`. Разработчики решили заморочиться по максимуму, проделывая над полученным хешем множество мудреных манипуляций, которые в итоге и приводят к неочевидному перемешиванию данных в структуре `qword_62FC9180`. |
| Shard | 176 (laksa) |
| Root Hash | 8590548565581247576 |
| Unparsed URL | ru,xakep!/2025/09/10/done-ex-reverse/ s443 |