Гайд Themida под медовухой

✊Rot Front✊
Пользователь
Статус
Оффлайн
Регистрация
2 Июл 2020
Сообщения
132
Реакции[?]
258
Поинты[?]
86K
Вступление
После статьи про VMP автор решил сделать анализ и пример обхода Loader/SDK протектора,но для Oreans.
Уже была опубликована статья про анализ этого протектора,но есть пару моментов:
1)Прошлую статью про этот протектор пришлось ужать в несколько раз(минимум ~ в 5 + многое пришлось перенести в pastebin),благодаря чему читабельность сильно падала(Прим:Можете считать это переизданием в более широком смысле).
2)Некоторые моменты были плохо раскрыты, поэтому сегодня мы это исправим.
3)Здесь будет практика и примеры,поэтому просто не получится что-то сказать не до конца.
4) [censored] 10 мая 1933.
Здесь будет написана dll proxy,чтобы игнорировать многие моменты протектора + неожиданный забавный бонус в конце :).
Сразу скажу: здесь будут рассмотрен только взлом Loader/SDK протектора, про мутацию поговорим в другой раз, но максимально подробно.
Некоторые моменты объединены т.к всё-равно придётся обходить,например,функцию лоадера и SDK(anti-debug).
Упор сделан на понятный и простой обход + автоматизацию ,поэтому не вижу смысла рассматривать какой crc алгоритм используется, например, для получения crc file(можно попытаться сделать атаку, путём нахождения где эта вундер-вафля лежит, но какой смысл?).

1 Импорт лоадера.
Отправной точкой в реверсе,пожалуй,любого протектора - каким образом протектор получает адреса API/NTAPI функций.
Самый простой способ - поставить на обращение к памяти заголовку PE к часто используемым библиотекам с IMAGE_DIRECTORY_ENTRY_EXPORT (например,kernel32.dll или ntdll.dll).
Если посмотреть в графике,то увидим такую ситуацию:
x64:

x32:

