Защита, использующая хасп-ключ. Часть 3: USB — Архив WASM.RU

Все статьи

Защита, использующая хасп-ключ. Часть 3: USB — Архив WASM.RU

Пояснение к третьей части

  Данная статья является расширением к моим статьям ("Защита, использующая хасп-ключ" и "Защита, использующая хасп-ключ. Часть 2"), посвященным анализу защиты этой программы.

  В первой статье был приведен поверхностный анализ этой защиты, исследовалась возможность эмуляции ключа на уровне команд ввода-вывода и необходимые действия для борьбы с приложением, препятствующим перехвату ввода-вывода (регистры отладки DRx).

  Во второй части было описано, как именно устроен код, общающийся с ключом и реализующий так называемые "функции" хасп-ключа и исследован метод эмуляции не отклика самого ключа (команды ввода-вывода), но эмуляции функций хасп-ключа.

  Первая и вторая части были посвящены ключу для LPT-порта, обладающему памятью порядка 128 байт и содержащему одну "секретную" функцию SeedCode. В настоящем документе будет исследоватся защита, основанная на другом ключе, использующем USB-порт. Различие этих ключей, конечно, не в том, что они используют различные интерфейсы, но в том, что новый ключ (предположительно Hasp Time 4) способен реализовать по крайней мере две новые функции (кроме новой SeedCode): функцию таймера и функцию типа Decrypt_Data - расшифровка указанной последовательности. Все исследования относительно ключа носят оценочный характер и не претендуют на полноту, однако прога все же запускается ;)

  Все исследования проводились в win98.

Общее описание структуры защиты новой версии

  Состав защиты. В новой версии участвуют "старые" драйвера: HASP.VXD и HARD.VXD (большой, после установки драйвера защиты новой версии он весит полмегабайта), но есть и новые, причем другого формата: это AKS.SYS (~20 килобайт). Последний является промежуточным звеном между HARD.VXD и драйверами системы: драйверами USB-порта (например, uhcd.sys) и HAL.DLL. HAL.DLL реализует так называемый уровень абстракции устройства: общение с ключом ведется не на уровне команд in/out, но через переходники типа READ_PORT_USHORT и т.д.

  Общая схема взаимодействия драйверов может быть представлена следующим образом:

Приложение win32 | | Исключение UD | | DeviceIoControl | | |---> HASP.VXD | | | | Directed_Sys_Control | | UD | HARD.VXD | | | | AKS.SYS entry point | | ----- AKS.SYS | | UHCD.SYS HALL.DLL ...ETC

  Итак, приложение использует api DeviceIoControl для общения с HASP.VXD и вызывает исключение UD, которое обрабатывает также HASP.VXD. Но если в прежней версии программы исключение UD являлось основным для проверки ключа (см. мою вторую статью) - на этом исключении было построено что-то вроде api-функций 01,02,..0Bh, причем функция 0Bh этого исключения именно проверяла ключ и получала из него данные, то в последней версии исключению UD отводится вспомогательная роль: используются подфункции 01..07, занимающиеся за/расшифровкой блоков данных по достаточно тривиальным алгоритмам:

... ; Расшифровка тела запроса по способу UD pushad ; eax=lpvOutBuffer mov eax,[esi].lpvOutBuffer ; Расшифровать буфер по способу F=06 #6 mov ecx,28h lea ebx,[eax+14h] @@DecryptOutBuffer: xor byte ptr [ebx],0AAh ror byte ptr ds:[ebx],4 inc ebx loop @@DecryptOutBuffer ... ; Зашифровать буфер по способу F=04 #6 mov ecx,28h lea ebx,[eax+14h] @@EncryptOutBuffer: rol byte ptr ds:[ebx],4 xor byte ptr ds:[ebx],0AAh inc ebx loop @@EncryptOutBuffer popad

  Но общение приложения через api DeviceIoControl является основным (или еще не все проверено). Далее HASP.VXD транслирует запрос DeviceIoControl напрямую в HARD.VXD. Таким образом, в новой версии этому драйверу отводится вспомогательная роль.

  HARD.VXD занимается непосредственно обработкой таких запросов, реализует сам некоторую часть функций ключа, но и часть работы переадресует "драйверу USB-ключа" - AKS.SYS. Сам HARD.VXD предположительно не выполняет никаких обращений к портам ключа, прямо или косвенно (READ_PORT_USHORT и т.д.). Этот драйвер отличает крайняя степень "антиотладочного" кодирования: обилие команд типа xchg ebp,edi+xchg edi,ebp или add eax,0 и т.п., впрочем никак не мешающих трассировке в Soft-Ice, но делающих неудобным исследование.

  AKS.SYS по-видимому, выполняет самую низкоуровневую реализацию функций ключа: именно он работает с системным драйвером USB-порта (UHCD.SYS). Скорее всего он реализует (частично) функцию ключа Decrypt_Data. Этот драйвер выгодно отличается от предидущего размером (выше) и отсутствием антиотладочных приемов. Впрочем, в нем есть функции вызова исключения UD (из HASP.VXD - на рисунке это показано обратной стрелочкой), но только вот эти функции почему-то не вызываются.

  Немного про драйвер USB, работающий с ключом, хотя непосредственного отношения к защите он не имеет. Драйвер реализует два асинхронных сервиса, которые переодически вызываются VMM. В них он опрашивает ключ. Исследования лога на команды ввода-вывода (лог может быть безболезненно получен как перехватом in/out через DRx так и перехватом READ_PORT_USHORT) показывают, что ключ выдает что-то подобное значению инкрементального 11-ти битного счетчика с приращением в пределах 100-110 на одно чтение. Эмуляция этого счетчика мне пока не удалась. Видимо, этот счетчик и является функцией Time этого типа ключа. Попытка подстановки заранее записанного лога была выполнена успешно, однако такая эмуляция работает лишь при вставленном ключе ;) Это может свидетельствовать о сигнале irq при вытаскивании ключа и обрабатываемым отдельным сервисом не через основные порты ключа (например, 900x). Факт отсутствия ключа в этом случае может быть проверен драйвером защиты через другие каналы, но в данной статье эта возможность не исследовалась.

  Таким образом основным "узким местом" и - самое главное - предположительно единственным является общение приложения с драйвером HASP.VXD через DeviceIoControl. Именно на этом участке будет сосредоточено все внимание в дальнейшем.

Описание протокола DeviceIoControl

  Перехват и логгирование. Не представляет трудностей; было выполнено через врезку jmp (jnz) внутри Control_Proc HASP.VXD:

; VxD entry point 010B: 83F807 cmp eax,007 010E: 0F84ECFEFFFF je .000000000 0114: 83F809 cmp eax,009 ... 0126: 83F802 cmp eax,002 0129: 0F84EBFEFFFF je .00000001A 012F: 83F823 cmp eax,023 0132: 0F8466FFFFFF je .00000009E <<< Change to jz Our_Trap 0138: 83F81B cmp eax,01B 013B: 74AF je .0000000EC 013D: 83F81C cmp eax,01C 0140: 74B9 je .0000000FB

  Эта область драйвера (Control_Proc VXD) не проверяется защитой на перехват (в отличии от тела драйвера: см. вторую статью). Сообщение 23h (DeviceIoControl) перехватывается драйвером-эмулятором. Перехват выполняется следующим образом: эмулятор перехватывает сообщения Directed_Sys_Control стандартным образом при запуске (через VMM) и ожидает сообщения, адресованного VMM драйверу HASP.VXD (фильтр на ID). Такое сообщение будет послано VMM при загрузке драйвера через CreateFile (сообщение DIOC_OPEN). После этого выполянется перехват обработки DeviceIoControl.

  После реализации перехвата начинаем записывать лог общения приложения через DeviceIoControl. Напомню вкратце основные параметры этого сообщения: при вызове функции F23 драйвер VXD получает следующую структуру по esi:

DIOCParams STRUC Internal1 DD ? VMHandle DD ? Internal2 DD ? dwIoControlCode DD ? lpvInBuffer DD ? cbInBuffer DD ? lpvOutBuffer DD ? cbOutBuffer DD ? ...

  Приведены не все поля, но даже из приведенных нас будет интересовать только два: dwIoControlCode - код подфункции функции F23 и lpvOutBuffer - адрес буфера, в который VXD может записать какие-то данные.

  Исследования лога показало, что приложение вызвает этот сервис с следующими значениями dwIoControlCode: 2,3 и 4. Причем буфер ответа (lpvOutBuffer) модифицируется драйвером только в случае dwIoControlCode=2. В остальных случаях (3,4) этот буфер не изменяется или указатель на него не передан. Естественным является попытка простейшей эмуляции подфункций 3 и 4: просто возврат с успешным результатом (eax=0, clc) и это ... срабатывает !

  Идем далее. Анализируем только подфункцию 2. Обнаруживаем, что во всех случаях размер буфера ответа одинаков и равен 48h (поле cbOutBuffer). Делаем записи этой длины буфера до и после выполнения обработки его HASP.VXD.

  Анализ запросов/ответов подфункции 2 показал, что структура пакета длиной 48h может быть описана примерно так:

; ; Структура пакета запроса F23, подфункция 2 ; tF23Packet struc ; Неизменяемая часть Type1 dd ? ; Всегда 1 Type2 dd ? ; Всегда 1 MagConst1 dd ? ; 6C687368h = "hshl" Len1 dd ? ; 48h - длина пакета ? Len2 dd ? ; 28h - длина шифрованной части ; Encrypted data, зашифрована по способу функции 6 исключения UD (28h bytes) MagConst2 dw ? ; 1D4Ch FuncNum dw ? ; Номер подфункции в виде WORD (01/03/05/06/32h/3ch/3dh) F32Data dd ? ; 0 для всех, кроме 32h - для нее: FC20h,FBD4h.. F3_6_32Data dd ? ; C9h для подфункций 03,06,32h Const1 dd ? ; Типа CDA03B6Dh - возможно, адрес в VXD (VTD.VXD ??) Const2 dd ? ; 818070CBh - возможно, адрес в win32 ; Changed data - то, что код драйвера может модифицировать Var1 dd ? ; 01,05: 0->1 ; 06: 0->DB3Fh ; 32: 4->4,0->0 (not changed) ; 03: 26h->26h, 3->3 (not changed, seed argument) ; 3c,3d: ->0 Var2 dw ? ; 01,05: 0->1 ; 06: 0->7D95h ; 32: 5->5 (not changed, seed argument) ; 03: 0->7875h, 0->3800h (seed 16 bits) ; 3d: size of encrypted data ; 3c: -> Var7 Var3 dw ? ; 01,03,05,06: 2742h->0 ; 32: 2742h->2742h (not changed) Var4 dd ? ; 01,32: 0->0 или C9h->0 ; 05: 0->C9h ; 03,06: C9h->0 Var5 dd ? ; 01,03,06,32: 0->0 (not changed) ; 05: 0->1F4Ah Var6 dd ? ; 0 - const Var7 dd ? ; 01,03,05,06: 0->0 (not changed) ; 32: 0->1, 1->5 (Var7:=Var2) StackAddr dd ? ; Address in stack (0069FC20h) for f32 or f3d tF23Packet ends

  Итак, что видно из этого пакета ? Во-первых, общение реализовано через подфункции (поле FuncNum), которые могут быть следующими: 1,3,5,6,32h,3ch,3dh. Следовательно, дальнейший разбор можно проводить для каждой функции отдельно. Следует заметить, что часть пакета приходит в драйвер в зашифрованном виде: это 28h байтов начиная с поля MagConst2. Шифрование выполняется приложением перед вызовом api DeviceIoControl через вызов исключения UD (см. выше). Драйвер HASP.VXD получает управление и вызывает уже внутри себя собственный обработчик исключения UD для дешифровки.

  Анализ пакетов для различных подфункций выполнялся следующим образом. Допустим, есть пакет для подфункции 01. Изучаем, что изменяет в ответном пакете эта функция. Обнаруживаем, что она меняет поля Var1, Var2, Var3 и Var7 в ноль, остальные поля не трогает или заполянет их нулями. Делаем то же самое в эмуляторе, но управление уже не передаем в HASP.VXD и убеждаемся, что это работает ! Таким образом были пройдены функции 1,5,6 и 3c. В случае других функций ситуация была несколько сложнее: например, функция 3 возвращала от раза к разу различные поля Var2 и входные значения Var1 были всякий раз различными. Однако можно было проследить однозначность значений этих полей, т.е. Var2=f(Var1), размер - word. На основе исследований ключа на LPT легко экстраполировать функцию SeedCode того ключа на этот случай; так и оказалось: функции 3 и 32h реализуют некую NewSeedCode на основе таблицы ~40h word'ов. Только функция 3 отвечает одним word из этой таблицы, т.е. f3=TableSeed(Var1), а функция 32h возвращает указанное в Var2 число Seed'ов по адресу, расположенному в поле StackAddr пакета (в область приложения). Полную таблицу Seed'ов я получил собственным вызовом драйвера со всеми возможными значениями входного аргумента.

  Особый случай представляет функция 3d. Эта функция выполняет дешифрацию байт длиной, указанной в поле Var2 пакета по адресу в поле StackAddr. Длины для дешифрации бывают только 8 или 10h байт.

  Что же за алгоритм дешифрации применила защита ? Может быть все: и DES, и самоделка и все, что угодно. Однако до сих пор мы не лезли с "ключом на двенадцать" в драйвера, а получили информацию изучая логи, что гораздо элегантнее. Однако кое-что мы можем узнать и без реверсинга, а только лишь задавая входные данные для функции шифрования.

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

  Выясняем размер блока шифрования (если это блочный алгоритм). Допустим, длина блока 64 бита, тогда первые 8 байт должны расшифровываться независимо от того, чему равны предидущие: например, 8-мь нулей и 00 должны быть расшифрованы так же, как и 8-мь нулей и FF (только первые 8 байт, конечно). На первый взгляд это именно так, но !! - расшифровка следующих 8-ми байт происходит ... независимо от их входных значений ! Т.е. первые 8-мь входных байт являются "ключом", он же (измененный) укладывается назад и последующие байты формируются только на основе первых 8-ми.

  Да, пожалуй - все. Приходится лезть в драйвер за информацией о способе шифровки. Довольно быстро, поставив bpm на данные, переданные для дешифрации HASP.VXD в HARD.VXD получаем несколько бряков. Обнаруживаются следующие узлы шифрования:

; Первый цикл: esi = указатель на 8-мь входных байт mov dword ptr Count,0 mov esi,offset TestBytes @@Decrypt1: mov edi,[esi] mov edx,edi xor edx,05B2C004Ah mov ecx,dword ptr Count mov eax,0FFFFFFF9h sub eax,ecx and eax,1Fh mov ecx,20h mov ebx,edx sub ecx,eax shr ebx,cl mov ecx,eax mov eax,[esi+4] shl edx,cl mov [esi+4],edi or ebx,edx xor ebx,eax mov [esi],ebx add dword ptr Count,5 cmp dword ptr Count,1Eh jb @@Decrypt1 ; Второй цикл: esi = указатель на 8-мь входных байт .data? Tmp dd ? .code mov esi,offset TestBytes mov eax,[esi] mov ebx,[esi+4] mov dword ptr [esi],ebx ^ HASP_Decrypt_Data[eax] ; ? mov [esi+4],eax xor edi,edi @@Decrypt2: mov edx,[esi] mov eax,0Ah sub eax,edi mov Tmp,edx and eax,1Fh xor edx,803425C3h mov ecx,20h mov ebx,edx sub ecx,eax add edi,2 shr ebx,cl mov ecx,eax shl edx,cl mov ecx,Tmp or ebx,edx mov edx,[esi+4] xor ebx,edx cmp edi,0Ch mov [esi],ebx mov [esi+4],ecx jb @@Decrypt2 ; Final mov esi,offset TestBytes mov eax,[esi] mov ebx,eax xor ebx,HASP_Decrypt_Data[eax] mov [esi],ebx mov [esi+4],eax ; В [esi] - первые 8-мь расшифрованных данных

  Обращаю внимание на то, что это лишь часть алгоритма - есть еще два вызова HASP_Decrypt_Data. Эту функцию с большой вероятностью реализует уже не HARD.VXD, но AKS.SYS. Возможно для этой функции не требуется большого объема данных для эмуляции (как для SeedCode/NewSeedCode) или вообще она реализуется минимальными средствами. По крайней мере в некоторых источниках я видел изображение этого ключа с подписью "ключ взломан" (сайт MeteO) - вполне вероятно, что эмулировать HASP_Decrypt_Data и означает окончательно добить эту защиту.

  Однако эмуляция этой функции может быть реализована гораздо проще ! Анализ логов показал, что эта функция вызывается не более 8-ми раз (!), да и то при запуске программы. Вполне возможно, что при открытии очередного модуля будут сделаны и другие вызовы, но ! никто не мешает пройти их по очереди или выполнить полный цикл каких-либо штатных действий до полного выписывания всех запросов функции 3d. Однако в первом приближении я не заметил таких вызовов; вызываются всякие разные успешно эмулируемые функции, но не сильнейшая. Интерес представляет также поиск сигнатур в исполняемом модуле на предмет обнаружения всех возможных данных, которые могут быть переданы для дешифрации функции 3d: допустим, всегда эти данные заканчиваются 8-мью нулями и т.п.

Небольшое заключение

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

  Спасибо всем прочитавшим :)

Полный текст эмулирующего драйвера и приложения

