Гайд Themida под героином

✊Rot Front✊
Пользователь
Статус
Оффлайн
Регистрация
2 Июл 2020
Сообщения
132
Реакции[?]
258
Поинты[?]
86K
Итак, сегодня речь будет затронута темида и ещё защиты.

Здесь анализировались следующие версии:
Repacke от
Пожалуйста, авторизуйтесь для просмотра ссылки.
(Themida v 3.0.4.0)
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.

WinLicense является просто модифицированной версией темиды,но с добавлением лицензии и другими плюшками.


Здесь будет продемонстрирован код больше x64 code,нежели x32 т.к логика почти одинакова
+ из-за ограничений по количеству слов автору пришлось пихнуть примеры в pastebin(заранее извиняюсь за это и просто вставьте его в notepad++,если надо)

Затрагиваемые моменты:
Анализ распаковки
Нахождение импорта в темиде
Обход anti-debug,anti-vm,file/register or monitor tool's
Анализ шифрование импорта
Обходим CRC file
Обходим Runtime CRC
Анализ мутации кода
Слегка анализируем VM

Так же автор попытается показать мысли/логику во время анализу,чтобы не было магическое появления информации
Распаковка
EP начинается с секции .boot и выглядит следующим образом:
Пожалуйста, авторизуйтесь для просмотра ссылки.


Я не вижу особого смысла анализировать т.к он просто расшифровывает секцию .themida и передаёт ей управление с jmp rax(просто смело пропускайте сие чудо).

в x32 аналогично

Теперь перейдём к анализу расшифровки нашей секции .text
Итак, давайте воспользуемся HWBP,чтобы не ломать голову откуда запись/чтение.
Устанавливаем HWBP на 1 байт секции.
Давайте просто начнём копать, откуда идёт запись.
unpack_hwbp_write.png

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

Если упростить код
(вы всегда можете удалить jmp т.к ими часто обузят протекторы и свернуть математические операции, но об этом будет сказано в мутации кода):
Из кода выше понятно следующее:
mov eax,dword ptr ds:[rsi] - чтение зашифрованный секции
add rsi,4 прибавление + sizeof(ULONG)
;decrypt
mov dword ptr ds:[rsi],eax - запись расшифрованный байт секции .text

Быстро и лениво деобфусцируя:

sub 50F7E667 -> add 3E0A24B7-> xor 4B1068D5
or sub 12EDC1B0 -> xor 4B1068D5


В упрощённом видел:
mov eax,dword ptr ds:[rsi];чтение
add rsi,4; + sizeof(ULONG)
sub eax,12EDC1B0;расшифровка 1
xor eax,4B1068D5; расшифровка 2
mov dword ptr ds:[rsi],eax;запись расшифрованных байт

Короче, первое действие - просто расшифровка с помощью sub & xor в данном случае

Вторая запись:
Пожалуйста, авторизуйтесь для просмотра ссылки.

В упрощенном виде:
mov byte ptr ds:[rdi],al
add rsi,1
add rdi,1
sub ecx,1
mov al,byte ptr ds:[rsi]
mov byte ptr ds:[rdi],al


Но погодите-ка, ведь адрес в rsi вообще выделен в отдельном регионе?
Ну, протектор, видимо, решил использовать данный трюк для усложнения + потом я покажу, что он использует этот трюк в другом месте.
alloce_decrypted.png
Отсюда растут ноги в запись в выделенную память.
Я не хочу пихать код т.к он очень большой, но он напоминает распаковку секции .themida т.к так же юзается
add dl, dl
Сам график(код в первоначальном виде т.е jmp не очищены и прочие приколы):


Нахождение OEP:
Здесь работает самый тупой способ т.е через PAGE_GUARD hook на .text секцию.
Проблема в том, что протектор должен не пихать jmp на свою секцию,а утянуть вызов в свою VM(как делает тот же VMProtect).

00007FF646C81480 - OEP

Оригинальный код:

00007FF646C8147A | E8 9F090000 | call <JMP.&_Exit> |
00007FF646C8147F | 90 | nop |
00007FF646C81480 <wi | 48:83EC 28 | sub rsp,28 |
00007FF646C81484 | E8 D7030000 | call winlicense_test.7FF646C81860 |
00007FF646C81489 | 48:83C4 28 | add rsp,28 |
00007FF646C8148D | E9 72FEFFFF | jmp winlicense_test.7FF646C81304 |


Виртуализированный OEP:

00007FF6717B147A | E8 9F090000 | call <JMP.&_Exit> |
00007FF6717B147F | 90 | nop |
00007FF6717B1480 | E9 3ED86700 | jmp winlicense_test_protected.7FF671E2ECC3 |;1 выполнение инструкции при PAGE_GUARD секции .text
00007FF6717B1485 | 50 | push rax |;перезаписанный код на мусор
00007FF6717B1486 | A2 82FBF50E6592495A | mov byte ptr ds:[5A4992650EF5FB82],al |;перезаписанный код на мусор
00007FF6717B148F | AA | stosb |;перезаписанный код на мусор
00007FF6717B1490 | DF62 CC | fbld st(0),tword ptr ds:[rdx-34] |;перезаписанный код на мусор
00007FF6717B1493 | CC | int3 |;code cave
00007FF6717B1494 | 40:53 | push rbx |