Относительно легко можно написать хук,чтобы получить список импорта:
1)Берём 'устойчивую инструкцию',например, 'rcl al,1'.
2)Сканируем секцию темиды на байты этой инструкции.
3)Проверяем через дизассемблирование эту функцию и ставим хук(в данном случае BP).
Однако,секция '.themida'(основной код защиты.[Прим.Название может быть другое,если используется при защите 'OPTION_ADVANCED_SECTION_NAME') может быть упакован,поэтому лучше дождаться выполнения GetModuleHandleA,а потом сканировать это чудо.
Сам список:
x64
Name -> LoadLibraryA
Name -> VirtualAlloc
Name -> GetProcAddress
Name -> SetEvent
Name -> SetEnvironmentVariableW
Name -> SetEnvironmentVariableA
Name -> WaitForSingleObject
Name -> CreateEventA
Name -> CreateProcessW
Name -> GetStartupInfoW
Name -> GetThreadContext
Name -> GetCurrentThread
Name -> TlsAlloc
Name -> TlsSetValue
Name -> LoadLibraryA
Name -> LoadLibraryW
Name -> FreeLibrary
Name -> GetEnvironmentVariableA
Name -> GetEnvironmentVariableW
Name -> GetTempPathW
Name -> GetTempFileNameW
Name -> wsprintfA
Name -> GetUserDefaultUILanguage
Name -> GetVersion
Name -> GetFileSize
Name -> CreateFileA
Name -> CreateFileW
Name -> CreateFileMappingW
Name -> MapViewOfFile
Name -> UnmapViewOfFile
Name -> ExitProcess
Name -> RegOpenKeyW
Name -> CloseHandle
Name -> Sleep
Name -> RtlEnterCriticalSection
Name -> RtlLeaveCriticalSection
Name -> RtlInitializeCriticalSection
Name -> CreateThread
Name -> RtlAddVectoredExceptionHandler
Name -> GetModuleFileNameW
Name -> CreateDirectoryW
Name -> RegCloseKey
Name -> RegFlushKey
Name -> RegSetValueExA
Name -> OutputDebugStringA
Name -> IsBadReadPtr
Name -> IsBadWritePtr
Name -> GetFileTime
Name -> SetFileTime
Name -> GetWindowsDirectoryW
Name -> GetSystemDirectoryW
Name -> MessageBoxExA
Name -> GetModuleHandleA
Name -> VirtualProtect
Name -> VirtualFree
Name -> CreateToolhelp32Snapshot
Name -> Process32First
Name -> Process32Next
Name -> Thread32First
Name -> Thread32Next
Name -> MessageBoxExW
Name -> wsprintfW
Name -> GetCommandLineW
Name -> TerminateThread
Name -> GetProcessHeap
Name -> RtlAllocateHeap
Name -> RtlReAllocateHeap
Name -> RtlFreeHeap
Name -> WideCharToMultiByte
Name -> MultiByteToWideChar
Name -> CharLowerW
Name -> GetCurrentThreadId
Name -> SuspendThread
Name -> OpenThread
Name -> SetCurrentDirectoryW
Name -> GetCurrentDirectoryW
Name -> GetFileAttributesExW
Name -> GetFileAttributesW
Name -> GetCurrentProcess
Name -> GetCurrentProcessId
Name -> SetFilePointer
Name -> ReadFile
Name -> WriteFile
Name -> SHGetSpecialFolderPathW
Name -> PathCanonicalizeW
Name -> CopyFileW
Name -> GetPrivateProfileStringW
Name -> GetPrivateProfileIntW
Name -> GetPrivateProfileSectionW
Name -> DeleteFileW
Name -> lstrcpyn
Name -> lstrcmpi
Name -> StrToIntA
Name -> RegCreateKeyExA
Name -> RegCreateKeyA
Name -> RegCreateKeyExW
Name -> RegOpenKeyA
Name -> RegQueryValueExA
Name -> RegQueryValueExW
Name -> RegDeleteValueA
Name -> RegDeleteValueW
Name -> RegEnumKeyExA
Name -> RegQueryInfoKeyA
Name -> RegSetValueExA
Name -> RegSetValueExW
Name -> GetLocalTime
Name -> GetSystemTime
Name -> SystemTimeToFileTime
Name -> FileTimeToSystemTime
Name -> VirtualQuery
Name -> IsWow64Process
Name -> IsWow64Process2
Name -> DeviceIoControl
Name -> GetMessageA
Name -> TranslateMessage
Name -> DispatchMessageA
Name -> GetCommandLineA
Name -> NtQueryInformationProcess
Name -> CheckRemoteDebuggerPresent
Name -> GetForegroundWindow
Name -> GetWindowTextA
Name -> GetCurrentThread
Name -> OpenThreadToken
Name -> GetCurrentProcess
Name -> OpenProcessToken
Name -> GetTokenInformation
Name -> AllocateAndInitializeSid
Name -> EqualSid
Name -> FreeSid
Name -> VirtualFree
Name -> FindWindowA
Name -> GetSystemFirmwareTable
Name -> FindWindowA
Name -> RtlRemoveVectoredExceptionHandler
GetProcAddress:
SetLastError
2: rdx "SetLastError"
2: rdx "GetLastError"
2: rdx "IsWow64Process2"
2: rdx "IsUserAnAdmin"
2: rdx "NtQuerySystemInformation"
2: rdx "RtlInitializeSListHead"
x32
Name -> LoadLibraryA
Name -> VirtualAlloc
Name -> GetProcAddress
Name -> SetEvent
Name -> SetEnvironmentVariableW
Name -> SetEnvironmentVariableA
Name -> WaitForSingleObject
Name -> CreateEventA
Name -> CreateProcessW
Name -> GetStartupInfoW
Name -> GetThreadContext
Name -> GetCurrentThread
Name -> TlsAlloc
Name -> TlsSetValue
Name -> LoadLibraryA
Name -> LoadLibraryW
Name -> FreeLibrary
Name -> GetEnvironmentVariableA
Name -> GetEnvironmentVariableW
Name -> GetTempPathW
Name -> GetTempFileNameW
Name -> wsprintfA
Name -> GetUserDefaultUILanguage
Name -> GetVersion
Name -> GetFileSize
Name -> CreateFileA
Name -> CreateFileW
Name -> CreateFileMappingW
Name -> MapViewOfFile
Name -> UnmapViewOfFile
Name -> ExitProcess
Name -> RegOpenKeyW
Name -> CloseHandle
Name -> Sleep
Name -> RtlEnterCriticalSection
Name -> RtlLeaveCriticalSection
Name -> RtlInitializeCriticalSection
Name -> CreateThread
Name -> GetModuleFileNameW
Name -> CreateDirectoryW
Name -> RegCloseKey
Name -> RegFlushKey
Name -> RegSetValueExA
Name -> OutputDebugStringA
Name -> IsBadReadPtr
Name -> IsBadWritePtr
Name -> GetFileTime
Name -> SetFileTime
Name -> GetWindowsDirectoryW
Name -> GetSystemDirectoryW
Name -> MessageBoxExA
Name -> GetModuleHandleA
Name -> VirtualProtect
Name -> VirtualFree
Name -> CreateToolhelp32Snapshot
Name -> Process32First
Name -> Process32Next
Name -> Thread32First
Name -> Thread32Next
Name -> MessageBoxExW
Name -> wsprintfW
Name -> GetCommandLineW
Name -> TerminateThread
Name -> GetProcessHeap
Name -> RtlAllocateHeap
Name -> RtlReAllocateHeap
Name -> RtlFreeHeap
Name -> WideCharToMultiByte
Name -> MultiByteToWideChar
Name -> CharLowerW
Name -> GetCurrentThreadId
Name -> SuspendThread
Name -> OpenThread
Name -> SetCurrentDirectoryW
Name -> GetCurrentDirectoryW
Name -> GetFileAttributesExW
Name -> GetFileAttributesW
Name -> GetCurrentProcess
Name -> GetCurrentProcessId
Name -> SetFilePointer
Name -> ReadFile
Name -> WriteFile
Name -> SHGetSpecialFolderPathW
Name -> PathCanonicalizeW
Name -> CopyFileW
Name -> GetPrivateProfileStringW
Name -> GetPrivateProfileIntW
Name -> GetPrivateProfileSectionW
Name -> DeleteFileW
Name -> lstrcpyn
Name -> lstrcmpiA
Name -> StrToIntA
Name -> RegCreateKeyExA
Name -> RegCreateKeyA
Name -> RegCreateKeyExW
Name -> RegOpenKeyA
Name -> RegQueryValueExA
Name -> RegQueryValueExW
Name -> RegDeleteValueA
Name -> RegDeleteValueW
Name -> RegEnumKeyExA
Name -> RegQueryInfoKeyA
Name -> RegSetValueExA
Name -> RegSetValueExW
Name -> GetLocalTime
Name -> GetSystemTime
Name -> SystemTimeToFileTime
Name -> FileTimeToSystemTime
Name -> VirtualQuery
Name -> IsWow64Process
Name -> IsWow64Process2
Name -> DeviceIoControl
Name -> GetMessageA
Name -> TranslateMessage
Name -> DispatchMessageA
Name -> GetCommandLineA
Name -> NtQueryInformationProcess
Name -> DbgUiRemoteBreakin
Name -> LdrShutdownProcess
Name -> DbgBreakPoint
Name -> RtlAddVectoredExceptionHandler
Name -> RaiseException
Name -> RtlRemoveVectoredExceptionHandler
Name -> GetForegroundWindow
Name -> GetWindowTextA
Name -> CheckRemoteDebuggerPresent
Name -> GetCurrentThread
Name -> OpenThreadToken
Name -> GetCurrentProcess
Name -> OpenProcessToken
Name -> GetTokenInformation
Name -> AllocateAndInitializeSid
Name -> EqualSid
Name -> FreeSid
Name -> VirtualFree
Name -> NtSetInformationThread
Name -> FindWindowA
Name -> FindWindowA
Name -> FindWindowA
Name -> GetSystemFirmwareTable
GetProcAddress:
2: [esp+8] "SetLastError"
2: [esp+8] "GetLastError"
2: [esp+8] "IsWow64Process2"
2: [esp+8] "NtQuerySystemInformation"
2: [esp+8] "IsUserAnAdmin"
P.S не совсем полный список импорта + при используется для обработки исключений VEH хук,то нужно зарегистрировать cвой с аргументами First = TRUE(чтобы обработчик протектора вызывался после вашего хука и передавать VEH обработчика протектора с First = FALSE) или скопировать адрес Handler,но не разрешать регистрацию,но вызывать после вашего исключения и т.д. Можно использовать более 'быстрые'(из-за небольшого кол-во выполняемых инструкций) хуки для исключений: KiUserExceptionDispatcher,RtlDispatchException,Wow64PrepareForException(x64) и т.д


2 Anti-debug или защита на страже от названия окна.

Основное свойство – скудость. Разработчики пару раз уже пинали плагин
Пожалуйста, авторизуйтесь для просмотра ссылки.
,путём детекта дебаггера через названия окна.
Основываясь на списке импорта протектора,можно написать хуки для защита от обнаружения отладчика.
Протектор используется для anti-debug следующие WINAPI/NTAPI функции:
В прошлой стать забыл упомянуть про NtGlobalFlag :):

