Хакер - Сны Фемиды. Ломаем виртуальную машину Themida

Хакер - Сны Фемиды. Ломаем виртуальную машину Themida

hacker_frei

https://t.me/hacker_frei

МВК

Themida счи­тает­ся одним из самых слож­ных инс­тру­мен­тов защиты прог­рамм от нелицен­зион­ного копиро­вания — не толь­ко из‑за обфуска­ции и наворо­чен­ных механиз­мов анти­отладки, но и из‑за широко­го исполь­зования вир­туали­зации. В пре­дыду­щей статье мы узна­ли, как сбро­сить три­ал в защищен­ной Themida прог­рамме. Теперь нас­тало вре­мя поковы­рять­ся в ее вир­туаль­ной машине.

WARNING

Статья име­ет озна­коми­тель­ный харак­тер и пред­назна­чена для спе­циалис­тов по безопас­ности, про­водя­щих тес­тирова­ние в рам­ках кон­трак­та. Автор и редак­ция не несут ответс­твен­ности за любой вред, при­чинен­ный с при­мене­нием изло­жен­ной информа­ции. Рас­простра­нение вре­донос­ных прог­рамм, наруше­ние работы сис­тем и наруше­ние тай­ны перепис­ки прес­леду­ются по закону.

В прош­лых стать­ях я уже упо­минал об одной очень злов­редной осо­бен­ности серь­езных про­тек­торов: что­бы осложнить жизнь хакерам, раз­работ­чики обфусци­руют кри­тичес­кие учас­тки ском­пилиро­ван­ного кода в мак­рокоман­ды вир­туаль­ной машины, щед­ро раз­бавлен­ные ловуш­ками и безум­ным кодом. При таком рас­кла­де объ­ем кода может уве­личи­вать­ся в тысячи раз, делая реверс чудовищ­но слож­ным. Вдо­бавок его мож­но делать мутиру­ющим, реали­зуя одну и ту же коман­ду сот­нями раз­ных спо­собов. Мы уже стал­кивались с подоб­ным в статье про Enigma, теперь поп­робу­ем разоб­рать более слож­ный спо­соб вир­туали­зации на при­мере сня­тия три­ала с одно­го из гра­фичес­ких пла­гинов.

Итак, усло­вия задачи: у нас есть 64-бит­ная биб­лиоте­ка, при­вязан­ная к опре­делен­ному озна­коми­тель­ному пери­оду. Халяв­ный сброс три­ала, методы которо­го я опи­сывал в пре­дыду­щих стать­ях, невоз­можен: при заг­рузке биб­лиоте­ка сту­чит­ся на сер­вер, который про­веря­ет текущую дату и дает доб­ро на запуск. При отсутс­твии соеди­нения прог­рамма прос­то не работа­ет. Код упа­кован и зашиф­рован, иссле­дова­нию в дизас­сем­бле­ре не под­лежит, но детек­торы не видят на нем никако­го извес­тно­го про­тек­тора. В общем, ситу­ация начина­ет слег­ка пугать.

Но мы не из пуг­ливых! Заг­ружа­ем прог­рамму в наш любимый отладчик x64dbg и при помощи опи­сан­ного мною в пре­дыду­щих стать­ях замеча­тель­ного пла­гина ScyllaHide под­бира­ем анти­анти­отла­доч­ную кон­фигура­цию (Themida). Теперь вклю­чаем уже опро­бован­ный нами в боях пла­гин Themidie и наконец получа­ем воз­можность поковы­рять­ся в рас­шифро­ван­ном и рас­пакован­ном коде (вклю­чая его трас­сиров­ку). Что­бы рас­шифро­ван­ный код было удоб­нее изу­чать, я сдам­пил его еще одним опи­сан­ным ранее пла­гином — Scylla. Если теперь мы заг­рузим сдам­плен­ный код в дизас­сем­блер IDA, то уви­дим при­мер­но такую кар­тину.

