🕷️ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 176 (from laksa110)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

📄
INDEXABLE
CRAWLED
8 days ago
🤖
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.3 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://xakep.ru/2025/09/10/done-ex-reverse/
Last Crawled2026-03-29 18:51:07 (8 days ago)
First Indexed2025-09-10 15:43:44 (6 months ago)
HTTP Status Code200
Meta TitleЛоманый Excel. Обходим защиту VBA-скриптов в DoneEx Compiler — Хакер
Meta Descriptionnull
Meta Canonicalnull
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
![](https://mc.yandex.ru/watch/88149838) Временная скидка 60% [на годовую подписку](https://xakep.ru/about-magazine/)\! [Вход](https://xakep.ru/login) ## [![Хакер](https://xakep.ru/wp-content/uploads/2018/09/x-new_6.png)](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/wp-content/plugins/xakep-core/images/xakep_logo_w.png) Годовая подписка на **Хакер** ![/](https://xakep.ru/wp-content/plugins/xakep-core/images/issue-stub.png)](https://xakep.ru/about) \-60% [![](https://xakep.ru/wp-content/uploads/2026/03/568998/323-1-210x280.jpg)](https://xakep.ru/issues/xa/323) Хакер \#323. Беспроводной самопал [![](https://xakep.ru/wp-content/uploads/2026/03/565658/322-210x280.jpg)](https://xakep.ru/issues/xa/322) Хакер \#322. Белый хакер [![](https://xakep.ru/wp-content/uploads/2026/01/563542/321-210x280.jpg)](https://xakep.ru/issues/xa/321) Хакер \#321. Железо для хешкрекинга [![](https://xakep.ru/wp-content/uploads/2026/01/561287/320-210x280.jpg)](https://xakep.ru/issues/xa/320) Хакер \#320. Королевство граблей [![](https://xakep.ru/wp-content/uploads/2025/12/559382/319-210x280.jpg)](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://xakep.ru/wp-content/uploads/2025/09/557771/done-ex-reverse.jpg) [![CyberED](https://static.xakep.ru/advert/2025/092025-xakep-cybered.jpeg)](https://cyber-ed.ru/apentester-hacker/?utm_source=hacker_tab&utm_medium=hacker&utm_campaign=hacker_50k&erid=2SDnjdo2JvT) [![Reverse Engeneering](https://static.xakep.ru/advert/2026/reverse-300x600-2.jpg)](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))`, одна­ко орди­налы из них экспор­тиру­ются доволь­но подоз­ритель­ные. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43240/1.jpg) Поп­робу­ем открыть защищен­ный документ. На экра­не появ­ляет­ся весь­ма раз­дра­жающее окно с бегущим пол­зунком, а затем выс­какива­ет пред­ложение о регис­тра­ции. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43241/2.jpg) По­ка оно висит, откро­ем наш любимый отладчик x64dbg и при­атта­чим­ся к про­цес­су Excel. При­нуди­тель­но прер­вав его выпол­нение, мы видим занят­ный стек вызовов. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43242/3.jpg) Из него как на ладони вид­на пос­ледова­тель­ность вызовов, порож­дающих это окно. Вна­чале непос­редс­твен­но из 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`. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43243/4.jpg) Зна­чит, при­дет­ся копать вглубь кода `DummyFunc05`, бла­го основные вызовы у нас уже раз­мечены на сте­ке. Доволь­но быс­тро мы натыка­емся на раз­вилку в коде `cbinrtl.dll`, которая ведет к запол­нению струк­туры `qword_62FC9180` (на сле­дующем скрин­шоте она обоз­начена как `a2`, пос­коль­ку переда­ется вто­рым парамет­ром в про­цеду­ру). ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43244/5.jpg) Фун­кция `sub_180047A20` в незаре­гис­три­рован­ной вер­сии выкиды­вает окна c пре­дуп­режде­ниями, одна­ко, если ском­пилиро­вать модуль без защиты, эта фун­кция прос­то воз­вра­щает 1 без лиш­них слов. Если в отладчи­ке закоро­тить ее на `return 1`, все тоже работа­ет безо вся­ких пре­дуп­режде­ний, но при попыт­ке пат­ча модуля `testvba1_xlsm_64.dll` нас ждет сюр­приз. Находим во вло­жен­ном в файл `testvba1_xlsm_64.dll` модуле `cbinrtl.dll` мес­то, соот­ветс­тву­ющее `sub_180047A20`, и пат­чим его нуж­ным обра­зом. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43245/6.jpg) Од­нако пат­ченный файл упор­но отка­зыва­ется заг­ружать­ся, хотя, как я уже говорил, при пат­че непос­редс­твен­но в отладчи­ке все работа­ет кор­рек­тно. Налицо встро­енный кон­троль целос­тнос­ти. Поп­робу­ем его откру­тить. Пер­вое, что бро­сает­ся в гла­за, — про­вер­ка 128-бит­ного хеша SHA-1 непос­редс­твен­но перед заг­рузкой `cbinrtl.dll`. Обра­ти вни­мание на вер­хнюю часть скрин­шота — заг­рузка модуля про­исхо­дит толь­ко тог­да, ког­да фун­кция `sub_62FC28D4` дает доб­ро. ![](https://static.xakep.ru/images/20f0fa7d0d25abc14a1269d3d92c42c2/43279/4-1.jpg) Внут­ри она реали­зова­на так. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43246/7.jpg) Фун­кция `sub_62FC27F7` чита­ет весь модуль, `sub_62FC2095` счи­тает его хеш, который затем срав­нива­ется с тес­товым зна­чени­ем при помощи memcmp (его воз­вра­щает `sub_62FC1720`). Эту про­вер­ку лег­ко мож­но закоро­тить, одна­ко ей дело не огра­ничи­вает­ся. Если мы это сде­лаем, то модуль `cbinrtl.dll` заг­ружа­ется, пат­ченная фун­кция `DummyFunc05` кор­рек­тно отра­баты­вает, одна­ко в самом кон­це `SetThisWorkbook` вылета­ет по эксепше­ну при вызове неко­его безымян­ного callback из того же `cbinrtl.dll`. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43247/8.jpg) В непат­ченном вари­анте ука­затель на фун­кцию `qword_62FC90B0` содер­жит совер­шенно дру­гой адрес, который отра­баты­вает нор­маль­но. Пом­нишь, в начале нашего повес­тво­вания я упо­минал некую жиз­ненно важ­ную струк­туру `qword_62FC9180`, запол­няемую в `DummyFunc05`? Она как раз и содер­жит этот адрес и, если модуль про­пат­чен, запол­няет­ся некор­рек­тно. Раз­работ­чики решили поум­ничать и мак­сималь­но запутать этот путь, но мы хит­рее их и поэто­му поищем обходную тро­пин­ку. Нам извес­тно, что сущес­тву­ет как минимум еще одна про­вер­ка целос­тнос­ти, помимо `sub_62FC28D4`, которая заново перечи­тыва­ет файл `cbinrtl.dll` (все дан­ные, счи­тан­ные фун­кци­ей `sub_62FC28D4`, оста­ются локаль­но внут­ри нее). Поэто­му мы сра­зу по отра­бот­ке `sub_62FC28D4` ста­вим точ­ку оста­нова на ядер­ную фун­кцию `ReadFile`, и — о чудо! — она тут же сра­баты­вает на новом чте­нии фай­ла `cbinrtl.dll`. Сно­ва смот­рим на стек вызовов. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43248/9.jpg) Очень инте­рес­но: выходит, на этот раз новорож­денная `cbinrtl.dll` переп­роверя­ет сама себя на невин­ность. Дви­гаясь по сте­ку вызовов вверх, мы обна­ружи­ваем саму про­цеду­ру под­сче­та хеша. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43249/10.jpg) На скрин­шоте фун­кция `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://secure.gravatar.com/avatar/ddd3d5d5f81158dc46bbb3c98a2ce0f757adeb495f5e4c01530435a0ed821658?s=150&d=retro&r=g)](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/) ![](https://static.xakep.ru/assets/tlg-up-01.png) [Подпишись на на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+** [![Qrator](https://xakep.ru/wp-content/themes/woohoo/images/curator-logo.svg)](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))`, одна­ко орди­налы из них экспор­тиру­ются доволь­но подоз­ритель­ные. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43240/1.jpg) Поп­робу­ем открыть защищен­ный документ. На экра­не появ­ляет­ся весь­ма раз­дра­жающее окно с бегущим пол­зунком, а затем выс­какива­ет пред­ложение о регис­тра­ции. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43241/2.jpg) По­ка оно висит, откро­ем наш любимый отладчик x64dbg и при­атта­чим­ся к про­цес­су Excel. При­нуди­тель­но прер­вав его выпол­нение, мы видим занят­ный стек вызовов. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43242/3.jpg) Из него как на ладони вид­на пос­ледова­тель­ность вызовов, порож­дающих это окно. Вна­чале непос­редс­твен­но из 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`. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43243/4.jpg) Зна­чит, при­дет­ся копать вглубь кода `DummyFunc05`, бла­го основные вызовы у нас уже раз­мечены на сте­ке. Доволь­но быс­тро мы натыка­емся на раз­вилку в коде `cbinrtl.dll`, которая ведет к запол­нению струк­туры `qword_62FC9180` (на сле­дующем скрин­шоте она обоз­начена как `a2`, пос­коль­ку переда­ется вто­рым парамет­ром в про­цеду­ру). ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43244/5.jpg) Фун­кция `sub_180047A20` в незаре­гис­три­рован­ной вер­сии выкиды­вает окна c пре­дуп­режде­ниями, одна­ко, если ском­пилиро­вать модуль без защиты, эта фун­кция прос­то воз­вра­щает 1 без лиш­них слов. Если в отладчи­ке закоро­тить ее на `return 1`, все тоже работа­ет безо вся­ких пре­дуп­режде­ний, но при попыт­ке пат­ча модуля `testvba1_xlsm_64.dll` нас ждет сюр­приз. Находим во вло­жен­ном в файл `testvba1_xlsm_64.dll` модуле `cbinrtl.dll` мес­то, соот­ветс­тву­ющее `sub_180047A20`, и пат­чим его нуж­ным обра­зом. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43245/6.jpg) Од­нако пат­ченный файл упор­но отка­зыва­ется заг­ружать­ся, хотя, как я уже говорил, при пат­че непос­редс­твен­но в отладчи­ке все работа­ет кор­рек­тно. Налицо встро­енный кон­троль целос­тнос­ти. Поп­робу­ем его откру­тить. Пер­вое, что бро­сает­ся в гла­за, — про­вер­ка 128-бит­ного хеша SHA-1 непос­редс­твен­но перед заг­рузкой `cbinrtl.dll`. Обра­ти вни­мание на вер­хнюю часть скрин­шота — заг­рузка модуля про­исхо­дит толь­ко тог­да, ког­да фун­кция `sub_62FC28D4` дает доб­ро. ![](https://static.xakep.ru/images/20f0fa7d0d25abc14a1269d3d92c42c2/43279/4-1.jpg) Внут­ри она реали­зова­на так. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43246/7.jpg) Фун­кция `sub_62FC27F7` чита­ет весь модуль, `sub_62FC2095` счи­тает его хеш, который затем срав­нива­ется с тес­товым зна­чени­ем при помощи memcmp (его воз­вра­щает `sub_62FC1720`). Эту про­вер­ку лег­ко мож­но закоро­тить, одна­ко ей дело не огра­ничи­вает­ся. Если мы это сде­лаем, то модуль `cbinrtl.dll` заг­ружа­ется, пат­ченная фун­кция `DummyFunc05` кор­рек­тно отра­баты­вает, одна­ко в самом кон­це `SetThisWorkbook` вылета­ет по эксепше­ну при вызове неко­его безымян­ного callback из того же `cbinrtl.dll`. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43247/8.jpg) В непат­ченном вари­анте ука­затель на фун­кцию `qword_62FC90B0` содер­жит совер­шенно дру­гой адрес, который отра­баты­вает нор­маль­но. Пом­нишь, в начале нашего повес­тво­вания я упо­минал некую жиз­ненно важ­ную струк­туру `qword_62FC9180`, запол­няемую в `DummyFunc05`? Она как раз и содер­жит этот адрес и, если модуль про­пат­чен, запол­няет­ся некор­рек­тно. Раз­работ­чики решили поум­ничать и мак­сималь­но запутать этот путь, но мы хит­рее их и поэто­му поищем обходную тро­пин­ку. Нам извес­тно, что сущес­тву­ет как минимум еще одна про­вер­ка целос­тнос­ти, помимо `sub_62FC28D4`, которая заново перечи­тыва­ет файл `cbinrtl.dll` (все дан­ные, счи­тан­ные фун­кци­ей `sub_62FC28D4`, оста­ются локаль­но внут­ри нее). Поэто­му мы сра­зу по отра­бот­ке `sub_62FC28D4` ста­вим точ­ку оста­нова на ядер­ную фун­кцию `ReadFile`, и — о чудо! — она тут же сра­баты­вает на новом чте­нии фай­ла `cbinrtl.dll`. Сно­ва смот­рим на стек вызовов. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43248/9.jpg) Очень инте­рес­но: выходит, на этот раз новорож­денная `cbinrtl.dll` переп­роверя­ет сама себя на невин­ность. Дви­гаясь по сте­ку вызовов вверх, мы обна­ружи­ваем саму про­цеду­ру под­сче­та хеша. ![](https://static.xakep.ru/images/7a0a1756c2391769250196290c4a725c/43249/10.jpg) На скрин­шоте фун­кция `cbinrtl.7FF9985145B0` воз­вра­щает в регис­тре `RAX` адрес ука­зате­ля на 512-бит­ный хеш Whirlpool от модуля `cbinrtl.dll` (выделен в дам­пе). В этом слу­чае запат­чить про­вер­ку не так прос­то, в отли­чие от пре­дыду­щего слу­чая, где хеши тупо срав­нивались при помощи `memcmp`. Раз­работ­чики решили заморо­чить­ся по мак­симуму, про­делы­вая над получен­ным хешем мно­жес­тво муд­реных манипу­ляций, которые в ито­ге и при­водят к неоче­вид­ному переме­шива­нию дан­ных в струк­туре `qword_62FC9180`.
Shard176 (laksa)
Root Hash8590548565581247576
Unparsed URLru,xakep!/2025/09/10/done-ex-reverse/ s443