И название окон,которое он проверяет:

x32:
NtGlobalFlag
if(IsWow64Process(NtCurremtProcess,is_wow) && is_wow64)
peb64->NtGlobalFlag

x64/x32
CheckRemoteDebuggerPresent(NtCurrentThread)[прим:смотри статью про anti-debug].
NtQueryInformationProcess(NtCurrentPorcess):ProcessDebugPort,ProcessDebugObjectHandle.
GetForegroundWindow -> GetWindowTextA
NtSetInformationThread(NtCurrentThread):ThreadHideFromDebugger
GetThreadContext(dr0,dr1,dr2,dr3)
NtQuerySystemInformation:SystemModuleInformation -> CompareStringA
FindWindowA

Anti-attach(old):
DbgUiRemoteBreakin
LdrShutdownProcess
DbgBreakPoint

GetWindowTextA lpString:
x64:x64d
x32:OllyDbg,PhantOm,x32d,Shadow,[CPU,[*C.
CompareStringA:ntice.sys,iceext.sys.Syser.sys.HanOlly.sys.extrem.sys,FRDTSC.SYS,fengyue.sys.
FindWindowA(lpClassName):OLLYDBG, GBDYLLO,pediy06
Думаю,что не нужно объяснять,как бороться со стандартным NtQueryInformationProcess,NtSetInformationThread,GetThreadContext,FindWindowA.
Просто возвращаете,что протектор ожидает,а для CompareStringA возвращаете другое значение(кроме CSTR_EQUAL),если эти строки защищены.
С названием окна решил не бороться(можно переименовать,но просто пусть протектор думает,что у него всё в порядке) и просто удаляем строки из GetWindowTextA.


3 Anti-vm.

На самом деле anti-vm относительно лёгкий,но в прошлый раз хоть автор и показал все детекты,но не обошёл из-за своего косяка(слегка об этом позже).
Поверив сообщению Catharsis,автор купил медовуху и был готов провести вечер,чтобы обойти неприятный детект.
На самом деле достаточно написать хук для этих функций и пропатчить 2 момента, чтобы миновать обнаружение(проверенно на VMware,хотя должно работать и на VirtualBox(лень тестить,ели детект -напишите об этом).
Первым делом идёт проверка реестра и тут 2 функции достаточно хукнуть,чтобы обойти детект:RegQueryValueExA,RegOpenKeyExA.
RegOpenKeyExA: возвращаем ERROR_FILE_NOT_FOUND для HARDWARE\\ACPI\\DSDT\\VBOX__.
RegQueryValueExA:DriverDesc,SystemBiosVersion(x2),VideoBiosVersion.
SystemBiosVersion 1 вызов - проверка на строку VBOX.
SystemBiosVersion 2 вызов -> PRLS, Oracle
VideoBiosVersion -> Oracle, Parallel
DriverDesc -> VMware
GetSystemFirmwareTable with RSMB -> VMware

Автор попался на прикол со 2 вызовом in eax,dx (eax - 'VMXh"; dx - '..VX') т.к VMware был настроен не совсем корректно.
code_language.asm6502:
push dword ptr fs:[0x00000000]
mov dword ptr fs:[0x00000000], esp
mov eax, 0x68584D56 ('hXMV')
mov ecx, 0x14
mov dx, 0x5856 ('viXV')
in eax,dx
pop dword ptr fs:[0]
add esp,4
cmp eax,0
jbe  check_next
jmp  detect

detect:
    mov dword ptr ss:[ebp+0x3EA2A], 0x01
    jmp vm_entry

check_next:
  lea eax, ss:[ebp+0x168349]
  push eax
  push dword ptr fs:[0x00000000]
  mov dword ptr fs:[0x00000000], esp
  mov ecx,A
  mov eax,4855D704
  add eax,DF78164
  mov ebx,8685D465
  mov edx,34B640
  sub edx, 0x345FE8

  in eax,dx (eax - 'VMXh"; dx - '..VX')
  pop dword ptr fs:[0]
  add esp,4
  cmp ebx,564D5868
  jne vm_entry
  jmp detect

Тут всё просто с WINAPI:вызываем о очищаем плохие строки.
Можно было забить и настроить корректно VMware,но т.к дали подзатыльник - верну это благодать обратно.
1)Сканируем байты 'устойчивой инструкции'(при вызове GetModuleHandleA[см 1.3 пункт].
2)дизассемблируем и проверяем, что это наш пациент.
3)патчим на безусловный переход(или чтобы был ожидаемый eflag/rflag) или запись mov [is_detect_vm], 0x01.
Итог(пример с x32):

В SDK(CHECK_VIRTUAL_PC) в функции проверяется только значение is_vm_detect из лоадера.

4 Anti-analisys/anti-monitoring tools и anti-sandbox
Ничего нового в обходе.
Для детекта anti-monitoring tools используется:FindWindowA и NtQuerySystemInformation:SystemModuleInformation -> lstrcmpiA.
FindWindowA:
lpClassName:FilemonClass,PROCMON_WINDOW_CLASS,RegmonClass,18467-41,Registry Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
lpWindowName:Process Monitor - Sysinternals: www.sysinternals.com,File Monitor - Sysinternals:
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
lstrcmpiA:FileMonitor.sys,Filem,REGMON,regsys,sysregm,PROCMON,Kernel Detective,CisUtMonitor,Revoflt.
С FindWindowA без объяснения всё понятно,а с lstrcmpiA - просто нужно вернуть не NULL.


5 Anti-File Patching/CRC file и CRC runtime.

С crc file тут всё легко т.к это вам не VMP,где протектор проверяем результат в памяти,а не только файл на диске.
WINAPI,которые использует протектор:
GetModuleFileName
CreateFileW
GetFileSize
CreateFileMappingW
MapViewOfFile
UnmapViewOfFile
Не вижу смысл показывать алгоритм CRC file т.к атака может быть легче. Самый простой вариант - вернуть путь к оригинальному бинарнику.
Обход в примере проверяет с название _orig и перенаправляет, если существует скопированный файл.
Пример обхода:
Код:
static auto WINAPI create_filew
(
    LPCWSTR               lpFileName,
    DWORD                 dwDesiredAccess,
    DWORD                 dwShareMode,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    DWORD                 dwCreationDisposition,
    DWORD                 dwFlagsAndAttributes,
    HANDLE                hTemplateFile
) -> HANDLE
{
    uint32_t type_file = NULL;

    HMODULE mod_addr = NULL;
    HANDLE access = NULL;
    WCHAR path_bin[MAX_PATH] = { NULL };

    for (size_t i = 0; i < crc_file.mod_info.size(); i++)
    {
        if (!crc_file.mod_info[i].addr)
        {
            mod_addr = GetModuleHandleW(crc_file.mod_info[i].name_mod);
            crc_file.mod_info[i].addr = mod_addr;
        }
        else
        {
            mod_addr = reinterpret_cast<HMODULE>(crc_file.mod_info[i].addr);
        }

        if (mod_addr && GetModuleFileNameW(mod_addr, path_bin, sizeof(path_bin)))
        {
            if (!wstricmp(lpFileName, path_bin))
            {
                if (get_orig_file(path_bin, type_file))
                {
                    access = reinterpret_cast<decltype(&CreateFileW)>(crc_file.orig_create_filew)(path_bin, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
                    if (access == INVALID_HANDLE_VALUE)
                    {
                        access = reinterpret_cast<decltype(&CreateFileW)>(crc_file.orig_create_filew)(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
                    }
                    return access;
                }

            }
        }
    }
    return reinterpret_cast<decltype(&CreateFileW)>(crc_file.orig_create_filew)(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
Можно,конечно,найти где лежит crc и изменить его или хукать vm-cmp,но нас интересует простой обход и чтобы пришлось прикладывать минимум усилий для него.

C CHECK_CODE_INTEGRITY есть небольшая проблема. Найти по обращению к .text(themida делает проверку только для этой секции,что странно) секции саму проверку очень легко:
x64:

x32:

Но есть 1 момент:нельзя точно вычислить ожидаемое значение. Были попробованы варианты:
1)Возврат к коду юзера и изменение переменной, но user_value в x32 шифруется динамический, поэтому плохой вариант ( x32 Tiger red) .
2)Скопировать после распаковки и копировать эту память при начале выполнения CRC,но тут нужно узнать где находятся релоки,поэтому пропускаем этот вариант.
3)Дизассемблировать и хукать динамический jmp reg/call reg/ret ,так пока не дойдем до vm_handle-cmp,но лучше сделать через эмуляцию.
Здесь мы дожидаемся 1 выполнения подсчёта CRC и после этого просто будем возвращать ожидаемое значение.
Сам обход тривиален:
1)Ждём вызова VirtualAlloce(туда протектор берёт самую первую секцию и убирает релоки на NULL)
2)Берём 'устойчивую инструкцию',например, 'mov dword ptr ss:[rbp-20],eax'(x64)/'mov dword ptr ss:[esp],eax'(x32)
3)Сканируем секцию темиды на байты этой инструкции.
4)устанавливаем хук и пишем обработчик для этого.
Можно дотянуться до ожидаемого значения,но тут лучше прикрепить эмуляцию(возможно, когда руки дотянутся - опубликую пример).