Cдам­плен­ный код в дизас­сем­бле­ре IDA

Бег­ло взгля­нув на кар­ту нашего модуля, мы уви­дим коротень­кую синюю полос­ку сле­ва. Она под­ска­зыва­ет, что в начале модуля сос­редото­чен нор­маль­ный вме­няемый код фун­кций, который по каким‑то при­чинам (обыч­но ско­рость исполне­ния) не под­вер­гся вир­туали­зации. Пес­трая полос­ка с пре­обла­дани­ем корич­невого цве­та спра­ва — шитый код вир­туаль­ной машины Themida, переме­жающий­ся обра­бот­чиками команд.

Поб­родив нем­ного отладчи­ком по деб­рям кода и слег­ка расс­тро­ившись, перехо­дим к более прог­рессив­ному методу работы. Поп­робу­ем отсле­дить и про­ана­лизи­ровать трас­су меж­ду вызыва­емы­ми невир­туали­зиро­ван­ными фун­кци­ями. В качес­тве отправ­ного пун­кта берем фун­кцию HTTP-зап­роса лицен­зии на сер­вер, бла­го она по понят­ным при­чинам не обфусци­рова­на. Ста­вим на нее точ­ку оста­нова и при ее дос­тижении жмем Ctrl-F9, выпол­няя фун­кцию до воз­вра­та в обра­бот­чик шитого кода, из которо­го она вызыва­ется.

На вхо­де обна­ружи­ваем такой огромный кусок бес­смыс­ленных команд, что его бес­полез­но пытать­ся прой­ти вруч­ную. Воз­ложим эту тяж­кую задачу на отладчик. Для это­го откро­ем вклад­ку «Трас­сиров­ка» (край­няя спра­ва) и пра­вой кноп­кой мыши выберем «Начать выпол­нение трас­сиров­ки». Затем для быс­тро­ты запус­каем трас­сиров­ку через Ctrl-Alt-F8 (трас­сиров­ка с обхо­дом). Памятуя о том, что невир­туали­зиро­ван­ный код находит­ся в сек­ции с мень­шими адре­сами, в качес­тве усло­вия оста­нов­ки ста­вим RIP до начала сек­ции, содер­жащей вир­туали­зиро­ван­ный код.

Ста­вим RIP до начала сек­ции, содер­жащей вир­туали­зиро­ван­ный код

В окне трас­сиров­ки шус­тро побежа­ли исполня­емые коман­ды, а вот и оста­нов­ка на сле­дующем вызове какой‑то фун­кции. Ого, нам пот­ребова­лась пара десят­ков тысяч шагов, что­бы пре­одо­леть про­межу­ток меж­ду ними! Это нас не пуга­ет: поп­робу­ем про­ана­лизи­ровать получен­ную трас­су.

Для начала нас инте­ресу­ет, каким обра­зом реали­зова­на псев­докоман­да вызова невир­туали­зиро­ван­ной фун­кции. В самом кон­це трас­сы находим такой учас­ток кода, соот­ветс­тву­юще­го обра­бот­чику вызова фун­кции и коду перехо­да на него от обра­бот­чика пре­дыду­щей псев­докоман­ды. Поп­робу­ем по нему понять прин­цип дей­ствия вир­туаль­ной машины:

33DC | 00007FFD071D113F | 48:89EF | mov rdi,rbp <--- RBP указывает на текущий фрейм кода

33DD | 00007FFD071D1142 | 48:81C7 36010000 | add rdi,136

33DE | 00007FFD071D1149 | 0907 | or dword ptr ds:[rdi],eax

33DF | 00007FFD071D114B | 48:25 FFFF0000 | and rax,FFFF <--- RAX 16-битный параметр текущей команды, представляющий собой

33E0 | 00007FFD071D1151 | 48:C1E0 03 | shl rax,3 <--- индекс в таблице 64-битных адресов обработчиков команд шитого кода