Хукаем WinApi,которые юзает темида
Итак,если вы попытаетесь трассировать темиду,то иногда ваш код застрянет на поиске импортов:

Нас интересует эта часть кода:
ret 0x18
или в x32 бинарнике
ret 0xC
Из моих опытов, всегда после этой инструкции идёт jmp,благодаря чему можно составить сигнатуру
x64 - C2 18 00 E9
x32 - C2 0C 00 E9
Это будет первая точка остановы с поиском импорта, которая сработает при поиске этого паттерна.
Давайте проверим мои слова:

и само выполнение кода:

Получаем следующие NtApi/Api:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
В теории вы можете просто перехватить это добро, чтобы,например, обойти anti-debug,CRC file и т.д

Так же в x64 бинарнике юзается VEH(в дальнейшем он удаляется).
Почему же они его юзают?
Ответ не застав долго ждать:



Начнём с простого т.к обнаружение мониторов для реестра/файлов.
Из списка выше понятно, что юзается FindWindows и вот список:
x32:
FindWindows
lpClassName:
"OLLYDBG"
"GBDYLLO"
"pediy06"
"PROCMON_WINDOW_CLASS"

lpWindowName :
"File Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
"
"Process Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
"

x64:
FindWindows
lpClassName:
"PROCMON_WINDOW_CLASS"
"RegmonClass"
"18467-41"
"Registry Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
"

lpWindowName :
"Process Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
"
"File Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
"
Однако, это не весь список WinApi/NtApi. WTF????(попробуйте только пропатчить FindWindows и запустить программу под темидой с детектом monitor tools)
Ну, ответ довольно прост:GetProcAddress(особенно из-за получения его выше темидой).
Лично автор решил данную проблему так: начинать трассировку, скопировать адрес NtApi/WinApi и когда индекс трассировки будет >50k смотреть данный адрес(трассировка->поиск-> константа)
Я так сделал и рекомендую так делать т.к разработчики протектора могут начать получать адрес в другом месте,хотя вы можете потратить много времени на это.

В любом случае, у нас есть в списке импорта lstrcmpiA на этот WinApi,поэтому ставим bp и мы получим следующий список драйверов:

NtQuerySystemInformation with SystemModuleInformation

CONST CHAR* bad_list_driver_monitor[] =
{
"FileMonitor.sys"
"Filem"
"REGMON"
"regsys"
"sysregm"
"PROCMON"
"Kernel Detective"
"CisUtMonitor"
"Revoflt"

};

Так же создаётся поток, который будет вызывать FindWindowA(можно просто сделать прыжок на свой же адрес т.е EB FE,заморозить поток и т.д).
Anti-debug(x64/x32):
Loader:
NtOpenSection + NtMapViewOfSection Map ntdll file(KnownDlls)(берёт только NtQueryInformationProcess)
NtSetInformationThread with ThreadHideFromDebugger
CheckRemoteDebuggerPresent -> ProcessDebugPort
GetThreadContext -> NtGetThreadContext
NtQueryInformationProcess with ProcessDebugPort/ProcessDebugObjectHandle
GetForegroundWindow -> NtUserGetForegroundWindow
GetWindowText -> GetWindowThreadProcessId -> NtUserQueryWindow


NtQuerySystemInformation with SystemModuleInformation
CONST CHAR* bad_list_driver_anti_debug[] =
{
ntice.sys
iceext.sys
Syser.sys
HanOlly.sys
extrem.sys
FRDTSC.SYS
fengyue.sys
};
VirtualProtect -> NtProtectVirtualMemory -> IsBadWritePtr -> DbgUiRemoteBreakin goto(jmp) LdrShutdownProcess
VirtualProtect -> NtProtectVirtualMemory -> DbgUiRemoteBreakin -> ret

Анти-дебаг в лоадере аналогичен в SDK за исключением SystemModuleInformation.

Anti-VM:
x64
Компьютер\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000 -> DriverDesc
Компьютер\HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System -> SystemBiosVersion\VideoBiosVersion
Компьютер\HKEY_LOCAL_MACHINE\HARDWARE\ACPI\DSDT\VBOX__
GetSystemFirmwareTable(NtQuerySystemInformation with SystemFirmwareTableInformation) + BMSR