6 Защита импорта или купить - нельзя, организовать - можно.

Здесь автор слегка удивился от 1 момента,который делает протектор.
Защита импорта является из тех немногих моментов,которые являются треугольной защитой при обфускации.
Найти момент,где идём получения импорта программы не супер сложно:

Однако,получения адреса module_base+rva_addr_api виртуализирован:

Предлагаю посмотреть,как выглядит оболочка обфусцированного импорта программы.
Если супер упрощать некоторые моменты,то ~так(основная логика):
Objective-C:
call qword ptr ds:[rva_jmp]
sub VSP,sizeof(PVOID);some time psuh rand_reg
call get_addr_protector
get_addr_protector:
    call winlicense_test_protected call $0
    pop rbp                               
    sub rbp,rva_sub                           get addr sec .themida
    ret
push qword ptr ds:[rax+rbp]
pop reg_use; rax
mov reg_use,ret_addr
add reg_use,const
sub reg_use,const
xor reg_use,const
and eax,const        ;const = -1
or rax,const
mov [rsp],rax
ret
Objective-C:
call dword ptr ds:[rva_jmp]
push reg, //sub VSP, sizeof(PVOID)
push dword ptr ss:[ebp+eax]
get_addr_protector:
    call winlicense_test_protected call $0
    pop ebp                               
    sub ebp,rva_sub                           get addr sec .themida
    ret