33E1 | 00007FFD071D1155 | 48:01C2 | add rdx,rax <--- базовый адрес, на который в RDX

33E2 | 00007FFD071D1158 | 4C:8B02 | mov r8,qword ptr ds:[rdx] <--- Элемент по этому индексу указывает на обработчик следующей команды, то есть 7FFD07011D20

33E3 | 00007FFD071D115B | 48:89EB | mov rbx,rbp

33E4 | 00007FFD071D115E | 48:81C3 EB000000 | add rbx,EB

33E5 | 00007FFD071D1165 | 48:8103 22000000 | add qword ptr ds:[rbx],22 <--- [RBP+EB] указатель на текущую команду шитого кода, ее размер был 22h байта, сдвинуть его на следующую команду

33E6 | 00007FFD071D116C | 41:FFE0 | jmp r8 <--- после чего перейти на ее обработчик

33E7 | 00007FFD07011D20 | 48:C7C2 00000000 | mov rdx,0

33E8 | 00007FFD07011D27 | 49:89E8 | mov r8,rbp

33E9 | 00007FFD07011D2A | 49:81C0 EB000000 | add r8,EB

33EA | 00007FFD07011D31 | 4D:8B00 | mov r8,qword ptr ds:[r8] <--- R8=[RBP+EB] указатель на новую команду шитого кода

33EB | 00007FFD07011D34 | 49:81C0 06000000 | add r8,6

33EC | 00007FFD07011D3B | 41:8B10 | mov edx,dword ptr ds:[r8] <--- В RDX 32-битный параметр псевдокоманды по смещению 6 байт

33ED | 00007FFD07011D3E | 48:89E9 | mov rcx,rbp

33EE | 00007FFD07011D41 | 48:81C1 01000000 | add rcx,1 <--- [RBP+1] <--- Базовый адрес модуля

33EF | 00007FFD07011D48 | 48:0311 | add rdx,qword ptr ds:[rcx] <--- Их сумма дает абсолютный адрес вызываемой функции в RDX

33F0 | 00007FFD07011D4B | 49:C7C6 00000000 | mov r14,0

33F1 | 00007FFD07011D52 | 49:89E8 | mov r8,rbp

33F2 | 00007FFD07011D55 | 49:81C0 EB000000 | add r8,EB

33F3 | 00007FFD07011D5C | 4D:8B00 | mov r8,qword ptr ds:[r8] <--- R8=[RBP+EB] указатель на текущую команду шитого кода

33F4 | 00007FFD07011D5F | 49:81C0 04000000 | add r8,4

33F5 | 00007FFD07011D66 | 6645:8B30 | mov r14w,word ptr ds:[r8] <--- В R14 16-битный параметр псевдокоманды по смещению 4 байта

33F6 | 00007FFD07011D6A | 49:01E6 | add r14,rsp <--- Это размер зарезервированного места в стеке под сохраненные регистры

33F7 | 00007FFD07011D6D | 49:8916 | mov qword ptr ds:[r14],rdx <--- Адрес вызываемой функции на стек для перехода

33F8 | 00007FFD07011D70 | 49:81C6 08000000 | add r14,8 <--- Место в стеке для адреса возврата из нее

33F9 | 00007FFD07011D77 | 48:C7C2 00000000 | mov rdx,0

33FA | 00007FFD07011D7E | 49:89E8 | mov r8,rbp

33FB | 00007FFD07011D81 | 49:81C0 EB000000 | add r8,EB

33FC | 00007FFD07011D88 | 4D:8B00 | mov r8,qword ptr ds:[r8] <--- R8=[RBP+EB] указатель на текущую команду шитого кода

33FD | 00007FFD07011D8B | 49:81C0 00000000 | add r8,0

33FE | 00007FFD07011D92 | 41:8B10 | mov edx,dword ptr ds:[r8] <--- В RDX 32-битный параметр псевдокоманды по смещению 0 байт