x32
in eax,dx ; eax - (68584D56)hXMV, dx - XV
in eax,dx eax - (564D5868)VMXh,dx - VX
Мне было лень полностью анализировать т.к они юзают что-то ещё и достать быстро не получилось:
Компьютер\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000 -> DriverDesc
Компьютер\HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System -> SystemBiosVersion\VideoBiosVersion
Компьютер\HKEY_LOCAL_MACHINE\HARDWARE\ACPI\DSDT\VBOX__
GetSystemFirmwareTable(NtQuerySystemInformation with SystemFirmwareTableInformation) + BMSR
И как-то ешё трюк, который мне лень анализировать из-за нехватки времени

anti-sandbox(x32/x64):
GetModuleHandleA:
cmdvrt32.dll
SbieDll.dll(Hi,VMProtect)

Обфускация импорта


При трассировке видим следящее:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Нас должно зацепить следующее:
1)Способ получения начала секции
через:
call$+5
pop rbp
sub rbp,31E3F

2)Последняя операция с расшифровкой импорта:
00007FF7FDDFD631 or rax,reg ; decrypt address

3)Запихивание переменной в стек через push и при этом с 2 регистрами:
00007FF7FDE07979 | FF3428 | push qword ptr ds:[rax+rbp]


Я не вижу смысла деобфусцировать т.к можно понять логику и скажу следущее:
1)Протектор должен прочитать откуда-то зашифрованное значение и расшифровать(в моём случае оно находится в секции .winlicense) -> можно поставить PAGE GUARD hook
Первое чтение идёт как раз из push qword ptr ds:[rax+rbp] ; push qword ptr ds:[offset+start_secthion] (offset - 255B4)
Это делается из-за того,чтобы не убивать скорость выполнение программы т.к под VM займёт куда больше операций,а отсюда и времени
2)((res_offset - 7C4591CA) ^ 7D0AE1FA) | FFFFFFFF
Здесь идут операции :sub,xor,and
3)
push reg
mov qword ptr ss:[rsp],decrypt_address

При анализе я всегда встречал 3 пункта с верху(так же jmp,похоже,всегда вставляется даже при виртуализированном коде т.е начинать сканирование нужно от jmp),поэтому можно сделать логику для расшифровки импортов.

в x32:
Пожалуйста, авторизуйтесь для просмотра ссылки.

1)Встречаем так же push dword ptr ss:[ebp+eax]
2)В конце используется xor для расшифровки
3) Так же в упрощённом виде:
push reg
mov qword ptr ss:[esp],decrypt_address

Аналогично так же с возможностью с расшифровкой автоматический(поиск jmp + проверка команд и меньше ~150 операций перед ret), но только нужно проверять на xor eax,reg в x32

Обходим CRC file

Итак, немного пояснения, чтобы не было проблем в различии CRC.
CRC используется протекторами для обнаружения изменений в файле/в секции.
Основная идея CRC file - обнаружить практический любое изменение байт в файле,за исключением некоторых моментов в файле + где сохраняется значение.
CRC подвергается коллизии, но этот способ неудобен в данном случае для обхода т.к нужно анализировать сам алгоритм,а он может быть в VM.
Самый простой способ - найти где сохраняется итоговый результат CRC или подменить файл на оригинальный.

Themida использует следующий способ подсчёта:
Themida использует следующий способ подсчёта CRC файла:
GetModuleFileName
CreateFileW
GetFileSize
CreateFileMappingW
MapViewOfFile
UnmapViewOfFile

Можно просто подменять файл и это работает,но давайте избавимся от бесполезной работы.
В данном примере понадобится CTF exploler для создания новой секции и вставки оригинального файла в новую секцию.
File -> open -> secthion headers -> add secthion(file data) и кидаем оригинальный файл -> add secthion(empty space) -> у новой секции change secthion flag ->
Is executeble и ставим галочку т.к туда будем пихать наш код.
Можно написать dll без crt и скопировать код(единственно, что вам нужно будет сделать: сохранять почти все регистры и Rlag/Eflag) и передавать туда выполнение
(вы сможете хукнуть эти api раньше, например, чем будет вообще выполнена распаковка(изменение EP на свой код)).
В данном примере автор продемонстрирует патчинг vm-entry после вызова API.
Логика обхода(в данном случае была дефолтная VM т.е Tiger Rea):
1)Делаем подмену rax/eax после вызова MapViewOfFile и сохраняем оригинальное значение, если вызов вернул не NULL
2)Делаем подмену размер файла(это не обязательно, но будем пунктуальные в этом плане)
3)Возвращаем оригинальный выделенный адрес из MapViewOfFile в UnmapViewOfFile т.к иначе будет unmap нашей секции или по-простому: нам кирдык.

Ставим bp на MapViewOfFile,GetFileSize и проверяем вызывается ли vm-handler пару раз или только 1 раз.
В моём случае он вызывался только 1 раз.
Мы должны получить адрес выхода vm перед вызовом UnmapViewOfFile т.к это убьёт наш файл.
Ставим bp на обращение к последним байтам,чтобы не снимать ооооочень длинную трассировку и начинаем трассировку,пока не дойдём до вызова.
У автора много раз вызывалась vm-exit,поэтому нужно ставить условие на подмену rax/eax.

