Реализация мини VM
Далее хотел бы предложить идею реализации мини ВМ, для защиты кода в программе.
Под мини ВМ подразумевается ВМ, с поддержкой ограниченного числа регистров и инструкций, по принципу чтения и исполнения байт кода/псевдокода.
Реализовано на примере алгоритма TEA.
Для начала посмотрим на дизассемблерный листинг алгоритма TEA. функция TEAEncrypt:
00401000 /. 55 PUSH EBP 00401001 |. 8BEC MOV EBP,ESP 00401003 |. 57 PUSH EDI 00401004 |. 56 PUSH ESI 00401005 |. 53 PUSH EBX 00401006 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] 00401009 |. 8B06 MOV EAX,DWORD PTR DS:[ESI] 0040100B |. 8B56 04 MOV EDX,DWORD PTR DS:[ESI+4] 0040100E |. 33DB XOR EBX,EBX 00401010 |. 0FC8 BSWAP EAX 00401012 |. 0FCA BSWAP EDX 00401014 |. 81C3 B979379E ADD EBX,9E3779B9 ------------------------------------------- 0040101A |. 8BCA |MOV ECX,EDX 0040101C |. C1E1 04 |SHL ECX,4 0040101F |. 8BFA |MOV EDI,EDX 00401021 |. 8D3413 |LEA ESI,DWORD PTR DS:[EBX+EDX] 00401024 |. 030D 20304000 |ADD ECX,DWORD PTR DS:[403020] 0040102A |. C1EF 05 |SHR EDI,5 0040102D |. 33CE |XOR ECX,ESI 0040102F |. 033D 24304000 |ADD EDI,DWORD PTR DS:[403024] 00401035 |. 33CF |XOR ECX,EDI 00401037 |. 03C1 |ADD EAX,ECX ------------------------------------------- 00401039 |. 8BC8 |MOV ECX,EAX 0040103B |. C1E1 04 |SHL ECX,4 0040103E |. 8BF8 |MOV EDI,EAX 00401040 |. 8D3403 |LEA ESI,DWORD PTR DS:[EBX+EAX] 00401043 |. 030D 28304000 |ADD ECX,DWORD PTR DS:[403028] 00401049 |. C1EF 05 |SHR EDI,5 0040104C |. 33CE |XOR ECX,ESI 0040104E |. 033D 2C304000 |ADD EDI,DWORD PTR DS:[40302C] 00401054 |. 33CF |XOR ECX,EDI 00401056 |. 03D1 |ADD EDX,ECX ------------------------------------------- 00401058 |. 81C3 B979379E |ADD EBX,9E3779B9 ------------------------------------------- 0040105E |. 8BCA |MOV ECX,EDX 00401060 |. C1E1 04 |SHL ECX,4 00401063 |. 8BFA |MOV EDI,EDX 00401065 |. 8D3413 |LEA ESI,DWORD PTR DS:[EBX+EDX] 00401068 |. 030D 20304000 |ADD ECX,DWORD PTR DS:[403020] 0040106E |. C1EF 05 |SHR EDI,5 00401071 |. 33CE |XOR ECX,ESI 00401073 |. 033D 24304000 |ADD EDI,DWORD PTR DS:[403024] 00401079 |. 33CF |XOR ECX,EDI 0040107B |. 03C1 |ADD EAX,ECX ------------------------------------------- 0040107D |. 8BC8 |MOV ECX,EAX 0040107F |. C1E1 04 |SHL ECX,4 00401082 |. 8BF8 |MOV EDI,EAX 00401084 |. 8D3403 |LEA ESI,DWORD PTR DS:[EBX+EAX] 00401087 |. 030D 28304000 |ADD ECX,DWORD PTR DS:[403028] 0040108D |. C1EF 05 |SHR EDI,5 00401090 |. 33CE |XOR ECX,ESI 00401092 |. 033D 2C304000 |ADD EDI,DWORD PTR DS:[40302C] 00401098 |. 33CF |XOR ECX,EDI 0040109A |. 03D1 |ADD EDX,ECX ------------------------------------------- 0040109C |. 81FB 2037EFC6 |CMP EBX,C6EF3720 ------------------------------------------- 004010A2 |.^0F85 6CFFFFFF \JNZ main.00401014 004010A8 |. 0FC8 BSWAP EAX 004010AA |. 0FCA BSWAP EDX 004010AC |. 8B75 0C MOV ESI,DWORD PTR SS:[EBP+C] 004010AF |. 8906 MOV DWORD PTR DS:[ESI],EAX 004010B1 |. 8956 04 MOV DWORD PTR DS:[ESI+4],EDX 004010B4 |. 5B POP EBX 004010B5 |. 5E POP ESI 004010B6 |. 5F POP EDI 004010B7 |. C9 LEAVE 004010B8 \. C2 0800 RETN 8 |
Первым делом надо выписать все инструкции что здесь используются, это:
PUSH,POP,MOV,XOR,BSWAP,ADD,SUB,SHL,SHR,LEA,JNZ,CMP,LEAVE,RETN |
Потом для упращения задачи, отсортировать инструкции и привести к общему виду:
PUSH REG32 POP REG32 MOV REG32, REG32 MOV REG32, DWORD PTR [REG32] MOV REG32, DWORD PTR [REG32 + imm8] MOV DWORD PTR [REG32], REG32 MOV DWORD PTR [REG32 + imm8], REG32 XOR REG32, REG32 BSWAP REG32 ADD REG32, REG32 ADD REG32, imm32 ADD REG32, DWORD PTR[imm32] SUB REG32, REG32 SUB REG32, imm32 SHL REG32, imm8 SHR REG32, imm8 LEA REG32, DWORD PTR [REG32 + REG32] CMP REG32, IMM32 JNZ imm32 LEAVE RETN imm16 |
Как и у любой другой ВМ, у нас должны быть регистры, их мы объявим в типе «MYCONTEXT».
Всего нам потребуется 10 регистров: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, EIP, EFLAGS (регистр флагов). Остальные трогать нет необходимости из-за «узконаправленной цели».
MYCONTEXT struct ; Registers r_EAX dd ? r_ECX dd ? r_EDX dd ? r_EBX dd ? r_ESP dd ? r_EBP dd ? r_ESI dd ? r_EDI dd ? r_EIP dd ? ; FLAGS Register flags dd ? MYCONTEXT ends |
Теперь переходим к составлению системы команд.
В Функциях TEAEncrypt и TEADecrypt всего используется 14 инструкций, следовательно на эти 14 инструкций мы можем затратить 4 бита под описание, а в остальных битах держать какую либо другую информацию. К примеру возьмём инструкцию «PUSH REG32», описать её можно таким видом:
1 БАЙТ 0 0 0 0 0 0 0 0 БИТ № 7 6 5 4 3 2 1 0 |
Биты под номерами 7-4 будут указывать ВМ на то, что это инструкция PUSH, а в битах 3-0 логично будет держать индекс регистра.
Далее приведу таблицу индексов регистров
EAX 0000b ECX 0001b EDX 0010b EBX 0011b ESP 0100b EBP 0101b ESI 0110b EDI 0111b |
Исходя из таблицы, можно смело утверждать, что мы использовали «PUSH EAX».
Для более конкретного примера возьмём инструкцию «SUB REG32, REG32»
2 БАЙТА 1010 0000 0000 0000 БИТ № 7654 3210 7654 3210 |
Как вы заметили инструкция SUB, занимает уже 2 байта, потому как в 4 бита первого байта описать 2 регистра будет не возможно. Они будут описаны во втором байте в битах под номерами 5-3 и 2-0. Ниже перечислен полный список системы команд «заточенной» под алгоритм TEA.
Мнемоника инструкции BYTE (1) BYTE (2) IMM8 / IMM32 PUSH 0000 REG32 - - POP 0001 REG32 - - BSWAP 0010 REG32 - - SHL 0011 REG32 - - SHR 0100 REG32 - - LEAVE 0101 - - - RETN 0110 0000 IMM16 MOV 0111 EXT* REG32, REG32 IMM8/IMM32 XOR 1000 0000 REG32, REG32 - ADD 1001 EXT* REG32, REG32 IMM32 SUB 1010 EXT* REG32, REG32 IMM32 LEA 1011 REG32 REG32, REG32 - JNZ 1100 0000 IMM32 CMP 1101 0000 IMM32 |
*EXT – означает, что инструкция имеет расширение, от значения которого зависит наличие дополнительных параметров/метода адресации и т.д. Рассмотрим параметр EXT подробнее:
EXT Дополнительные Параметры 0001 REG32, REG32 0010 REG32, DWORD PTR [REG32] 0011 REG32, DWORD PTR [IMM32] 0100 REG32, DWORD PTR [REG32 + imm8] 0101 MOV REG32, IMM32 |
Стоит объяснить на примере смысл значения EXT.
OPCODE EXT BYTE 2 IMM8 0111 0100 00001010 020h |
По полю «OPCODE» видно, что используется инструкция «MOV», по параметру «EXT» из таблицы можно понять, какой метод адресации используется в данной инструкции, получается вид: «REG32, DWORD PTR [REG32 + imm8]» далее по второму байту, в котором хранятся индексы двух регистров можно смело утверждать, что первый регистр будет ECX, а второй EDX, из третьего байта возьмём IMM8. В результате имеем следующее:
MOV ECX, DWORD PTR [EDX + 020h] |
Итак, будем считать, что система команд у нас готова. Далее следует реализация псевдокода. В этом примере я использовал макросы для генерации оного. Описание приводить здесь не буду, посмотрите исходник в архиве «macros.inc», ничего сложного там нет, всё сделано по табличке системы комманд.
P.S. Хотелось бы добавить ещё мысли по поводу индексов регистров в системе комманд.
Можно заменить индексы, прямыми адресами переменных под регистры, что уменьшит скорость обращения к ним, но увеличит размер псевдокода, но данную причину не расцениваю как недостаток, ведь всёравно быстрее чем на реальном процессоре выполнить псевдокод не получится.
Автор: JakoLerto
Скачать исходники для статьи (мини VM) (412)