33FF | 00007FFD07011D95 | 48:89E8 | mov rax,rbp |

3400 | 00007FFD07011D98 | 48:05 01000000 | add rax,1 |

3401 | 00007FFD07011D9E | 48:0310 | add rdx,qword ptr ds:[rax] <--- [RBP+1] — базовый адрес модуля, их сумма дает

3402 | 00007FFD07011DA1 | 49:8916 | mov qword ptr ds:[r14],rdx <--- адрес возврата из вызываемой функции на стек

3403 | 00007FFD07011DA4 | 48:89EB | mov rbx,rbp

3404 | 00007FFD07011DA7 | 48:81C3 7F000000 | add rbx,7F

3405 | 00007FFD07011DAE | C703 00000000 | mov dword ptr ds:[rbx],0 <--- По всей видимости, [RBP+7F] флаг реентерабельности?

3406 | 00007FFD07011DB4 | 41:58 | pop r8

3407 | 00007FFD07011DB6 | 41:59 | pop r9

3408 | 00007FFD07011DB8 | 41:5A | pop r10

3409 | 00007FFD07011DBA | 41:5B | pop r11

340A | 00007FFD07011DBC | 41:5C | pop r12

340B | 00007FFD07011DBE | 41:5D | pop r13

340C | 00007FFD07011DC0 | 41:5E | pop r14

340D | 00007FFD07011DC2 | 41:5F | pop r15

340E | 00007FFD07011DC4 | 5F | pop rdi

340F | 00007FFD07011DC5 | 5E | pop rsi

3410 | 00007FFD07011DC6 | 5D | pop rbp

3411 | 00007FFD07011DC7 | 5B | pop rbx

3412 | 00007FFD07011DC8 | 5A | pop rdx

3413 | 00007FFD07011DC9 | 59 | pop rcx

3414 | 00007FFD07011DCA | 58 | pop rax

3415 | 00007FFD07011DCB | 9D | popfq

3416 | 00007FFD07011DCC | C2 0000 | ret 0 <--- Перейти к вызываемой функции

Итак, мы при­мер­но разоб­рали одну (из нес­коль­ких тысяч) коман­ду шитого кода Themida — вызов невир­туали­зиро­ван­ной фун­кции. Выг­лядит она при­мер­но так.

Вы­зов невир­туали­зиро­ван­ной фун­кции

Что же делать даль­ше? По‑хороше­му надо прой­тись по таб­лице адре­сов обра­бот­чиков вир­туаль­ных команд, бла­го она у нас есть, разоб­рать­ся, что дела­ет каж­дая из них, и «рас­пря­мить» наш безум­ный код. Одна­ко это путь не из при­ятных: команд ну очень мно­го, при­чем они мутиру­ют, то есть одна и та же коман­да может при­сутс­тво­вать в раз­ных вари­ациях.

Воз­можно, пос­ле все­го опи­сан­ного тебя уже не силь­но напуга­ет то, что в одном исполня­емом фай­ле может исполь­зовать­ся даже нес­коль­ко раз­ных мутиро­вав­ших вир­туаль­ных машин (раз­ные сис­темы команд с перес­тавлен­ными парамет­рами, дли­нами и так далее). Поэто­му для начала поп­робу­ем най­ти более корот­кий путь. Пос­коль­ку трас­са даже меж­ду дву­мя сосед­ними вызова­ми фун­кций получа­ется чудовищ­но длин­ной, попыта­емся залоги­ровать хотя бы сами эти вызовы. Обра­ти вни­мание, что регис­тры для сов­мести­мос­ти вро­де как сох­раня­ются в одном поряд­ке, поэто­му поищем код их сох­ранения (41 58 41 59 41 5A...). Наш­лось при­мер­но две сот­ни мутиро­ван­ных обра­бот­чиков вызова невир­туали­зиро­ван­ных фун­кций. Но рас­став­лять руками точ­ки оста­нова на них очень мутор­но, поэто­му пишем сле­дующий скрипт:

findallmem 0, "41584159415A415B415C415D415E415F5F5E5D5B5A59589DC20000"

mov i,0

loop:

cmp i, $result

je continue

bp ref.addr(i)+18

bpcnd ref.addr(i)+18, 0

bpl ref.addr(i)+18, "called from: "{rip}" called: "{[rsp]}" return to: "{[rsp+8]}" rsp: "{rsp}" PC: "{[mem.base(rip)+128EDDC+EB]}"

inc i

jmp loop

continue:

То есть мы ищем все мес­та в коде, где есть такая пос­ледова­тель­ность вос­ста­нов­ления регис­тров, и ста­вим на нее условную точ­ку оста­нова, логиру­ющую текущее сос­тояние вир­туаль­ной машины. Вол­шебное чис­ло 128EDDC получе­но эмпи­ричес­ки как сме­щение текуще­го фрей­ма отно­ситель­но базы модуля, а вол­шебное чис­ло EB — как сме­щение до прог­рам­мно­го счет­чика вир­туаль­ной машины из при­веден­ного выше фраг­мента кода. Пос­ле отра­бот­ки скрип­та получа­ем две сот­ни условных точек оста­нова, которые пишут в лог трас­су вызовов при­мер­но в таком виде:

called from: 7FFD069D8E12 called: 7FFD158B6D30 return to: 7FFD06B8067F rsp: 6B694FA710 PC: 7FFD06AE481F

called from: 7FFD069D8E12 called: 7FFD158B6DB0 return to: 7FFD06B807E5 rsp: 6B694FA710 PC: 7FFD06AE4A3C

called from: 7FFD06A8ACB5 called: 7FFD0507CB40 return to: 7FFD06B8094D rsp: 6B694FA710 PC: 7FFD06AE4BC3

called from: 7FFD069D8E12 called: 7FFD158B6EC0 return to: 7FFD06B80A70 rsp: 6B694FA710 PC: 7FFD06AE4DA6

called from: 7FFD0698CFB6 called: 7FFD158B6D30 return to: 7FFD06B80BC8 rsp: 6B694FA710 PC: 7FFD06AE506B

called from: 7FFD069E6E0F called: 7FFD158B6DB0 return to: 7FFD06B80D0C rsp: 6B694FA710 PC: 7FFD06AE5294

called from: 7FFD06A146C8 called: 7FFD0507CB60 return to: 7FFD06B80EB9 rsp: 6B694FA710 PC: 7FFD06AE542D

called from: 7FFD069D8E12 called: 7FFD158B6EC0 return to: 7FFD06B81002 rsp: 6B694FA710 PC: 7FFD06AE5616

called from: 7FFD0698CFB6 called: 7FFD158B6D30 return to: 7FFD06B8114F rsp: 6B694FA710 PC: 7FFD06AE58EB

called from: 7FFD0698CFB6 called: 7FFD158B6DB0 return to: 7FFD06B812C2 rsp: 6B694FA710 PC: 7FFD06AE5B0B

called from: 7FFD06AA94FE called: 7FFD0507CC60 return to: 7FFD06B8143D rsp: 6B694FA710 PC: 7FFD06AE5C9A

called from: 7FFD069E6E0F called: 7FFD158B6EC0 return to: 7FFD06B815EB rsp: 6B694FA710 PC: 7FFD06AE5E87

called from: 7FFD0698CFB6 called: 7FFD158B6D30 return to: 7FFD06B81741 rsp: 6B694FA710 PC: 7FFD06AE60CE

called from: 7FFD069E6E0F called: 7FFD158B6DB0 return to: 7FFD06B81875 rsp: 6B694FA710 PC: 7FFD06AE62DC

called from: 7FFD06A146C8 called: 7FFD0507CE60 return to: 7FFD06B819C5 rsp: 6B694FA710 PC: 7FFD06AE647E