Будет прикреплён с файлом в качестве примера.

Краткий обзор файла и пример обхода crc file(будет прикреплены в качестве примера):

rva: header va : offset file
5E36E4 : 00000001405E36E4 : 5DE4E4 - filze size(vm-entry)
5CA074 : 00000001405CA074 : 5C4E74 - map file(vm-entry)
3A6E7 : 000000014003A6E7 : 354E7 - unmap file(vm-exit call api or jmp next code)
call GetFileSize -> vm-emtry -> jmp patch ->
mov eax,0x674E00 ;размер полученный в оригинальном файле с помощью GetFileSize
pushfq ; восстанавливаем украденные байты
sub rsp,0x8
jmp winlicense_test_protected_2_11.7FF7966A36E9

MapViewOfFile -> vm-entry -> jmp patch ->
mov qword ptr ds:[0x7FF79673A120],rax ;сохраняем значение относительно rip + offset
lea rax,qword ptr ds:[0x7FF79673B000] ; получаем адрес оригинального файла в секции относительно rip
pushfq ; восстанавливаем украденные байты
push 0x6FF5AC8B
jmp winlicense_test_protected_2_11.7FF79668A079

Тут вообще должна быть проверка сначала:
cmp rax,0
но весь рофл в том,что темида всё-равно будет читать, если даже при неудачном NTSTATUS


pop rcx ; rcx - наш адрес, который мы подменили
push rdx
lea rdx,qword ptr ds:[0x7FF79673B000]; получаем адрес скопированной нашего файла
cmp rcx,rdx;наш подменённый адрес
jne winlicense_test_protected_2_11.7FF79673A051
mov rcx,qword ptr ds:[0x7FF79673A120] ; подменяем, иначе будет худо нам
pop rdx
pop rax ; просто восстанавливаем украденные байты
popfq
ret 0x0

Браво! Вы обошли CRC file ничего особо не делая!
Можно другими способами, но я продемонстрировал, который пришёл самый первый в голову автора.

в x32 почти аналогично.

Обходим Runtime CRC
или
Я купил себе машину, думал, круче не найти,
Откатал на ней неделю, сдохла, мать её ити!


Я называю так CRC т.к проверка может быть выполнена только в runtime самого вашего кода(CHECK_CODE_INTEGRITY ).
На самом деле CRC секции подсчитано и оно просто вычисляется заново & сравняется с готовым CRC.
Так же CRC runtime проверяет только патч ER секции(.text),а не другие и тем более VM(я не видел,чтобы темида его проверяла и сама пять ERW)

Итак, начинаем с того, что мы пробуем пропатчить любой байт в .text секции и мы получаем обнаружение.
Попробуем изменить безобидный code cave(int3) и получаем обнаружение:

Посмотри откуда идёт чтение:


видим такую ситуацию:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Вас должен сразу смутить следущий код:
00007FF6BFEC86DD | mov bl,0x7
Значение перезаписывается т.е оно сохраняется где-то сверху и как раз после чтения идёт запись в RW регион памяти!


Теперь ставим там bp на обращение и смотрим, откуда идёт чтение:

00007FF6C044CFB4 | add eax,dword ptr ds:[r11]
и
00007FF6C044CE4C | xor eax,dword ptr ds:[rdx]
Если посмотрим на график,то это просто мутированный код и нам повезло!
График:





В упрощённом виде:


loop_read:
00007FF6C044CFB4 | add eax,dword ptr ds:[r11]
00007FF6C03F9184 | rol eax,10
00007FF6C044CE2B | push rdx
00007FF6C044CE42 | add rdx,rsi
00007FF6C044CE4C | xor eax,dword ptr ds:[rdx]
00007FF6C044CE52 | pop rdx
00007FF6C044E2F3 | add rsi,4; +sizeof(ULONG)
00007FF6C044F16E | sub ecx,1
00007FF6C03C5C6D | test ecx,ecx
00007FF6C0403D1F | je winlicense_test_protected.stop_scan
00007FF6C0403D25 | jmp winlicense_test_protected.loop_read

stop_scan:
00007FF6C0433708 | 8945 E0 | mov dword ptr ss:[rbp-20],eax
00007FF6C044FE30 | FF75 E4 | push qword ptr ss:[rbp-1C]
00007FF6C044B12F | FF97 D9310600 | call qword ptr ds:[rdi+631D9]; прыжок в VM

Дальше нас особо код не интересует
*Часть кода пропущена и основная логика без этого понятна.

Итак,здесь просто происходит цикл, да ещё и не в VM! ЛЯПОТА!
Результат сохраняется в eax и давайте его попробуем пропатчить!
убираем все патчи -> получаем оригинальный результат CRC(eax - 00000000F84B2AA5) -> видим E9 00000000 | jmp winlicense_test_protected.7FF6C044F287(идёт после pop rax) и меняем на:
mov eax,0xF84B2AA5 (5 байт как раз)
Ура! Мы обошли CRC runtime!