; ; *************** Инклюд-файл ******************** ; MAX_LOG_RECORDS equ 200 OpCodesSize equ 4 ; Packet for F23 trapping PacketF23 equ 0 InBufferSize equ 48h OutBufferSize equ 48h ; 15E8h Func3dArgSize equ 08h Func3dAnsSize equ 10h tLogF23Packet struc PacketType db ? ; Тип пакета FuncNum dw ? ; Номер подфункции в виде WORD (01/03/05/06/32h/3ch/3dh) RegEAX dd ? ; Регистр EAX dwIoControlCode dd ? ; Код функции от приложения lpvInBuffer dd ? ; Указатель на данные, переданные приложением cbInBuffer dd ? ; Размер переданных данных lpvOutBuffer dd ? ; Указатель на данные для ответа VxD cbOutBuffer dd ? ; Размер данных для ответа (max) lpcbBytesReturned dd ? ; Сколько байтов вернули OutBuffChanged db ? ; Изменен буфер обмена OutBufferBefore db OutBufferSize dup(?) OutBuffer db OutBufferSize dup(?) F32Arg dd ? ; Аргумент функции F32 F32Seed dd ? ; Ответ функции F32 ; Данные подфункции f3d Func3dArg db Func3dArgSize dup(?) Func3dAns db Func3dAnsSize dup(?) Func3dNotEmul db ? ; Успешно эмулирована функция f3d tLogF23Packet ends ; Packet for UD trapping PacketUD equ 1 tLogPacket struc PacketType db ? ; Тип пакета RegEAX dd ? ; Регистр EAX RegEDI dd ? ; Регистр EDI tLogPacket ends ; Размер пакета (= максимальный размер из всех пакетов) LogPacketSize equ sizeof(tLogF23Packet) DeviceBig_ID equ 3543h DeviceLitt_ID equ 3CDCh ; ID of little VxD NumberOfUDTraps equ 17 ; Число всех вызовов исключения UD с функцией 0Bh SelfCallUD6 equ 40666666h ; Номер собственной функции для UD6 ; ; Структура пакета запроса F23, подфункция 2 ; tF23Packet struc ; Неизменяемая часть Type1 dd ? ; Всегда 1 Type2 dd ? ; Всегда 1 MagConst1 dd ? ; 6C687368h = "hshl" Len1 dd ? ; 48h - длина пакета ? Len2 dd ? ; 28h - длина шифрованной части ; Encrypted data, зашифрована по способу функции 6 исключения UD (28h bytes) MagConst2 dw ? ; 1D4Ch FuncNum dw ? ; Номер подфункции в виде WORD (01/03/05/06/32h/3ch/3dh) F32Data dd ? ; 0 для всех, кроме 32h - для нее: FC20h,FBD4h F3_6_32Data dd ? ; C9h для подфункций 03,06,32h Const1 dd ? ; Типа CDA03B6Dh - возможно, адрес в VXD (VTD.VXD ??) Const2 dd ? ; 818070CBh - возможно, адрес в win32 ; Changed data - то, что код драйвера может модифицировать Var1 dd ? ; 01,05: 0->1 ; 06: 0->DB3Fh ; 32: 4->4,0->0 (not changed) ; 03: 26h->26h, 3->3 (not changed) Var2 dw ? ; 01,05: 0->1 ; 06: 0->7D95h ; 32: 5->5 (not changed) ; 03: 0->7875h, 0->3800h Var3 dw ? ; 01,03,05,06: 2742h->0 ; 32: 2742h->2742h (not changed) Var4 dd ? ; 01,32: 0->0 или C9h->0 ; 05: 0->C9h ; 03,06: C9h->0 Var5 dd ? ; 01,03,06,32: 0->0 (not changed) ; 05: 0->1F4Ah Var6 dd ? ; 0 - const Var7 dd ? ; 01,03,05,06: 0->0 (not changed) ; 32: 0->1, 1->5 (Var7:=Var2) StackAddr dd ? ; Address in stack (0069FC20h) for f32 tF23Packet ends ; ; *************** Драйвер ******************** ; ; Программа - перехват исключения UD ; Coded by Chingachguk. 2004. ; .586p include vmm.inc include vwin32.inc DECLARE_VIRTUAL_DEVICE UD1C,1,0, UD1C_Control,\ UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER Begin_control_dispatch UD1C Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl Control_Dispatch DESTROY_PROCESS, OnDESTROY_PROCESS End_control_dispatch UD1C ; Сегмент данных VxD include 1c06.inc VxD_LOCKED_DATA_SEG ; Буфер лога LogPtr dd 0 ; Указатель лог-буфера LogPackets db (MAX_LOG_RECORDS * LogPacketSize) dup (?) old_ud06handler dd 0 ; Адрес обработчика UD в VxD old_14handler dd ? ; Адрес обработчика PageFault в VxD DDB dd ? ; Адрес Device Block VxD ; Переменные для перехвата Control_Proc VxD F23Addr dd 0 ; Адрес начала проверки cmp eax,23h F23JmpFound dd 0 F23EntryPoint dd ? ContinuePoint dd ? RestoreJmpArg dd ? ; Аргумент jmp - saved DirectedSysLocked dd 0 ; Флаг перехвата функций VxD pPrevHook_Directed_Sys_Control dd ? UD14EntryPoint dd 0 ; Точка входа в #14 UD6EntryPoint dd 0 ; Точка входа в #UD6 Hook14Count dd 0 ; Число вызовов исключения Page Fault HookUDCount dd 0 ; Число вызовов UD6 SaveSEHProc dd ? ; Адрес начального обработчика SEH StepNum dd ? ; Номер блока шагов по 126 CounterCalls14Step2 dd 0 ; Отладка - счетчик вызовов #14 на шаге 2 CrcProcHookAddr dd ? ; Адрес точки перехвата crc-процедуры AfterCrcProcHookAddr dd ? ; Адрес возврата после перехвата crc-процедуры LastPacketPtr dd ? ; Указатель на последний пакет при перехвате F23 NeedForExecuteF23 dd ? ; Флаг необходимости вызова оригинальной F23 ; Таблица для подфункции f32 f32Table label word dw 00001h ;00 dw 00000h ;01 dw 00000h ;02 dw 03800h ;03 dw 06a02h ;04 dw 0fedbh ;05 dw 06b1eh ;06 dw 01be4h ;07 dw 0b0dbh ;08 dw 06e0dh ;09 dw 0d84ch ;0a dw 0ceb6h ;0b dw 0ec39h ;0c dw 003cdh ;0d dw 0d155h ;0e dw 039d1h ;0f dw 0de19h ;10 dw 0a6ddh ;11 dw 08f5bh ;12 dw 0ea67h ;13 dw 02984h ;14 dw 0b4ech ;15 dw 069bch ;16 dw 096a6h ;17 dw 08cb3h ;18 dw 0090eh ;19 dw 0fd37h ;1a dw 06e4eh ;1b dw 04cb6h ;1c dw 03e1dh ;1d dw 03fb6h ;1e dw 0a864h ;1f dw 0c9f8h ;20 dw 09f29h ;21 dw 0c80ah ;22 dw 065cah ;23 dw 02a04h ;24 dw 06194h ;25 dw 07875h ;26 dw 0393fh ;27 dw 0ae21h ;28 dw 04ebfh ;29 dw 04bbah ;2a dw 01826h ;2b dw 0bf20h ;2c dw 0e760h ;2d dw 05736h ;2e dw 0e6e0h ;2f dw 04e24h ;30 dw 081b1h ;31 dw 03e6eh ;32 dw 0e436h ;33 dw 011a6h ;34 dw 0135eh ;35 dw 00d07h ;36 dw 05052h ;37 dw 05052h ;38 dw 05052h ;39 dw 05052h ;3a dw 05052h ;3b dw 05052h ;3c dw 05052h ;3d dw 05052h ;3e dw 05052h ;3f dw 05052h ;40 dw 05052h ;41 dw 05052h ;42 dw 05052h ;43 dw 05052h ;44 dw 05052h ;45 dw 05052h ;46 dw 05052h ;47 dw 05052h ;48 dw 05052h ;49 dw 05052h ;4a dw 05052h ;4b dw 05052h ;4c dw 05052h ;4d dw 05052h ;4e dw 05052h ;4f Func3dArgsAnswersSize equ 8 Func3dArgsAnswers label byte db 0dbh,0feh,01eh,06bh,0e4h,01bh,0dbh,0b0h db 095h,078h,04bh,035h,05eh,0bch,0dch,048h,06ch,08ah,0e2h,00dh,022h,0bah,0f8h,0c3h db 05eh,022h,0e1h,05eh,04eh,0c8h,003h,02fh db 08bh,00eh,068h,014h,0beh,044h,000h,056h,027h,0d7h,0bah,0a4h,0fah,0d7h,01eh,0d8h db 080h,030h,0d4h,000h,0a8h,052h,006h,01eh db 050h,08ah,02dh,01bh,000h,05bh,0dah,0e7h,000h,000h,000h,000h,000h,000h,000h,000h db 0b8h,052h,003h,027h,080h,030h,0d4h,000h db 0a6h,016h,0ach,0eeh,08bh,0b9h,0efh,059h,000h,000h,000h,000h,000h,000h,000h,000h db 0b5h,019h,0cch,006h,097h,021h,0b9h,097h db 0e8h,09fh,02fh,0ffh,0ffh,08bh,0f0h,085h,093h,04ch,07dh,07bh,0cdh,061h,0a0h,030h db 0ech,059h,02dh,01eh,0fch,040h,008h,001h db 0ffh,0eah,0b4h,0aeh,0beh,02ch,050h,024h,000h,000h,000h,000h,000h,000h,000h,000 db 034h,05dh,0cdh,000h,00ch,0fch,069h,000h db 03dh,06fh,0aah,0b6h,060h,0b8h,073h,029h,000h,000h,000h,000h,000h,000h,000h,000 db 007h,0d4h,071h,05bh,0bbh,0b7h,0e3h,02dh db 0e8h,093h,031h,0ffh,0ffh,08bh,0f0h,085h,093h,04ch,07dh,07bh,08eh,090h,0b9h,0e3h VxD_LOCKED_DATA_ENDS ; А вот наш сегмент кода. VxD_LOCKED_CODE_SEG ; ; Сообщение DESTROY_PROCESS: ; BeginProc OnDESTROY_PROCESS ; деинсталлируем все перехваты ; Инсталляция ловушек уже была ? cmp dword ptr ds:DirectedSysLocked,0 jz @@ContinueHook ; Убираем перехват. ; Деинсталляция перехватчиков (UD) call Uninstall_Handlers ; Мы опять готовы приступить к перехвату. mov dword ptr ds:DirectedSysLocked,0 @@ContinueHook: xor eax,eax clc ret EndProc OnDESTROY_PROCESS ; ; Сообщение DeviceIoControl ; BeginProc OnDeviceIoControl ; Сделаем так, чтобы esi был адресом переданной нам структуры - DIOCParams. assume esi:ptr DIOCParams ; При загрузке VxD в память система позовет ее с контрольными сообщениям .if [esi].dwIoControlCode==DIOC_Open ; Контрольное сообщение ?! ; ; Установка перехватчика Directed_Sys_Control: ; ; Он ожидает сообщения от VMM для Hasp.vxd и перехватывает обработчик #06 ; ; Перехватываем функцию VMM "Directed_Sys_Control" ; *** ; INT 20 P - Microsoft Windows - 0147h "Directed_Sys_Control" ; VxD = 0001h ; 0147h "Directed_Sys_Control" mov eax,00010147h mov esi,offset32 Hooked_Directed_Sys_Control int 20h ; Call VxD dw 0090h ; 0090h hook device service dw 0001h ; ID VMM mov eax,-1 jnc @@HookDirected_Sys_ControlOK xor eax,eax @@HookDirected_Sys_ControlOK: xor eax,eax ; Надо отвечать: eax=0. ; ; Сигнал завершения работы ; .elseif [esi].dwIoControlCode==DIOC_Closehandle ; *** ; Освобождаем "Directed_Sys_Control" ; *** mov eax,00010147h mov esi,offset32 Hooked_Directed_Sys_Control int 20h ; Call VxD dw 011Ch ; 011Ch unhook device service dw 0001h ; ID VMM ; ; Запрос на выдачу буфера лога ; .elseif [esi].dwIoControlCode==1 ; Получим адрес переданной нам структуры InBuffer в регистр ebx mov ebx,[esi].lpvInBuffer mov edi,[ebx] ; указатель на буфер, который нам передал win32-код mov esi,offset32 LogPtr cld lodsd stosd imul eax,eax,LogPacketSize mov ecx,eax test eax,eax jz @@NoLogData rep movsb @@NoLogData: call Uninstall_Handlers xor eax,eax ; Вернем в eax флаг ошибки .endif ret EndProc OnDeviceIoControl ; ; ************************** SUBPROGRAMS *********************************** ; ; ; подпрограмма - перехватчик функции 23h - DeviceIOControl: ; ожидает сообщения от VMM для hasp.vxd и перехватывает ud6 и F23 ; BeginProc Hooked_Directed_Sys_Control, HOOK_PROC, pPrevHook_Directed_Sys_Control, LOCKED push ebp mov ebp,esp pushfd ; Remember, hooks must preserve all regs pushad ; ; Если обращение к Big, то возвращаем OK ; cmp word ptr [ecx+6],DeviceBig_ID ; jnz @@NotBigVXD ; ; popad ; popfd ; pop ebp ; xor eax,eax ; clc ; ret @@NotBigVXD: ; Нужно ли мониторить этот вызов ? cmp word ptr [ecx+6],DeviceLitt_ID jnz @@ItNotIsOurVxD ; Инсталляция обработчиков ud06 и F23 (если возможно) cmp dword ptr ds:DirectedSysLocked,0 jz @@HookFunctions jmp @@AlreadyHooked @@HookFunctions: mov dword ptr ds:DirectedSysLocked,1 ; ; Инсталлируем перехватчик #6: ; ; ;9B4D: jmp 9B63 EB 14 ; db 'GenuineDevil' = db 47,65,6E,75,69,6E,65,44,65,76,69,6C ; db 06,00,01,03,48,24,00,00 ;9B63: 1E push ds ;9B64: 06 push es ;9B65: 50 push eax [ebp+10h] ;9B66: 51 push ecx [ebp+0Ch] ;9B67: 52 push edx [ebp+8] ;9B68: 57 push edi [ebp+4] ;9B69: 55 push ebp [ebp+0] ;9B6A: 8BEC mov ebp,esp ;9B6C: 668CD0 mov ax,ss ;9B6F: 668ED8 mov ds,ax ;9B72: 668EC0 mov es,ax ;9B75: 55 push ebp ;9B76: 9C pushfd ;9B77: E800000000 call 000009B7C ;9B7C: 5D pop ebp ;9B7D: 81ED780E0000 sub ebp,000000E78 ;9B83: 9D popfd ;9B84: 0F014D00 sidt [ebp][00] ; Второй вариант, начало #6 ;29AE: EB18 jmps .0000029C8 ;29B0: db 47,65,6E,75,69,6E,65,44,65,76,69,6C ;29BC: 06,00,02,00,94,23,00,00,00,24,00,00 ;29C8: 1E push ds << jmp Our_Trap_Program ;29C9: 06 push es ;29CA: 50 push eax ;29CB: 51 push ecx ;29CC: 52 push edx ;29CD: 57 push edi ;29CE: 55 push ebp ;29CF: 8BEC mov ebp,esp ;29D1: 668CD0 mov ax,ss ;29D4: 668ED8 mov ds,ax ;29D7: 668EC0 mov es,ax ;29DA: 55 push ebp ;29DB: 9C pushfd ;29DC: E800000000 call .0000029E1 ;29E1: 5D pop ebp ;29E2: 81EDBD0E0000 sub ebp,000000EBD ;29E8: 9D popfd ;29E9: 0F014D00 sidt [ebp][00] ; Получить адрес control'а vxd call GetLitt_DDB mov eax,dword ptr ds:DDB test eax,eax jz @@VxDNotFound mov eax,dword ptr [eax+18h] ; Ищем байты начала #06. Это вторая строка 'GenuineDevil' (первая - #14) mov ecx,0FFFFh xor ebx,ebx @@FindUDEntryPoint: cmp dword ptr ds:[eax],0756E6547h jnz @@NextByteScan cmp dword ptr ds:[eax+4],044656E69h jnz @@NextByteScan test ebx,ebx jz @@UD14EntryPointFound ; Найден обработчик UD - int 6 lea edx,[eax-2] mov dword ptr ds:UD6EntryPoint,edx jmp @@ScanForUdDone ; Найден обработчик #14 - PageFault @@UD14EntryPointFound: inc ebx lea edx,[eax-2] mov dword ptr ds:UD14EntryPoint,edx @@NextByteScan: inc eax loop @@FindUDEntryPoint jmp @@NotSetup ; Найдены адреса входа в оба обработчика @@ScanForUdDone: ; Вписать команду перехода в тело обработчика #6 ;; call Install_Jmp_Into_UD6 ;; jmp @@SkipF23 ; Найти команду перехода на 23 в VxD-обработчике (control proc) ; Это две команды: ; cmp eax,23h ; 83 F8 23 ; jz @L ; 0F 84 66 FF FF FF mov eax,dword ptr ds:DDB mov eax,dword ptr [eax+18h] ; Control proc ; Найти команды перехода на инсталлятор mov ecx,0FFFFh @@FindJmp23: cmp dword ptr [eax],0F23F883h jnz @@PrevByte cmp dword ptr [eax+4],0FFFF6684h jnz @@PrevByte ; Дезактивировать старые команды перехода, ; запомнив их адрес mov dword ptr F23Addr,eax mov dword ptr F23JmpFound,1 jmp @@InstallerFound @@PrevByte: inc eax loop @@FindJmp23 jmp @@NotSetup @@InstallerFound: ; Установить перехватчик функции 23h ; Запомнить EntryPoint функции 23h mov ebx,dword ptr F23Addr add ebx,3 ; Адрес jz @@F23 lea eax,[ebx+6] ; Адрес следующей команды после jz @@F23 ; Запомнить ее mov ContinuePoint,eax add eax,[ebx+2] ; Входная точка F23 mov F23EntryPoint,eax ; Вписать в команду jz @F23 адрес нашего обработчика F23 lea eax,[ebx+6] ; Адрес следующей команды после jz @@F23 sub eax,offset32 HookControl neg eax ; Размер перехода ; Сохранить ее для восстановления mov edx,dword ptr [ebx+2] mov dword ptr [ebx+2],eax ; Переход на Trap mov dword ptr RestoreJmpArg,edx @@SkipF23: ; Счетчик вызовов int 6 mov dword ptr ds:HookUDCount,0 @@VxDNotFound: @@NotSetup: @@AlreadyHooked: @@ItNotIsOurVxD: ; Продолжение выполнения popad popfd pop ebp jmp [pPrevHook_Directed_Sys_Control] ; Chain to previous hook EndProc Hooked_Directed_Sys_Control ; ; Деинсталляция перехватчиков UD6 и 23h ; Uninstall_Handlers proc pushad cmp dword ptr F23JmpFound,0 jz @@WasNotInstalled ; Восстановить команду перехода на функцию 23h ; cmp eax,23h ; 83 F8 23 ; jz @L ; 0F 84 66 FF FF FF ; Получение адреса обработчика mov ebx,dword ptr F23Addr add ebx,3 mov eax,dword ptr RestoreJmpArg mov [ebx+2],eax @@WasNotInstalled: ; Восстановить команды в VxD call Uninstall_Jmp_Into_UD6 popad ret Uninstall_Handlers endp ; ; подпрограмма - перехватчик #6 - UD ; TrapPort proc ; Команды, которые не успел выполнить обработчик #6 ;29C8: 1E push ds << jmp Our_Trap_Program ;29C9: 06 push es ;29CA: 50 push eax ;29CB: 51 push ecx ;29CC: 52 push edx EntryEAX equ dword ptr [ebp-04h] EntryEBX equ dword ptr [ebp-10h] EntryECX equ dword ptr [ebp-08h] EntryEDX equ dword ptr [ebp-0Ch] EntryEDI equ dword ptr [ebp-20h] CrashAdr equ dword ptr [ebp+18h] ; EIP ; [ebp+18h] push ds ; [ebp+14h] push es ; [ebp+10h] push eax ; [ebp+0Ch] push ecx ; [ebp+8h] push edx ; [ebp+4h] push ebp ; [ebp+0h] mov ebp,esp pushad ; push eax ; [ebp-04h] ; push ecx ; [ebp-08h] ; push edx ; [ebp-0Ch] ; push ebx ; [ebp-10h] ; push esp ; [ebp-14h] ; push ebp ; [ebp-18h] ; push esi ; [ebp-1Ch] ; push edi ; [ebp-20h] push ds push ss pop ds ; Адрес возврата EIP mov ecx,CrashAdr ; Запомнить байты инструкции (опционально) call Store_LogRecord cmp EntryEAX,40000007h jnz @@NotF7 ; Эмуляция первого и не только вызова функции 07 ; В первом приближении это подсчет crc из [edx] длиной ecx и запись в [edi] pushad xor eax,eax mov edi,EntryEDX mov ecx,EntryECX @@CalcCRC: add al,ds:[edi] inc edi dec ecx jnz @@CalcCRC mov edi,EntryEDI mov ds:[edi],al popad ; Возврат в код приложения jmp @@ReturnToFault @@NotF7: cmp EntryEAX,40000006h jnz @@NotF6 ; Эмуляция первого и не только вызова функции 06 ; В первом приближении это расшифровка из [edx] длиной ecx xor AAh + ror 4 pushad xor eax,eax mov edi,EntryEDX mov ecx,EntryECX @@DecryptF06: xor byte ptr ds:[ecx+edi-1],0AAh ror byte ptr ds:[ecx+edi-1],4 dec ecx jnz @@DecryptF06 popad ; Возврат в код приложения, но на адрес из edi ; Модификация указателя mov eax,EntryEDI mov CrashAdr,eax jmp @@SimpleReturnToFault @@NotF6: cmp EntryEAX,40000003h jnz @@NotF3 ; Эмуляция первого и не только вызова функции 03 ; В первом приближении это расшифровка из [edx] длиной ecx rol 4 + xor AAh pushad xor eax,eax mov edi,EntryEDX mov ecx,EntryECX @@DecryptF03: rol byte ptr ds:[edi],4 xor byte ptr ds:[edi],0AAh inc edi dec ecx jnz @@DecryptF03 popad ; Возврат в код приложения jmp @@ReturnToFault @@NotF3: cmp EntryEAX,40000001h jnz @@NotF1 ; Эмуляция первого и не только вызова функции 01 ; В первом приближении это просто возврат + 8 ; Во втором - чтение из dr7 700h, запись в dr7 0, но это не обязательно ; Возврат в код приложения jmp @@ReturnToFault @@NotF1: cmp EntryEAX,40000004h jnz @@NotF4 ; Эмуляция первого и не только вызова функции 04 ; В первом приближении это расшифровка из [edx] длиной ecx rol 4 + xor AAh pushad xor eax,eax mov edi,EntryEDX mov ecx,EntryECX @@DecryptF04: rol byte ptr ds:[edi],4 xor byte ptr ds:[edi],0AAh inc edi dec ecx jnz @@DecryptF04 popad ; Возврат в код приложения, но на адрес из edi ; Модификация указателя mov eax,EntryEDI mov CrashAdr,eax jmp @@SimpleReturnToFault @@NotF4: cmp EntryEAX,40000002h jnz @@NotF2 ; Эмуляция первого и не только вызова функции 01 ; В первом приближении это просто возврат + 8 ; Во втором - запись в dr7 700h, но это не обязательно ; Возврат в код приложения jmp @@ReturnToFault @@NotF2: cmp EntryEAX,4000000Bh jnz @@NotFB jmp @@ToPrevHandler @@NotFB: @@ToPrevHandler: pop ds popad pop ebp jmp dword ptr ss:old_ud06handler ; ; Возврат в код, вызвавший исключение ; @@ReturnToFault: ; Инкримент указателя EIP add CrashAdr,8 @@SimpleReturnToFault: pop ds popad pop ebp ; Команды от оригинального обработчика pop edx pop ecx pop eax pop es pop ds ; Флаг RF: resume flag после выполнения исключения - continue or byte ptr ss:[esp+0Ah],1h iretd TrapPort endp ; ; Запомнить байты в лог-буфере ; ecx-> EIP start Store_LogRecord proc ; Счетчик вызовов int 6 mov eax,dword ptr ds:HookUDCount inc dword ptr ds:HookUDCount ;; cmp dword ptr ds:HookUDCount,50 ;; jbe @@ContinueHookUD ; (Номер шага+1) кратен 127 ? ;; pushad ;; add eax,2 ;; xor edx,edx ;; mov ebx,127 ;; div ebx ;; mov dword ptr ds:StepNum,eax ;; test edx,edx ;; popad ;; jz @@UnhookUD6AndWaiting ;; jmp @@StepsDone @@UnhookUD6AndWaiting: ;; cmp dword ptr ds:StepNum,2 ;; jae @@HookToCrcProcDone ; Устанавливаем ловушку на #14, ожидающую кода-расшифровщика на стек ; после того, как он найдет код декриптора на стек, ; он запишет после него вызов (наш) #6 ;; call Uninstall_Handlers @@ContinueHookUD: ;;call Install_Jmp_Into_14 @@HookToCrcProcDone: @@StepsDone: ; Записываем в лог только пакеты от функции 0Bh (отладка, можно убрать) ;; cmp EntryEAX,4000000Bh ;; jz @@LogFuncB ;; ret @@LogFuncB: ; Запоминаем байты и значения регистров команды mov eax,dword ptr ds:LogPtr cmp eax,MAX_LOG_RECORDS jae LogFull inc dword ptr ds:LogPtr pushad imul eax,eax,LogPacketSize mov ebx,offset32 LogPackets add ebx,eax assume ebx: ptr tLogPacket ; Тип пакета mov byte ptr [ebx].PacketType,PacketUD ; Регистр eax mov eax,EntryEAX mov dword ptr [ebx].RegEAX,eax ; Регистр edi mov eax,EntryEDI mov dword ptr [ebx].RegEDI,eax assume ebx:nothing popad ret LogFull: call Uninstall_Handlers ret Store_LogRecord endp ; ; Перехват вызова F 23h VxD ; HookControl proc push ebp mov ebp,esp push eax ; [ebp-4] push ebx ; [ebp-8] push ecx ; [ebp-0C] push edx ; [ebp-10] push esi ; [ebp-14] push edi ; [ebp-18] pushad push ds push es push ds pop es assume esi:ptr DIOCParams ; Фильтруем те запросы, которые можно не выполнять, а сразу - ret cmp dword ptr [esi].dwIoControlCode,DIOC_Open jz @@NotHaspEx cmp dword ptr [esi].dwIoControlCode,DIOC_Closehandle jz @@NotHaspEx ; Ответы изменяются только в сообщениях с подфункцией 2 cmp dword ptr [esi].dwIoControlCode,2 jnz @@NotHaspEx jmp @@ContinueLog @@NotHaspEx: ; После первого закрытия устройства устанавливаем перехват UD cmp dword ptr [esi].dwIoControlCode,DIOC_Closehandle ; DIOC_Open jnz @@NotDeviceClose cmp dword ptr old_ud06handler,0 jnz @@HandlerUDAlreadyInstalled ;; call Install_Jmp_Into_UD6 @@NotDeviceClose: @@HandlerUDAlreadyInstalled: assume esi:nothing pop es pop ds popad pop edi pop esi pop edx pop ecx pop ebx pop eax pop ebp ;; jmp dword ptr F23EntryPoint ; Выполняем возврат без перехода в драйвер xor eax,eax clc ret @@ContinueLog: ; Возможно, эмулируем работу драйвера - функции F23 assume esi:ptr DIOCParams mov dword ptr NeedForExecuteF23,0 ; Расшифровка тела запроса по способу UD pushad ; eax=lpvOutBuffer mov eax,[esi].lpvOutBuffer ; Расшифровать буфер по способу F=06 #6 mov ecx,28h lea ebx,[eax+14h] @@DecryptOutBuffer: xor byte ptr [ebx],0AAh ror byte ptr ds:[ebx],4 inc ebx loop @@DecryptOutBuffer ; Запомнить байты пакета (расшифрованные) call Store_LogF23Record ; Анализируем код подфункции функции 2 F23 assume eax:ptr tF23Packet ;; jmp @@SkipF23Self cmp word ptr [eax].FuncNum,01h jnz @@NotFunc01 ; Имитация подфункции 01 mov dword ptr NeedForExecuteF23,1 mov dword ptr [eax].Var1,1 mov word ptr [eax].Var2,1 mov word ptr [eax].Var3,0 mov dword ptr [eax].Var4,0 @@NotFunc01: cmp word ptr [eax].FuncNum,03h jnz @@NotFunc03 ; Имитация подфункции 03 mov dword ptr NeedForExecuteF23,1 pushad movzx ecx,word ptr [eax].Var1 mov cx,word ptr f32Table[ecx*2] mov word ptr [eax].Var2,cx popad mov word ptr [eax].Var3,0 mov dword ptr [eax].Var4,0 @@NotFunc03: cmp word ptr [eax].FuncNum,05h jnz @@NotFunc05 ; Имитация подфункции 05 mov dword ptr NeedForExecuteF23,1 mov dword ptr [eax].Var1,1 mov word ptr [eax].Var2,1 mov word ptr [eax].Var3,0 mov dword ptr [eax].Var4,0C9h mov dword ptr [eax].Var5,01F4Ah @@NotFunc05: cmp word ptr [eax].FuncNum,06h jnz @@NotFunc06 ; Имитация подфункции 06 mov dword ptr NeedForExecuteF23,1 mov dword ptr [eax].Var1,0DB3Fh mov word ptr [eax].Var2,07D95h mov word ptr [eax].Var3,0 mov dword ptr [eax].Var4,0 @@NotFunc06: cmp word ptr [eax].FuncNum,32h jnz @@NotFunc32 ; Имитация подфункции 32 movzx ebx,word ptr [eax].Var2 mov dword ptr [eax].Var7,ebx mov dword ptr [eax].Var4,0 ; Получить seed по таблице pushad pushfd mov ecx,dword ptr [eax].Var1 lea esi,dword ptr f32Table[ecx*2] movzx ecx,word ptr [eax].Var2 mov edi,dword ptr [eax].StackAddr cld rep movsw popfd popad mov dword ptr NeedForExecuteF23,1 @@NotFunc32: cmp word ptr [eax].FuncNum,3ch jnz @@NotFunc3c ; Имитация подфункции 3c mov dword ptr NeedForExecuteF23,1 mov dword ptr [eax].Var1,0 movzx ebx,word ptr [eax].Var2 mov dword ptr [eax].Var7,ebx @@NotFunc3c: cmp word ptr [eax].FuncNum,3dh jnz @@NotFunc3d ; Имитация подфункции 3d mov dword ptr [eax].Var1,0 movzx ebx,word ptr [eax].Var2 mov dword ptr [eax].Var7,ebx pushad ; Сканируем аргументы f3d mov byte ptr [ebx].Func3dNotEmul,0 ; Успешно эмулирована функция f3d mov edi,dword ptr [eax].StackAddr mov esi,offset Func3dArgsAnswers mov ecx,Func3dArgsAnswersSize cld @@FindArgF3d: pushad mov ecx,Func3dArgSize repe cmpsb popad jz @@ArgF3dFound add esi,Func3dArgSize+Func3dAnsSize loop @@FindArgF3d jmp @@ArgF3dNotFound @@ArgF3dFound: ;; jmp @@ArgF3dNotFound ; Аргумент найден, подставляем расшифровку требуемой длины mov dword ptr NeedForExecuteF23,1 mov byte ptr [ebx].Func3dNotEmul,1 ; Успешно эмулирована функция f3d movzx ecx,word ptr [eax].Var2 add esi,Func3dArgSize rep movsb @@ArgF3dNotFound: popad @@NotFunc3d: @@SkipF23Self: assume eax:nothing ; Зашифровать буфер по способу F=04 #6 mov ecx,28h lea ebx,[eax+14h] @@EncryptOutBuffer: rol byte ptr ds:[ebx],4 xor byte ptr ds:[ebx],0AAh inc ebx loop @@EncryptOutBuffer popad assume esi:nothing pop es pop ds popad pop edi pop esi pop edx pop ecx pop ebx pop eax pop ebp ; Вызов функции обработки (опционально) cmp dword ptr NeedForExecuteF23,0 jnz @@SkipExecOrigF23 call dword ptr F23EntryPoint @@SkipExecOrigF23: pushad pushfd ; Возможно, эмулируем работу драйвера - функции F23 (после выполнения) assume esi:ptr DIOCParams ; Расшифровка тела запроса по способу UD pushad ; eax=lpvOutBuffer mov eax,[esi].lpvOutBuffer ; Расшифровать буфер по способу F=06 #6 mov ecx,28h lea ebx,[eax+14h] @@DecryptOutBufferAfter: xor byte ptr [ebx],0AAh ror byte ptr ds:[ebx],4 inc ebx loop @@DecryptOutBufferAfter ; Запомнить байты расшифрованного пакета (после) call Store_LogF23RecordAfter ; Анализируем код подфункции функции F23 ; assume eax:ptr tF23Packet ; ; cmp word ptr [eax].FuncNum,32h ; jnz @@NotFunc32After ; ; cmp dword ptr [eax].Var1,0 ; jz @@NotFunc32After ; cmp word ptr [eax].Var2,1 ; jz @@NotFunc32After ; movzx ebx,word ptr [eax].Var2 ; mov dword ptr [eax].Var7,ebx ; mov dword ptr [eax].Var4,0 ; Получить seed по таблице ; mov ecx,dword ptr [eax].Var1 ; mov ecx,dword ptr f32Table[ecx*2] ; mov ebx,dword ptr [eax].StackAddr ; mov dword ptr [ebx],ecx ; ;@@NotFunc32After: assume eax:nothing ; Зашифровать буфер по способу F=04 #6 mov ecx,28h lea esi,[eax+14h] @@EncryptOutBufferAfter: rol byte ptr ds:[esi],4 xor byte ptr ds:[esi],0AAh inc esi loop @@EncryptOutBufferAfter popad assume esi:nothing popfd popad @@F23FuncDone: xor eax,eax clc ret HookControl endp ; ; Запомнить байты по перехвату F23 в лог-буфере ; Store_LogF23Record proc pushad ; Запоминаем байты и значения регистров команды mov eax,dword ptr ds:LogPtr cmp eax,MAX_LOG_RECORDS jae LogF23Full inc dword ptr ds:LogPtr ; Активация/дезактивация GetXXXTime ; cmp eax,0 ; jnz @@SkipActivateTime ; push eax ; mov eax,ds:InitializedTimeFlag ; mov dword ptr ds:[eax],1 ; pop eax ;@@SkipActivateTime: ; cmp eax,0FEh ; jnz @@SkipDeactivateTime ; push eax ; mov eax,ds:InitializedTimeFlag ; mov dword ptr ds:[eax],0 ; pop eax ;@@SkipDeactivateTime: imul eax,eax,LogPacketSize mov ebx,offset32 LogPackets add ebx,eax ; Сохранить указатель на последний пакет mov LastPacketPtr,ebx assume ebx: ptr tLogF23Packet ; Тип пакета mov byte ptr [ebx].PacketType,PacketF23 ; Регистр eax mov eax,dword ptr [ebp-4] mov dword ptr [ebx].RegEAX,eax assume esi:ptr DIOCParams ; Код подфункции функции F23 mov eax,[esi].lpvOutBuffer assume eax:ptr tF23Packet mov cx,word ptr [eax].FuncNum mov word ptr [ebx].FuncNum,cx assume eax:nothing ; dwIoControlCode mov eax,[esi].dwIoControlCode mov dword ptr [ebx].dwIoControlCode,eax ; lpvInBuffer mov eax,[esi].lpvInBuffer mov dword ptr [ebx].lpvInBuffer,eax ; Размер переданных данных cbInBuffer mov eax,[esi].cbInBuffer mov dword ptr [ebx].cbInBuffer,eax ; Указатель на данные для ответа VxD mov eax,[esi].lpvOutBuffer mov dword ptr [ebx].lpvOutBuffer,eax ; Аргумент ответа функции F32 mov dword ptr [ebx].F32Arg,0 cmp word ptr [ebx].FuncNum,32h jnz @@SkipSeedF32Before assume eax:ptr tF23Packet mov eax,dword ptr [ebx].lpvOutBuffer ; Получить аргумент для seed f32 mov eax,dword ptr [eax].Var1 assume eax:nothing mov dword ptr [ebx].F32Arg,eax @@SkipSeedF32Before: ; Аргумент ответа функции F3d cmp word ptr [ebx].FuncNum,3dh jnz @@SkipArgF3d assume eax:ptr tF23Packet mov eax,dword ptr [ebx].lpvOutBuffer mov eax,dword ptr [eax].StackAddr assume eax:nothing pushad mov ecx,dword ptr [eax] mov dword ptr [ebx].Func3dArg,ecx mov ecx,dword ptr [eax+4] mov dword ptr [ebx+4].Func3dArg,ecx popad @@SkipArgF3d: ; Размер данных для ответа (max) mov eax,[esi].cbOutBuffer mov dword ptr [ebx].cbOutBuffer,eax ; Сколько байтов вернули mov eax,[esi].lpcbBytesReturned mov dword ptr [ebx].lpcbBytesReturned,eax ; Попытаться запомнить выходной буфер ДО mov byte ptr [ebx].OutBuffChanged,0 ; Изменен буфер обмена ; Сначала заполнить его нулями lea edi,[ebx].OutBuffer mov ecx,OutBufferSize xor eax,eax rep stosb mov esi,dword ptr [ebx].lpvOutBuffer test esi,esi jz @@OutBuffBeforeIsNull ; Потом скопировать mov ecx,OutBufferSize lea edi,[ebx].OutBufferBefore rep movsb @@OutBuffBeforeIsNull: assume esi:nothing assume ebx:nothing LogF23Full: popad ret Store_LogF23Record endp ; ; Запомнить F23 байты в лог-буфере после выполнения ; Store_LogF23RecordAfter proc pushad mov eax,dword ptr ds:LogPtr cmp eax,MAX_LOG_RECORDS jae LogF23AfterFull mov ebx,LastPacketPtr assume ebx: ptr tLogF23Packet cld ; Попытаться запомнить выходной буфер ; Сначала заполнить его нулями lea edi,[ebx].OutBuffer mov ecx,OutBufferSize xor eax,eax rep stosb mov esi,dword ptr [ebx].lpvOutBuffer test esi,esi jz @@OutBuffIsNull ; Потом скопировать mov ecx,OutBufferSize lea edi,[ebx].OutBuffer rep movsb ; Проверка изменения буфера mov ecx,OutBufferSize lea esi,[ebx].OutBufferBefore lea edi,[ebx].OutBuffer repe cmpsb jz @@BuffsEqual inc byte ptr [ebx].OutBuffChanged ; Изменен буфер обмена ! @@BuffsEqual: ; Ответ функции F32 mov dword ptr [ebx].F32Seed,0 cmp word ptr [ebx].FuncNum,32h jnz @@SkipSeedF32 assume eax:ptr tF23Packet mov eax,dword ptr [ebx].lpvOutBuffer ; Получить указатель на память, содержащую ответный seed f32 mov eax,dword ptr [eax].StackAddr assume eax:nothing ; Получит значение seed mov eax,[eax] mov dword ptr [ebx].F32Seed,eax @@SkipSeedF32: ; Ответ функции F3d cmp word ptr [ebx].FuncNum,3dh jnz @@SkipAnsF3d assume eax:ptr tF23Packet mov eax,dword ptr [ebx].lpvOutBuffer ; Получить указатель на память, содержащую расшифровку f3d и длину pushad mov esi,dword ptr [eax].StackAddr movzx ecx,word ptr [eax].Var2 assume eax:nothing lea edi,[ebx].Func3dAns pushad mov ecx,Func3dAnsSize xor eax,eax rep stosb popad rep movsb popad @@SkipAnsF3d: @@OutBuffIsNull: assume ebx:nothing LogF23AfterFull: popad ret Store_LogF23RecordAfter endp ; ; Вписать jmp на наш обработчик #6 ; Install_Jmp_Into_UD6 proc pushad cli ; eax=команда короткого jmp на тело mov eax,dword ptr ds:UD6EntryPoint ; вычислить начало обработчика movzx ebx,byte ptr ds:[eax+1] lea eax,[ebx+eax+2] ; Вписать jmp mov byte ptr ds:[eax],0E9h ; jmp mov ebx,offset32 TrapPort sub ebx,eax sub ebx,5 mov dword ptr ds:[eax+1],ebx ; offset add eax,5 mov dword ptr old_ud06handler,eax sti popad ret Install_Jmp_Into_UD6 endp ; ; Убрать jmp на наш обработчик #6 ; Uninstall_Jmp_Into_UD6 proc pushad cli mov eax,dword ptr old_ud06handler test eax,eax jz @@HandlerUDWasNotFound sub eax,5 ;29C8: 1E push ds << jmp Our_Trap_Program ;29C9: 06 push es ;29CA: 50 push eax ;29CB: 51 push ecx ;29CC: 52 push edx mov byte ptr ds:[eax],01Eh mov dword ptr ds:[eax+1],52515006h @@HandlerUDWasNotFound: sti popad ret Uninstall_Jmp_Into_UD6 endp Install_Jmp_Into_14 proc ; ; Вписать команду перехода на перехватчик #14 ; ;9A02: EB14 jmps .000009A18 ;9A04: db 'GenuineDevil' = db 47,65,6E,75,69,6E,65,44,65,76,69,6C ;9A10: 0E,00,01,02,D8,00,00,00, ;9A18: 1E push ds << jmp Hook_14 ;9A19: 06 push es ;9A1A: 16 push ss ;9A1B: 1F pop ds ;9A1C: 50 push eax ;9A1D: 51 push ecx ;9A1E: 52 push edx ;9A1F: 57 push edi ; Второй вариант VxD, начало #14 ;2822: EB18 jmps .00000283C ;2824: db 47,65,6E,75,69,6E,65,44,65,76,69,6C ;2830: db 0E,00,02,28,33,00,B4,00,00,00,40,01,00,00 ;283C: 1E push ds ;283D: 06 push es ;283E: 16 push ss ;283F: 1F pop ds ;2840: 50 push eax ;2841: 51 push ecx ;2842: 52 push edx ;2843: 57 push edi pushad mov eax,dword ptr ds:UD14EntryPoint ; вычислить начало обработчика movzx ebx,byte ptr ds:[eax+1] lea eax,[ebx+eax+2] mov byte ptr ds:[eax],0E9h ; jmp mov ebx,offset32 Hook_14 sub ebx,eax sub ebx,5 mov dword ptr ds:[eax+1],ebx ; offset add eax,5 ; Запомнить точку возврата mov dword ptr ds:old_14handler,eax ; Счетчик вызовов #14 mov dword ptr ds:Hook14Count,0 popad ret Install_Jmp_Into_14 endp ; ; Убрать jmp на наш обработчик #14 ; Uninstall_Jmp_Into_14 proc pushad mov eax,dword ptr ds:old_14handler test eax,eax jz @@HandlerPageFaultWasNotFound sub eax,5h ;283C: 1E push ds ;283D: 06 push es ;283E: 16 push ss ;283F: 1F pop ds ;2840: 50 push eax mov byte ptr ds:[eax],1Eh mov dword ptr ds:[eax+1],501F1606h @@HandlerPageFaultWasNotFound: popad ret Uninstall_Jmp_Into_14 endp ; ; Перехватчик исключения #14 ; Hook_14 proc EntryEIP_14 equ dword ptr [ebp+14h] ; Повторяем команды оригинального обработчика #14 ; EIP [ebp+14h] ; ErrCode [ebp+10h] push ds ; [ebp+0Ch] << jmp Hook_14 push es ; [ebp+8h] push ss pop ds push eax ; [ebp+4h] push ebp ; [ebp+0h] mov ebp,esp pushad popad pop ebp ; Возврат в VxD jmp dword ptr ss:old_14handler Hook_14 endp ; ; Получение DDB адрес ; GetLitt_DDB proc pushad ; Определение DDB VxD mov eax,DeviceLitt_ID xor edi,edi VMMCall Get_DDB ; ecx= адрес DDB ? mov dword ptr ds:DDB,ecx popad ret GetLitt_DDB endp VxD_LOCKED_CODE_ENDS end ; ; *************** Приложение ******************** ; ; Объявляем доступными команды процессора 386, непривелигерованные инструкции. .386 ; Модель памяти - flat, способ вызова апи - stdcall .model flat,stdcall ; Case-sensetive в именах option casemap:none ; Инклюды, содержащие описание вин-апи include \masm32\include\windows.inc ; Макрос invoke...etc include \masm32\include\kernel32.inc ; DeviceIOControl, CreateFile... etc includelib \masm32\lib\kernel32.lib ; Сама библиотека include \masm32\include\user32.inc ; MessageBox includelib \masm32\lib\user32.lib ; Сама библиотека ; Сегмент данных программы(инициализированных) .data ; Отладочные сообщения, выводимые через MessageBox MsgCaption db "Iczelion's tutorial no.2",0 ; Сообщения о процессе загрузки/выгрузки VxD AppName db "Hasp key test program for win9x",0 Success db "The reseacher is successfully loaded!",0 SerNumErr db "VxD not present or internal error...",0 Failure db "The VxD is not loaded !",0 ; Имя загружаемого VxD, которое передается CreateFile-у VxDName db "\\.\UD1C.VXD",0 ; Структура, которой передаются параметры коду VxD InBuffer dd offset LogPtr ; Указатель на буфер для чтения лога include 1C06.inc ; Буфер лога LogPtr dd 0 ; Указатель лог-буфера LogPackets db (MAX_LOG_RECORDS * LogPacketSize) dup (?) ; Сегмент данных программы(неинициализированных) .data? hVxD dd ? ; Тут будет храниться хэндл открытого VxD ; Начало выполнимого кода .code start: ; *** ; Открываем лог ; *** .data LogFileName db "UD1C_06.log",0 .data? LogDescr dd ? bWrite dd ? .data VxDHASPName db "\\.\HASP95DL.VXD",0 PacketF32 db 001h,000h,000h,000h,001h,000h,000h,000h db 068h,073h,068h,06ch,048h,000h,000h,000h db 028h,000h,000h,000h,04ch,01dh,032h,000h db 020h,0fch,000h,000h,0c9h,000h,000h,000h db 06dh,03bh,0afh,0cdh,0cbh,070h,081h,081h Argum db 004h,000h,000h,000h,00ah,000h,042h,027h db 000h,000h,000h,000h,04ah,01fh,000h,000h db 000h,000h,000h,000h,000h,000h,000h,000h SeedAddr db 020h,0fch,069h,000h,000h,000h,004h,000h .data? Seed dd ? hVxDHASP dd ? PacketF32Tmp db 48h dup(?) .code ; Открыть лог, если есть он уже invoke CreateFile,offset LogFileName,GENERIC_WRITE,FILE_SHARE_WRITE+FILE_SHARE_READ,\ 0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 mov LogDescr,eax ; Save file descriptor inc eax jnz @@LogFileOpen ; Видимо, нет. Тогда попробовать создать invoke CreateFile,offset LogFileName,GENERIC_WRITE,FILE_SHARE_WRITE+FILE_SHARE_READ,\ 0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0 mov LogDescr,eax ; Save file descriptor inc eax jnz @@LogFileOpen .data OpenErrorMsg db "Log file not created !",0Ah,0 .code push offset OpenErrorMsg call Write_Log jmp Exit @@LogFileOpen: ; Встать в конец лога invoke SetFilePointer,LogDescr,0,NULL,FILE_END ; Эмуляция функции f32 .data ;;TestBytes db 0B8h,052h,003h,027h,080h,030h,0D4h,000h TestBytes db 0DBh,0FEh,01Eh,06Bh,0E4h,01Bh,0DBh,0B0h ;;TestBytes db 05Eh,022h,0E1h,05Eh,04Eh,0C8h,003h,02Fh TestBytesStr db 'Bytes1=????????????????????????????????',0Dh,0Ah,0 .data? Count dd ? .code mov dword ptr Count,0 mov esi,offset TestBytes ;; mov eax,ds:[0] @@Decrypt1: mov edi,[esi] mov edx,edi xor edx,05B2C004Ah mov ecx,dword ptr Count mov eax,0FFFFFFF9h sub eax,ecx and eax,1Fh mov ecx,20h mov ebx,edx sub ecx,eax shr ebx,cl mov ecx,eax mov eax,[esi+4] shl edx,cl mov [esi+4],edi or ebx,edx xor ebx,eax mov [esi],ebx add dword ptr Count,5 cmp dword ptr Count,1Eh jb @@Decrypt1 mov ecx,8h mov esi,offset TestBytes mov edi,offset TestBytesStr+7 call Get_HexStr push offset TestBytesStr call Write_Log .data? Tmp dd ? .code mov esi,offset TestBytes mov eax,[esi] mov dword ptr [esi],0C9162F54h ; ? mov [esi+4],eax ;; mov eax,ds:[0] xor edi,edi @@Decrypt2: mov edx,[esi] mov eax,0Ah sub eax,edi mov Tmp,edx and eax,1Fh xor edx,803425C3h mov ecx,20h mov ebx,edx sub ecx,eax add edi,2 shr ebx,cl mov ecx,eax shl edx,cl mov ecx,Tmp or ebx,edx mov edx,[esi+4] xor ebx,edx cmp edi,0Ch mov [esi],ebx mov [esi+4],ecx jb @@Decrypt2 mov ecx,8h mov esi,offset TestBytes mov edi,offset TestBytesStr+7 call Get_HexStr push offset TestBytesStr call Write_Log ; Final mov esi,offset TestBytes mov eax,[esi] mov ebx,eax xor ebx,31F18DE2h mov [esi],ebx mov [esi+4],eax mov ecx,8h mov esi,offset TestBytes mov edi,offset TestBytesStr+7 call Get_HexStr push offset TestBytesStr call Write_Log ; Exit ;; invoke ExitProcess,NULL ; Загрузим динамический VxD через CreateFile invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0 cmp eax,INVALID_HANDLE_VALUE ; VxD Успешно загружена ? ; Сохранить хэндл VxD mov hVxD,eax jnz @@LoadedOK @@VxDProblem: invoke CloseHandle,hVxD invoke MessageBox,NULL,addr Failure,NULL,MB_OK+MB_ICONERROR jmp Exit @@LoadedOK: ; Выдать сообщение о том, что VxD загружена успешно, давая возможность ; прекратить работу VxD invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATION jmp @@SkipDebug ; Вызвать тестовым образом HASP95DL.VXD mov dword ptr SeedAddr,offset Seed mov dword ptr Argum,0 ; Открыть VXD invoke CreateFile,addr VxDHASPName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0 ; Сохранить хэндл VxD mov hVxDHASP,eax ; ;; invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATION @@NextArg: mov esi,offset PacketF32 mov edi,offset PacketF32Tmp mov ecx,48h cld rep movsb ; Зашифровать буфер по способу F=04 #6 mov ecx,28h lea esi,PacketF32Tmp[14h] @@EncryptOutBufferAfter: rol byte ptr ds:[esi],4 xor byte ptr ds:[esi],0AAh inc esi loop @@EncryptOutBufferAfter invoke DeviceIoControl,hVxDHASP,2,addr PacketF32Tmp,48h,addr PacketF32Tmp,48h,NULL,NULL inc dword ptr Argum cmp dword ptr Argum,60h jbe @@NextArg ; Закрыть VXD invoke CloseHandle,hVxDHASP @@SkipDebug: ; Получить протокол работы invoke DeviceIoControl,hVxD,1,addr InBuffer,sizeof InBuffer,NULL,NULL,NULL,NULL ; Проверка на ошибку. Если ошибка, то eax = 0 test eax,eax jz @@VxDProblem ; Ошибки нет. Скинем данные в лог. call Print_SerialInfo ; Закроем VxD invoke CloseHandle,hVxD Exit: ; Завершим программу invoke ExitProcess,NULL ; Подпрограммы .data SerialInfo db "Total traps: ?????????? See log file UD1C_01.log...",0Dh,0Ah,0 LogInfoEnd db 'EAX=???????? EDI=????????',0Dh,0Ah,0 StrNumber dd 0 LogInfoStart db 'Num=????:',0 LogInfoInBuf db 'BuffBef=',0 LogInfoOp db '0??h,',0 LogInfoOutBuf db 'OutBuff=',0 LogInfoEnd1 db 'dwIoControlCode=???????? lpvInBuffer=???????? cbInBuffer=????????',0Dh,0Ah,0 LogInfoEnd2 db 'lpvOutBuffer=???????? cbOutBuffer=???????? lpcbBytesReturned=????????',0Dh,0Ah,0 LogInfoFuncN db 'Func=????',0Dh,0Ah,0 LogInfoF32Seed db 'F32Seed[????????]=????????',0Dh,0Ah,0 Func3dArgAnsMsg db 'Func3d[????????????????]=????????????????????????????????',0Dh,0Ah,0 LogInfoBuffCh db 'Out buffer changed !',0Dh,0Ah,0 .data? LogSize dd ? .code Print_SerialInfo proc ; Сколько было записей в логе mov eax,dword ptr LogPtr mov ebx,1000000000 mov edi,offset SerialInfo+13 call DecChar invoke MessageBox,NULL,addr SerialInfo,addr MsgCaption,MB_OK push offset SerialInfo call Write_Log mov ecx,dword ptr LogPtr test ecx,ecx jnz @@IsLogData ret @@IsLogData: ; Размер лога mov eax,ecx imul eax,eax,LogPacketSize add eax,4 ; Size mov dword ptr LogSize,eax mov ebx,offset LogPackets @@OutLogData: pushad ; Номер строки ;; call Write_StrNum ; ; Обрабатываем пакеты различных типов ; ; Пакет перехвата UD6 assume ebx: ptr tLogPacket cmp byte ptr [ebx].PacketType,PacketUD jnz @@NoUDPacket jmp @@SkipLogPacket ; Номер строки call Write_StrNum ; Регистр eax и изображение mov eax,dword ptr [ebx].RegEAX mov edi,offset LogInfoEnd+4 call HexChar ; Регистр edi mov eax,dword ptr [ebx].RegEDI mov edi,offset LogInfoEnd+17 call HexChar push offset LogInfoEnd call Write_Log assume ebx:nothing @@NoUDPacket: assume ebx: ptr tLogF23Packet cmp byte ptr [ebx].PacketType,PacketF23 jnz @@NoF23Packet ; Проверка changed ? ;; cmp byte ptr [ebx].OutBuffChanged,0 ; Изменен буфер обмена ? ;; jz @@SkipLogPacket ; Номер функции: фильтр ;; cmp word ptr [ebx].FuncNum,32h ;; jnz @@SkipLogPacket ; Номер функции: фильтр ;; cmp word ptr [ebx].FuncNum,3h ;; jnz @@SkipLogPacket ; Номер функции: фильтр cmp word ptr [ebx].FuncNum,3dh jnz @@SkipLogPacket cmp byte ptr [ebx].Func3dNotEmul,1 ; Успешно эмулирована функция f3d ? jnz @@SkipLogPacket ; Номер строки call Write_StrNum ; dwIoControlCode mov eax,dword ptr [ebx].dwIoControlCode mov edi,offset LogInfoEnd1+16 call HexChar ; lpvInBuffer mov eax,dword ptr [ebx].lpvInBuffer mov edi,offset LogInfoEnd1+37 call HexChar ; Размер переданных данных cbInBuffer mov eax,dword ptr [ebx].cbInBuffer mov edi,offset LogInfoEnd1+57 call HexChar push offset LogInfoEnd1 call Write_Log ; lpvOutBuffer mov eax,dword ptr [ebx].lpvOutBuffer mov edi,offset LogInfoEnd2+13 call HexChar ; cbOutBuffer mov eax,dword ptr [ebx].cbOutBuffer mov edi,offset LogInfoEnd2+34 call HexChar ; lpcbBytesReturned mov eax,dword ptr [ebx].lpcbBytesReturned mov edi,offset LogInfoEnd2+61 call HexChar push offset LogInfoEnd2 call Write_Log ; Признак изменения буфера cmp byte ptr [ebx].OutBuffChanged,0 ; Изменен буфер обмена ? jz @@NotChanged ;; push offset LogInfoBuffCh ;; call Write_Log @@NotChanged: ; Номер функции mov ax,word ptr [ebx].FuncNum mov edi,offset LogInfoFuncN+5 call HexWORD push offset LogInfoFuncN call Write_Log ; Байты входного буфера push offset LogInfoInBuf call Write_Log mov ecx,OutBufferSize lea esi,[ebx].OutBufferBefore ; Расшифровать буфер по способу F=06 #6 ;; call Decrypt_Buffer @@OutBufferBefore: pushad mov ecx,1h mov edi,offset LogInfoOp+1 call Get_HexStr push offset LogInfoOp call Write_Log popad inc esi loop @@OutBufferBefore call Write_EndStr_ToLog ; Байты выходного буфера push offset LogInfoOutBuf call Write_Log mov ecx,OutBufferSize lea esi,[ebx].OutBuffer ; Расшифровать буфер по способу F=06 #6 ;; call Decrypt_Buffer @@OutOutBuffer: pushad mov ecx,1h mov edi,offset LogInfoOp+1 call Get_HexStr push offset LogInfoOp call Write_Log popad inc esi loop @@OutOutBuffer call Write_EndStr_ToLog ; Ответ F32 - F32Seed ; Номер функции: фильтр cmp word ptr [ebx].FuncNum,32h jnz @@SkipF32SeedOut ; Var1 mov eax,dword ptr [ebx].F32Arg mov edi,offset LogInfoF32Seed+8 call HexChar ;Seed mov eax,dword ptr [ebx].F32Seed mov edi,offset LogInfoF32Seed+18 call HexChar ;; mov eax,dword ptr [ebx].F32SeedBefore ;; mov edi,offset LogInfoF32Seed+31 ;; call HexChar push offset LogInfoF32Seed call Write_Log @@SkipF32SeedOut: ; Ответ F3d ; Номер функции: фильтр cmp word ptr [ebx].FuncNum,3dh jnz @@SkipF3dData pushad mov ecx,Func3dArgSize lea esi,[ebx].Func3dArg mov edi,offset Func3dArgAnsMsg+7 call Get_HexStr mov ecx,Func3dAnsSize lea esi,[ebx].Func3dAns mov edi,offset Func3dArgAnsMsg+25 call Get_HexStr push offset Func3dArgAnsMsg call Write_Log popad @@SkipF3dData: call Write_EndStr_ToLog assume ebx:nothing @@NoF23Packet: @@SkipLogPacket: popad add ebx,LogPacketSize dec ecx jnz @@OutLogData ret Print_SerialInfo endp ; ; Расшифровать буфер по способу F=06 #6 ; esi=offset, ecx=len of buffer (but only 28h bytes) ; Decrypt_Buffer proc pushad add esi,14h mov ecx,28h @@DecryptBuffer: xor byte ptr [esi],0AAh ror byte ptr ds:[esi],4 inc esi loop @@DecryptBuffer popad ret Decrypt_Buffer endp ; ; ; Write_StrNum proc ; Номер строки pushad mov eax,StrNumber inc StrNumber mov ebx,1000 mov edi,offset LogInfoStart+4 call DecChar push offset LogInfoStart call Write_Log popad ret Write_StrNum endp ; ************* DecChar: Подпрограмма форматирования строки из числа *********** ; eax=number to digit, edi=offset result string in format 00000000(@n[ebx]) ; ebx=начальный делитель DecChar proc pushad pushfd cld @GetDec: xor edx,edx div ebx add al,'0' stosb push edx mov eax,ebx xor edx,edx mov ebx,10 div ebx mov ebx,eax pop eax test ebx,ebx jnz @GetDec popfd popad ret DecChar endp ; *** ; Подпрограмма записи в лог и на консоль одновременно ; *** ; [ebp+8] - адрес строки для записи Write_Log proc push ebp mov ebp,esp ; Получить длину строки mov esi,dword ptr [ebp+8] ; Адрес строки call Str_Len test ecx,ecx jz @@ExitWrite_Log ; Запись в протокол push NULL push offset bWrite push ecx ; Длина строки push dword ptr [ebp+8] ; Адрес строки push LogDescr call WriteFile @@ExitWrite_Log: pop ebp ret 4 Write_Log endp Write_EndStr_ToLog proc .data EndStr db 0Ah,0 .code push offset EndStr call Write_Log ret Write_EndStr_ToLog endp ; *** ; Get lenght of string ; esi=addr of string; result: ecx=length ; *** Str_Len proc xor ecx,ecx push eax push esi @@GetStrLen: lodsb test al,al jz @@ExitStrLen inc ecx jmp @@GetStrLen @@ExitStrLen: pop esi pop eax ret Str_Len endp ; Форматировать число в EAX в строку HexChar proc pushad cld mov ecx,8 mov ebx,offset TabHex @GetHex: rol eax,4 push eax and al,0fh xlat stosb pop eax loop @GetHex popad ret HexChar endp TabHex db '0123456789abcdef' ; Формирует хекс-строку ; ecx - длина строки байт, esi - адрес строки, edi - приемник Get_HexStr proc pushad mov ebx,offset TabHex @@Get_HexStr: lodsb rol al,4 push eax and al,0Fh xlat stosb pop eax shr al,4 xlat stosb loop @@Get_HexStr popad ret Get_HexStr endp ; Форматировать число в AX в строку HexWORD proc pushad cld mov ecx,4 mov ebx,offset TabHex @GetWORD: rol ax,4 push eax and al,0fh xlat stosb pop eax loop @GetWORD popad ret HexWORD endp end start

2002-2013 (c) wasm.ru