push dword ptr ss:[ebp+eax] ; [get_addr_protector+rva_crypt_imp]
pop reg_use;eax
sub reg_use,const
xor reg_use,const
mov [VSP],reg_use
//clean stack
ret

Но начиная выше версии(не могу сказать точно,но в версии 3.1.4.0+ присутствует) если 1 прикол:
Objective-C:
//imp get addr
xor reg_use,const
mov [VSP],reg_use
call fake_call_kernel32
ret

fake_call_kernel32:
cmp reg_use,kernel32_base+offset(base+last rva?+ offset?)
jbe failed
cmp reg_use,kernel32_base
jae do_call
jmp failed

failed:
ret

do_call:
cmp dword ptr ds:[addr_number_call],0x64
jae exit
add dword ptr ds:[addr_number_call],1
mov rcx,0
call qword ptr ds:[some_addr+rva_sleep]; call Sleep(NULL)
mov rcx,addr_str_len_1
call qword ptr ds:[some_addr+rva_lstrlen]; call lstrlen(addr_str_len_1)
ret
Скорее всего,это сделано против деобфускации импортов с помощи эмуляции(если не написана логика),но если бы разработчики не делали вызов через call [reg],а через push и ret,то многих реверсеров вы бы смогли удивить.Так же от версии к версии некоторые моменты могут слегка отличатся:
в x64 может,например, может быть 1 команда не add,а sub для расшифровки адреса импорта.
Мне лень разбираться,но перед ret идёт cmp [some_addr],NULL и дальше jne/jmp,поэтому просто делаем рекурсию,чтобы пропатчить оба ret_address.
Предлагаю написать хук для оболочки защиты импортов,чтобы можно было хукать их при вызове(или легировать с аргументами).
1)Сканируем байты 'push [reg+reg]'(при вызове GetModuleHandleA[см 1.3 пункт].
2)дизассемблируем и проверяем,что используются определённые команда для декрипта импорта
3)устанавливаем хук на ret и убираем бессмысленную проверку.
Пример результата:


Теперь вы можете просто добавить export в dll,а потом добавить импорт в нужный вам атакуемый файл,чтобы наша dll загружалась автоматический.
Это не влияет на функцию CHECK_PROTECTION из SDK,поэтому можно курить бамбук!
Спасибо за чтение статьи и всем хорошего настроения :).
При написании кода и статьи использовалось 2 медовухи, поэтому название себя оправдывает(или нет,если нужно было больше,но жду мнение алкоголиков👨‍🔧).
Сам
Пожалуйста, авторизуйтесь для просмотра ссылки.

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

P.S когда выравнивание текста сделают нормальным на этом форуме?
 
Последнее редактирование:
Сверху Снизу