В крайнем случае вы можете всегда найти все места откуда идёт чтение и постепенно пропатчит их/просто давать скопированный регион.
С x32 такая же история.

Анализ мутации кода


До мутации:

После:

и


Поэтапно будем разбирать:
1)Злоупотреблением jmp.
00007FF786810E86 | add rsp,8
00007FF786810E8A | jmp winlicense_test_protected.7FF786803559
00007FF786803559 | push 77CC7B6D
00007FF78680355E | mov qword ptr ss:[rsp],rsi
00007FF786803562 | mov rsi,rsp
00007FF786803565 | add rsi,8
00007FF786803569 | sub rsi,8


Если смотреть просто дизассемблированный код,то видим следящее:
00007FF78680355D ja winlicense_test_protected.7FF7868035A7
00007FF78680355F mov dword ptr ss:[rsp],esi
00007FF786803562 mov rsi,rsp
00007FF786803565 add rsi,8
00007FF786803569 sub rsi,8
Основная цель - попытаться обмануть дизассемблер т.к если дизассемблировать линейно т.е с начал адреса секции,то многие операнды будут накладываться друг на друга и ломать анализ
2)Расшифровка в зашифрованном режиме:

00007FF7867EBB2B | 48:B8 AAB7EF7F00000000 | mov rax,7FF786170000
00007FF7867FD14C | 48:81EE 2749FF7E | sub rsi,7EFF4927
00007FF7867FD153 | 48:81EE CD8FFB17 | sub rsi,17FB8FCD
00007FF7867FD15A | 48:81C6 B7F1FC7F | add rsi,7FFCF1B7
00007FF7867FD161 | 48:81C6 C1A7F67F | add rsi,7FF6A7C1
00007FF7867FD168 | 48:81EE 41C1FF7B | sub rsi,7BFFC141
00007FF7867FD16F | 48:01C6 | add rsi,rax
00007FF7867FD172 | 48:81C6 41C1FF7B | add rsi,7BFFC141
00007FF7867FD179 | 48:81EE C1A7F67F | sub rsi,7FF6A7C1
00007FF7867FD180 | 48:81EE B7F1FC7F | sub rsi,7FFCF1B7
00007FF7867FD187 | 48:81C6 CD8FFB17 | add rsi,17FB8FCD
00007FF7867FD18E | 48:81C6 2749FF7E | add rsi,7EFF4927

Протектор использует это только к sub и add.
Суть и так ясна
3)Расшифровка констант,используя математические операции:
;some code
Пожалуйста, авторизуйтесь для просмотра ссылки.

;some code
rcx будет преобразован в 140000000
и
Пожалуйста, авторизуйтесь для просмотра ссылки.

mov eax, 80008001- код,который была мутированная

5)mba
[rsp] - 0,rsi - 63B08FFAF8
00007FF7867C38DE | 48:333424 | xor rsi,qword ptr ss:[rsp] | | 00000063B08FFAE8: 0-> 0
00007FF7867C38E2 | 48:313424 | xor qword ptr ss:[rsp],rsi | | 00000063B08FFAE8: 0-> 63B08FFAF8
00007FF7867C38E6 | 48:333424 | xor rsi,qword ptr ss:[rsp] | rsi: 63B08FFAF8-> 0 | 00000063B08FFAE8: 63B08FFAF8-> 63B08FFAF8

Эта запись аналогична простому:xchg qword ptr ss:[rsp], rsi

6)Получить начальный адрес секции:
00007FF7861838AE | E8 00000000 | call winlicense_test_protected.7FF7861838B3;получаем адресс следующей инструкции(pop rbp)
00007FF7861838B3 | 5D | pop rbp
00007FF7861838B4 | 48:81ED B3B80000 | sub rbp,B8B3
00007FF7861838BB | C3 | ret


7)переход к новому адресу, используя ret
Трассировка:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Нас интересует только это:

7FF786170000 - PE файла
7FF7861AA888 - ret address

Пожалуйста, авторизуйтесь для просмотра ссылки.


Чтение самой секции:
00007FF7867EBB22 | FFB5 BEFD2F00 | push qword ptr ss:[rbp+2FFDBE] | rsp: DE5CD9FC20-> DE5CD9FC18 | 00007FF786477DBE: 7FF786170000-> 7FF786170000 000 |