called from: 7FFD069D8E12 called: 7FFD158B6EC0 return to: 7FFD06B81B3A rsp: 6B694FA710 PC: 7FFD06AE6679

called from: 7FFD06AA94FE called: 7FFD0506B620 return to: 7FFD06B81C91 rsp: 6B694FA710 PC: 7FFD06AE6874

called from: 7FFD069E6E0F called: 7FFD158B6D30 return to: 7FFD06B81DB7 rsp: 6B694FA710 PC: 7FFD06AE6A49

called from: 7FFD069E6E0F called: 7FFD158B6DB0 return to: 7FFD06B81F01 rsp: 6B694FA710 PC: 7FFD06AE6C6E

called from: 7FFD069E6E0F called: 7FFD158BE0D0 return to: 7FFD06B82060 rsp: 6B694FA710 PC: 7FFD06AE6E97

called from: 7FFD069E6E0F called: 7FFD158D0E50 return to: 7FFD06B821AE rsp: 6B694FA710 PC: 7FFD06AE7098

called from: 7FFD069D8E12 called: 7FFD158BDDB0 return to: 7FFD06B822C9 rsp: 6B694FA710 PC: 7FFD06AE725F

called from: 7FFD069D8E12 called: 7FFD158B6EC0 return to: 7FFD06B82405 rsp: 6B694FA710 PC: 7FFD06AE7446

called from: 7FFD069E6E0F called: 7FFD158B6D30 return to: 7FFD06B82569 rsp: 6B694FA710 PC: 7FFD06AE7633

called from: 7FFD0698CFB6 called: 7FFD158B6DB0 return to: 7FFD06B826D3 rsp: 6B694FA710 PC: 7FFD06AE7845

Ука­затель сте­ка мы про­веря­ем для кон­тро­ля вызовов вир­туали­зиро­ван­ных фун­кций, а в пос­ледней колон­ке содер­жится ука­затель на текущую исполня­емую коман­ду шитого кода. Два таких лога, запущен­ные со вклю­чен­ным и отклю­чен­ным интерне­том, дают нам воз­можность най­ти раз­вилку в шитом коде с точ­ностью до вызова невир­туали­зиро­ван­ной фун­кции.

Для более точ­ного нахож­дения раз­вилки нам при­дет­ся искать коман­ду условно­го опе­рато­ра и ее обра­бот­чик. С этой целью сно­ва пов­торя­ем пос­ледова­тель­ность дей­ствий, опи­сан­ную в начале этой статьи — оста­нав­лива­емся на пос­леднем вызове невир­туали­зиро­ван­ной фун­кции перед раз­вилкой и запус­каем более деталь­ную трас­сиров­ку при вклю­чен­ном и отклю­чен­ном интерне­те. При­дет­ся повозить­ся, срав­нивая ну очень длин­ные трас­сы, но в ито­ге мы находим обра­бот­чик условно­го опе­рато­ра. Реали­зация его чрез­вычай­но слож­на, нас­толь­ко, что тут нет мес­та, что­бы при­вес­ти ее пол­ностью. Да и смыс­ла никако­го в этом нет: код мутиру­ет и поч­ти ни один шаб­лон не дей­ству­ет.

Бо­лее того, злоб­ные кодеры из Oreans еще силь­нее усложни­ли нам жизнь, добавив в коман­ду допол­нитель­ный 8-бит­ный параметр. От его зна­чения зависит флаг, на который реаги­рует условный переход. И разуме­ется, при мутации команд эти парамет­ры меня­ются. Само мес­то раз­вилки выг­лядит при­мер­но так:

2564 | 00007FFD6A21E0CE | 49:89E8 | mov r8,rbp <--- RBP указывает на текущий фрейм кода

2565 | 00007FFD6A21E0D1 | 49:81F5 01000000 | xor r13,1

