Реализация мини VM

автор | 7 Январь, 2009
рубрики RCE программирование, Антиотладка, Статьи Комментарии к записи Реализация мини VM отключены

asmil

Далее хотел бы предложить идею реализации мини ВМ, для защиты кода в программе.
Под мини ВМ подразумевается ВМ, с поддержкой ограниченного числа регистров и инструкций, по принципу чтения и исполнения байт кода/псевдокода.

Реализовано на примере алгоритма 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) (386)
Оценить эту тему:
1 звезда2 звезды3 звезды4 звезды5 звезд (137 голосов, средний: 4,04 из 5)
Loading...Loading...
Популярность: 6 293 просмотров
Вы можете следить за любыми ответами на эту запись через RSS 2.0 feed. Комментарии в настоящее время закрыты.