00007FF7867EBB2A | 50 | push rax | rsp: DE5CD9FC10-> DE5CD9FC08 | 000000DE5CD9FC08: 0-> 1 |
00007FF7867EBB2B | 48:B8 AAB7EF7F00000000 | mov rax,7FEFB7AA | rax: 1-> 7FEFB7AA | |
00007FF7867EBB35 | 49:BE 191F2FFF00000000 | mov r14,FF2F1F19 | r14: 0-> FF2F1F19 | |
00007FF7867EBB3F | 49:29C6 | sub r14,rax | r14: FF2F1F19-> 7F3F676F | |
00007FF7867EBB42 | 58 | pop rax | rax: 7FEFB7AA-> 1 rsp: DE5CD9FC08-> DE5CD9FC10 | 000000DE5CD9FC08: 1-> 1 |
00007FF7867EBB43 | 4C:317424 08 | xor qword ptr ss:[rsp+8],r14 | | 000000DE5CD9FC18: 7FF786170000-> 7FF7F928676F |
00007FF7867EBB48 | 41:5E | pop r14 | rsp: DE5CD9FC10-> DE5CD9FC18 r14: 7F3F676F-> 0 | 000000DE5CD9FC10: 0-> 0 |
00007FF7867EBB4A | 48:8B0424 | mov rax,qword ptr ss:[rsp] | rax: 1-> 7FF7F928676F | 000000DE5CD9FC18: 7FF7F928676F-> 7FF7F928676F |
00007FF7867EBB4E | 48:83C4 08 | add rsp,8 | rsp: DE5CD9FC18-> DE5CD9FC20 | |
00007FF7867EBB52 | 48:35 6F673F7F | xor rax,7F3F676F | rax: 7FF7F928676F-> 7FF786170000 |



00007FF786803A1D | 48:C70424 A041BE3F | mov qword ptr ss:[rsp],3FBE41A0 | | 000000DE5CD9FC10: 0-> 3FBE41A0 |
00007FF786803A25 | 4C:8B3424 | mov r14,qword ptr ss:[rsp] | r14: 0-> 3FBE41A0 | 000000DE5CD9FC10: 3FBE41A0-> 3FBE41A0 |
00007FF786803A29 | 48:83C4 08 | add rsp,8 | rsp: DE5CD9FC10-> DE5CD9FC18 | |
00007FF786803A2D | 41:81F6 4B579B37 | xor r14d,379B574B | r14: 3FBE41A0-> 82516EB | |
00007FF786803A34 | 41:81EE 86ECFF6F | sub r14d,6FFFEC86 | r14: 82516EB-> 98252A65 | |
00007FF786803A3B | 41:83C6 01 | add r14d,1 | r14: 98252A65-> 98252A66 | |
00007FF786803A3F | 41:81F6 EE822698 | xor r14d,982682EE | r14: 98252A66-> 3A888 | |
00007FF786803A46 | 44:89F1 | mov ecx,r14d | rcx: 140000000-> 3A888 | |
00007FF786803A49 | 41:5E | pop r14 | rsp: DE5CD9FC18-> DE5CD9FC20 r14: 3A888-> 0 | 000000DE5CD9FC18: 0-> 0 |
00007FF786803A4B | E9 BD9E0000 | jmp winlicense_test_protected.7FF78680D | | |
00007FF78680D90D | 48:81C1 6AFAFB7F | add rcx,7FFBFA6A | rcx: 3A888-> 7FFFA2F2 | |
00007FF78680D914 | 48:81C1 C01D9B1B | add rcx,1B9B1DC0 | rcx: 7FFFA2F2-> 9B9AC0B2 | |
00007FF78680D91B | 48:81E9 528EEE6D | sub rcx,6DEE8E52 | rcx: 9B9AC0B2-> 2DAC3260 | |
00007FF78680D922 | 48:81E9 3DCADD3F | sub rcx,3FDDCA3D | rcx: 2DAC3260-> FFFFFFFFEDCE6823 | |
00007FF78680D929 | 48:01C1 | add rcx,rax | rcx: FFFFFFFFEDCE6823-> 7FF773E56823 | |
00007FF78680D92C | 48:81C1 3DCADD3F | add rcx,3FDDCA3D | rcx: 7FF773E56823-> 7FF7B3C33260 | |
00007FF78680D933 | 48:81C1 528EEE6D | add rcx,6DEE8E52 | rcx: 7FF7B3C33260-> 7FF821B1C0B2 | |
00007FF78680D93A | 48:81E9 C01D9B1B | sub rcx,1B9B1DC0 | rcx: 7FF821B1C0B2-> 7FF80616A2F2 | |
00007FF78680D941 | 48:81E9 6AFAFB7F | sub rcx,7FFBFA6A | rcx: 7FF80616A2F2-> 7FF7861AA888 |

Если упростить и взять только логику с ret,то:
;some code
call $+5
pop rax
sub rax,decrypt_offset_fix_start_secthion
push qword ptr ss:[rax+offset_themida.base_address];read secthion .winlicense and push
pop rax
add rax,decrypt_offset_next_code_ret
push rax;go next code
ret


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

Это больше в качестве маленького и бесполезного бонуса т.к у автора мало времени на дальнейший анализ...
Слегка анализируем VM(Tiger Lite)
Пожалуйста, авторизуйтесь для просмотра ссылки.
Если копать под jmp r9:

005F | 00007FF6D41429BD | E8 00000000 | call tiger_lite.7FF6D41429C2 | rsp: 72D32FFDC0-> 72D32FFDB8 | 00000072D32FFDB8: 6CF3AC79-> 7FF6D41429C2
00EC | 00007FF6D4142BD5 | 48:83E9 05 | sub rcx,5 | rcx: 7FF6D41429C2-> 7FF6D41429BD |
00ED | 00007FF6D4142BD9 | 48:81E9 BD290F00 | sub rcx,F29BD | rcx: 7FF6D41429BD-> 7FF6D4050000 |

rcx 7FF6D4050000 - base address

Темида получает адрес текущей секции через call $+5

2)Увеличить RSP:
1)
00A2 | 00007FF6D4142ABC | 48:89E0 | mov rax,rsp | rax: 0-> 72D32FFD70 |
00A3 | 00007FF6D4142ABF | 48:83C0 08 | add rax,8 | rax: 72D32FFD70-> 72D32FFD78 |
00A4 | 00007FF6D4142AC3 | 48:2D 08000000 | sub rax,8 | rax: 72D32FFD78-> 72D32FFD70 |
00A5 | 00007FF6D4142AC9 | 48:870424 | xchg qword ptr ss:[rsp],rax | rax: 72D32FFD70-> 0 | 00000072D32FFD70: 0-> 72D32FFD70
00A6 | 00007FF6D4142ACD | 48:8B2424 | mov rsp,qword ptr ss:[rsp]

2)
0205 | 00007FF6D41431BC | 41:55 | push r13 | rsp: 72D32FFD40-> 72D32FFD38 | 00000072D32FFD38: 0-> 0
0206 | 00007FF6D41431BE | 49:89E5 | mov r13,rsp | r13: 0-> 72D32FFD38 |
0207 | 00007FF6D41431C1 | 49:83C5 08 | add r13,8 | r13: 72D32FFD38-> 72D32FFD40 |
0208 | 00007FF6D41431C5 | 49:81C5 08000000 | add r13,8 | r13: 72D32FFD40-> 72D32FFD48 |
0209 | 00007FF6D41431CC | 4C:872C24 | xchg qword ptr ss:[rsp],r13 | r13: 72D32FFD48-> 0 | 00000072D32FFD38: 0-> 72D32FFD48
020A | 00007FF6D41431D0 | 48:8B2424 | mov rsp,qword ptr ss:[rsp] | rsp: 72D32FFD38-> 72D32FFD48 | 00000072D32FFD38: 72D32FFD48-> 72D32FFD48



3)Расшифровка таблицы переходов via VM handlers:

Пожалуйста, авторизуйтесь для просмотра ссылки.


BCF6D + base_address


0242 | 00007FF6D41432CE | 89FE | mov esi,edi | rsi: 0-> 6BBFDC58 |
0244 | 00007FF6D41432D1 | 81CE CB19FF0D | or esi,DFF19CB | rsi: 6BBFDC58-> 6FFFDDDB |
0245 | 00007FF6D41432D7 | F7D6 | not esi | rsi: 6FFFDDDB-> 90002224 |
0246 | 00007FF6D41432D9 | 81C6 A7D2F33F | add esi,3FF3D2A7 | rsi: 90002224-> CFF3F4CB |
0247 | 00007FF6D41432DF | 81EE 774C0090 | sub esi,90004C77 | rsi: CFF3F4CB-> 3FF3A854 |
0248 | 00007FF6D41432E5 | 89F3 | mov ebx,esi | rbx: 0-> 3FF3A854 |
024B | 00007FF6D41432EF | 81C3 EA570CC0 | add ebx,C00C57EA | rbx: 3FF3A854-> 3E |


0005 | 00007FF6D4465815 | 48:BE DB00000000000000 | mov rsi,DB | rsi: 0-> DB |
0253 | 00007FF6D414347B | 48:8B1C24 | mov rbx,qword ptr ss:[rsp] | rbx: 3E-> DB

025B | 00007FF6D414349E | 48:C1E3 03 | shl rbx,3 | rbx: DB-> 6D8 |

0260 | 00007FF6D41434BA | 48:01D8 | add rax,rbx | rax: 7FF812ADF201-> 7FF812ADF8D9 |

0265 | 00007FF6D41434D5 | FF20 | jmp qword ptr ds:[rax] | | 00007FF6D410D645: 7FF6D40B98D5-> 7FF6D40B98D5

mov rax,6D8+ (BCF6D + base_address)
jmp [rax];handle execute


Основная цель выполнение vm-handler'ов и при этом данный способ требует от реверсера найти все vm-handler'ы и фиксить их,если мы распаковали программу:


Статья подошла к своему концу из-за нехватки времени.
Be robbers and ravagers as long as you cannot be rulers and owners, you men of knowledgel...
Пожалуйста, авторизуйтесь для просмотра ссылки.
:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
Легенда форума
Статус
Оффлайн
Регистрация
10 Дек 2018
Сообщения
4,385
Реакции[?]
2,286
Поинты[?]
191K
Ахуенно огромная стена текста. Чуть не умер, пока листал до низа, чтобы поставить лайк.
Мне этот гайд ни к чему, но, думаю, заинтересованным людям максимально зайдёт.