2566 | 00007FFD6A21E0D8 | 49:01D5 | add r13,rdx

2567 | 00007FFD6A21E0DB | 4C:31CA | xor rdx,r9

2568 | 00007FFD6A21E0DE | 49:81C0 EB000000 | add r8,EB

2569 | 00007FFD6A21E0E5 | 4C:01EA | add rdx,r13

256A | 00007FFD6A21E0E8 | 48:09D2 | or rdx,rdx

256B | 00007FFD6A21E0EB | 4D:8B00 | mov r8,qword ptr ds:[r8] <--- R8=[RBP+EB] указатель на новую команду шитого кода

256C | 00007FFD6A21E0EE | 49:81C0 0A000000 | add r8,A

256D | 00007FFD6A21E0F5 | 48:81C9 80000000 | or rcx,80

256E | 00007FFD6A21E0FC | 45:8A08 | mov r9b,byte ptr ds:[r8] <--- В R9 битный идентификатор флага по смещению A байт

256F | 00007FFD6A21E0FF | 41:80F9 E4 | cmp r9b,E4 <--- В этой реализации команды идентификатор E4 соответствует Zero flag

2570 | 00007FFD6A21E103 | 0F84 19000000 | je 7FFD6A21E122

2571 | 00007FFD6A21E122 | 48:81E2 90000000 | and rdx,90

2572 | 00007FFD6A21E129 | 49:81E6 04000000 | and r14,4

2573 | 00007FFD6A21E130 | 4D:09CD | or r13,r9

2574 | 00007FFD6A21E133 | 41:54 | push r12

2575 | 00007FFD6A21E135 | 41:81E4 40000000 | and r12d,40 <--- Регистр флагов уже загружен в r12d, маска 40h — установлен бит Zero

2576 | 00007FFD6A21E13C | 0F84 18000000 | je 7FFD6A21E15A <-------------------Развилка

2577 | 00007FFD6A21E15A | 49:C7C5 00000000 | mov r13,0

2578 | 00007FFD6A21E161 | 48:81C1 78000000 | add rcx,78

2579 | 00007FFD6A21E168 | 48:81E9 88000000 | sub rcx,88

257A | 00007FFD6A21E16F | 41:5C | pop r12

257B | 00007FFD6A21E171 | 49:C7C5 00000000 | mov r13,0

257C | 00007FFD6A21E178 | 49:C7C5 00040000 | mov r13,400

257D | 00007FFD6A21E17F | 41:80F9 60 | cmp r9b,60

Код дан­ного обра­бот­чика мы поменять не можем (он исполь­зует­ся в бес­числен­ном количес­тве дру­гих мест), одна­ко мы можем модифи­циро­вать коман­ду шитого кода, ведь она содер­жит в сво­их парамет­рах адре­са и обе­их веток вир­туаль­ного кода, и их обра­бот­чиков. Разуме­ется, при­дет­ся вно­сить исправ­ления в уже рас­пакован­ный и рас­шифро­ван­ный код (при­мер халяв­ного решения дан­ной проб­лемы я при­водил в пре­дыду­щей статье), а еще — оза­дачить­ся борь­бой с про­вер­кой кон­тро­ля целос­тнос­ти.

Итак, мы дос­тигли пос­тавлен­ной цели: срав­нили два лога и наш­ли раз­вилку в коде меж­ду вет­ками с пра­виль­ным отве­том сер­вера и без него. Про­пат­чив код, мы можем изле­чить наш подопыт­ный гра­фичес­кий пла­гин от излишней алчнос­ти.

Мы рас­смот­рели лишь общие прин­ципы реали­зации вир­туаль­ной машины Themida. К сло­ву ска­зать, у Oreans есть и дру­гие похожие про­дук­ты, нап­ример Code Virtualizer. Эта статья, воз­можно, поможет кому‑то в борь­бе и с подоб­ными вир­туаль­ными машина­ми и обфуска­тора­ми.

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page