Если докапываться, оформление текста подкачало, используй жирный текст, курсив и блоки кода, будет смотреться куда лучше.
 
i hate p2cs
Участник
Статус
Оффлайн
Регистрация
18 Окт 2022
Сообщения
617
Реакции[?]
217
Поинты[?]
146K
Repacke от
Пожалуйста, авторизуйтесь для просмотра ссылки.
(Themida v 3.0.4.0)
Перешёл по ссылке и ахренел, такого я не видел даже на r0crew
Лол с каких это пор китайцы так эволюционировали, прошло вроде немного с "футболка шорта по пять" до patch themida virtualizer, + они даже за хвх шарят, во дают:expressionless:
 
✊Rot Front✊
Пользователь
Статус
Оффлайн
Регистрация
2 Июл 2020
Сообщения
132
Реакции[?]
258
Поинты[?]
86K
Ахуенно огромная стена текста. Чуть не умер, пока листал до низа, чтобы поставить лайк.
Мне этот гайд ни к чему, но, думаю, заинтересованным людям максимально зайдёт.

Если докапываться, оформление текста подкачало, используй жирный текст, курсив и блоки кода, будет смотреться куда лучше.
Да,с оформлением текста траблы т.к мне пришлось сократить сие чудо где-то минимум в 2 раза + перетаскивать код в pastebin
Это все очень интересно, а героин где?
Героин был использован частично для анализа, но большая часть осталась для анализа самих VM oreans :LUL:
 
Начинающий
Статус
Оффлайн
Регистрация
7 Фев 2021
Сообщения
8
Реакции[?]
2
Поинты[?]
2K
И как-то ешё трюк, который мне лень анализировать из-за нехватки времени
Вот этот:

(я Рафаэлю этот метод и репортил, так как детект VM был уж совсем плохой)
rtdsc + cpuid и получаем еще один детект VM
Только надо покрутить пару сотен итераций, отсортировать результаты, взять медианное значение и сравнить с эталонным.
 
Последнее редактирование:
✊Rot Front✊
Пользователь
Статус
Оффлайн
Регистрация
2 Июл 2020
Сообщения
132
Реакции[?]
258
Поинты[?]
86K
Вот этот:

(я Рафаэлю этот метод и репортил, так как детект VM был уж совсем плохой)
rtdsc + cpuid и получаем еще один детект VM
Только надо покрутить пару сотен итераций, отсортировать результаты, взять медианное значение и сравнить с эталонным.
rdtsc с VM-exit хороший пример обнаружения гипервизора, но его популярность приводит к
Пожалуйста, авторизуйтесь для просмотра ссылки.
обнаружения самого гипервизора.
Я лично предлагал Пермякому переписать anti-vm т.к способ обхода давно
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
Если говорить про специальные детекты,то для VMWare можно использовать
Пожалуйста, авторизуйтесь для просмотра ссылки.
т.к это неплохой отпечаток VM.
Для VirtualBox достаточно
Пожалуйста, авторизуйтесь для просмотра ссылки.
т.к его неправильно обрабатывает VirtualBox(который и использует VMP уже много лет).
Хорошим примером обнаружением гипервизора является на мой взгляд
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
• Breakpoint-Condition Detected (B3–B0)—Bits 3:0. The processor updates these four bits on every
debug breakpoint or general-detect condition. A bit is set to 1 if the corresponding addressbreakpoint register detects an enabled breakpoint condition, as specified by the DR7 Ln, Gn, R/Wn
and LENn controls, and is cleared to 0 otherwise. For example, B1 (bit 1) is set to 1 if an addressbreakpoint condition is detected by DR1.

• Single Step (BS)—Bit 14. The processor sets this bit to 1 if the #DB exception occurs as a result of
single-step mode (rFLAGS[TF] = 1). Single-step mode has the highest-priority among debug
exceptions. Other status bits within the DR6 register can be set by the processor along with the BS
bit.
• B0 through B3 (breakpoint condition detected) flags (bits 0 through 3) — Indicates (when set) that its
associated breakpoint condition was met when a debug exception was generated. These flags are set if the
condition described for each breakpoint by the LENn, and R/Wn flags in debug control register DR7 is true.
They may or may not be set if the breakpoint is not enabled by the Ln or the Gn flags in register DR7. Therefore
on a #DB, a debug handler should check only those B0-B3 bits which correspond to an enabled breakpoint.

• BS (single step) flag (bit 14) — Indicates (when set) that the debug exception was triggered by the singlestep execution mode (enabled with the TF flag in the EFLAGS register). The single-step mode is the highestpriority debug exception. When the BS flag is set, any of the other debug status bits also may be set.
 
Сверху Снизу