Parsi Coders
Simple Code Virtualization (Virtual Machine / Emulator) - نسخه قابل چاپ

+- Parsi Coders (http://parsicoders.com)
+-- انجمن: Software Development Programming (http://parsicoders.com/forumdisplay.php?fid=37)
+--- انجمن: Pascal/Delphi (http://parsicoders.com/forumdisplay.php?fid=45)
+---- انجمن: Delphi (http://parsicoders.com/forumdisplay.php?fid=69)
+---- موضوع: Simple Code Virtualization (Virtual Machine / Emulator) (/showthread.php?tid=1113)



Simple Code Virtualization (Virtual Machine / Emulator) - Amin_Mansouri - 10-18-2011

Hi longtime ago learning about VM (virtual Machine),



کد:
program vmtest;

uses
  Windows, sysutils, codesitelogging;

const
// Registers
REGISTER_EAX = 0;
REGISTER_ECX = 1;
REGISTER_EDX = 2;
REGISTER_EBX = 3;
REGISTER_ESP = 4;
REGISTER_EBP = 5;
REGISTER_ESI = 6;
REGISTER_EDI = 7;
REGISTER_NOP = 8;


Type
  PVMCONTEXT = ^TVMCONTEXT;
  TVMCONTEXT = record
    _Eip: DWord;
    Reg: array [0..7] of DWord;  //EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
  end;

  TINST = Record
    op: string;
    Func: Procedure (c: PVMCONTEXT);
  end;

procedure Addcode(c: PVMCONTEXT; n : byte);
begin
  inc(c^._eip, n);
end;

Procedure VRetN(c: PVMCONTEXT);
begin
  codesite.Send('eax', c^.Reg[REGISTER_EAX]);
end;

Procedure VJmp(c: PVMCONTEXT);
var
  imm32 : DWord;
begin
  inc(c^._eip);
  imm32 := PDword(c^._eip)^;
  c^._eip := imm32;
end;

Procedure VPUSHImm(c: PVMCONTEXT);
var
  imm32 : DWord;
begin
  inc(c^._eip);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  PDword(c^.Reg[REGISTER_ESP])^ := imm32;
  inc(c^.Reg[REGISTER_ESP], 4);
end;

Procedure VPUSHReg(c: PVMCONTEXT);
var
  regflag: Byte;
  imm32 : DWord;
begin
  inc(c^._eip);
  regflag := pByte(c^._eip)^;
  Addcode(c,1);
  if( regflag < 8 ) then begin
    imm32 := c^.Reg[regflag];
    PDword(c^.Reg[REGISTER_ESP])^ := imm32;
    inc(c^.Reg[REGISTER_ESP], 4);
  end else begin
    codesite.senderror('VPUSHReg');
  end;
end;

Procedure VPUSHMem(c: PVMCONTEXT);
var
  mem32 : DWord;
  imm32 : DWord;
begin
  inc(c^._eip);
  mem32 := PDword(c^._eip)^;
  imm32 := PDword(mem32)^;
  Addcode(c, 4);
  PDword(c^.Reg[REGISTER_ESP])^ := imm32;
  inc(c^.Reg[REGISTER_ESP], 4);
end;

Procedure VPOPReg(c: PVMCONTEXT);
var
  regflag: Byte;
  imm32 : DWord;
begin
  inc(c^._eip);
  regflag := pByte(c^._eip)^;
  Addcode(c,1);
  if( regflag < 8 ) then begin
    imm32 := PDword(c^.Reg[REGISTER_ESP])^;
    dec(c^.Reg[REGISTER_ESP], 4);
    c^.Reg[regflag] := imm32;
  end;
end;

Procedure VPOPMem(c: PVMCONTEXT);
var
  imm32 : DWord;
  mem32 : DWord;
begin
  imm32 := PDword(c^.Reg[REGISTER_ESP])^;
  dec(c^.Reg[REGISTER_ESP], 4);
  mem32 := PDword(c^._eip)^;
  Addcode(c, 4);
  PDword(mem32)^ := imm32;
end;

procedure VMovRegReg(c: PVMCONTEXT);
var
  DestReg, SrcReg: Byte;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if( DestReg < 8 ) and ( SrcReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VMovRegReg');
  end;
end;

procedure VMovRegImm(c: PVMCONTEXT);
var
  DestReg: Byte;
  imm32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := imm32;
  end else begin
    codesite.senderror('VMovRegImm');
  end;
end;

procedure VMovRegMem(c: PVMCONTEXT);
var
  DestReg: Byte;
  mem32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  mem32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := PDword(mem32)^;
  end else begin
    codesite.senderror('VMovRegMem');
  end;
end;

procedure VADDRegReg(c: PVMCONTEXT);
var
  DestReg, SrcReg: Byte;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if( DestReg < 8 ) and ( SrcReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] +  c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VADDRegReg');
  end;
end;

procedure VADDRegImm(c: PVMCONTEXT);
var
  DestReg: Byte;
  imm32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] + imm32;
  end else begin
    codesite.senderror('VADDRegImm');
  end;
end;

procedure VADDRegMem(c: PVMCONTEXT);
var
  DestReg: Byte;
  mem32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  mem32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] + PDword(mem32)^;
  end else begin
    codesite.senderror('VADDRegMem');
  end;
end;

procedure VSUBRegReg(c: PVMCONTEXT);
var
  DestReg, SrcReg: Byte;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if( DestReg < 8 ) and ( SrcReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] -  c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VSUBRegReg');
  end;
end;

procedure VSUBRegImm(c: PVMCONTEXT);
var
  DestReg: Byte;
  imm32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] - imm32;
  end else begin
    codesite.senderror('VSUBRegImm');
  end;
end;

procedure VSUBRegMem(c: PVMCONTEXT);
var
  DestReg: Byte;
  mem32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  mem32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] - PDword(mem32)^;
  end else begin
    codesite.senderror('VSUBRegMem');
  end;
end;

procedure VMulEaxReg(c: PVMCONTEXT);
var
  SrcReg: Byte;
begin
  inc(c^._eip);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if ( SrcReg < 8 ) then begin
    c^.Reg[REGISTER_EAX] := c^.Reg[REGISTER_EAX] -  c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VMulEaxReg');
  end;
end;

procedure VDivEaxReg(c: PVMCONTEXT);
var
  SrcReg: Byte;
begin
  inc(c^._eip);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if ( SrcReg < 8 ) then begin
    c^.Reg[REGISTER_EAX] := c^.Reg[REGISTER_EAX] div c^.Reg[SrcReg];
    c^.Reg[REGISTER_EDX] := c^.Reg[REGISTER_EAX] mod c^.Reg[SrcReg]
  end else begin
    codesite.senderror('VDivEaxReg');
  end;
end;

procedure VAndRegReg(c: PVMCONTEXT);
var
  DestReg, SrcReg: Byte;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if( DestReg < 8 ) and ( SrcReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] and  c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VAndRegReg');
  end;
end;

procedure VAndRegImm(c: PVMCONTEXT);
var
  DestReg: Byte;
  imm32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] And imm32;
  end else begin
    codesite.senderror('VAndRegImm');
  end;
end;

procedure VAndRegMem(c: PVMCONTEXT);
var
  DestReg: Byte;
  mem32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  mem32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] And PDword(mem32)^;
  end else begin
    codesite.senderror('VAndRegMem');
  end;
end;

procedure VORRegReg(c: PVMCONTEXT);
var
  DestReg, SrcReg: Byte;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  SrcReg := pByte(c^._eip)^;
  Addcode(c,1);
  if( DestReg < 8 ) and ( SrcReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] or  c^.Reg[SrcReg];
  end else begin
    codesite.senderror('VORRegReg');
  end;
end;

procedure VORRegImm(c: PVMCONTEXT);
var
  DestReg: Byte;
  imm32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  imm32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] Or imm32;
  end else begin
    codesite.senderror('VORRegImm');
  end;
end;

procedure VORRegMem(c: PVMCONTEXT);
var
  DestReg: Byte;
  mem32: DWord;
begin
  inc(c^._eip);
  DestReg := pByte(c^._eip)^;
  Addcode(c,1);
  mem32 := PDword(c^._eip)^;
  Addcode(c,4);
  if( DestReg < 8 ) then begin
    c^.Reg[DestReg] := c^.Reg[DestReg] or PDword(mem32)^;
  end else begin
    codesite.senderror('VORRegMem');
  end;
end;

const
  inst_table1 : array [0..23] of TINST =(
    {00}(op: 'Retn'; Func: VRetN),
    {01}(op: 'Jump'; Func: VJmp),
    {02}(op: 'PUSHIm'; Func: VPUSHImm),
    {03}(op: 'PUSHReg'; Func: VPUSHReg),
    {04}(op: 'PUSHMem'; Func: VPUSHMem),
    {05}(op: 'POPReg'; Func: VPOPReg),
    {06}(op: 'POPMem'; Func: VPOPMem),
    {07}(op: 'MovRegReg'; Func: VMovRegReg),
    {08}(op: 'MovRegImm'; Func: VMovRegImm),
    {09}(op: 'MovRegMem'; Func: VMovRegMem),
    {10}(op: 'ADDRegReg'; Func: VADDRegReg),
    {11}(op: 'ADDRegImm'; Func: VADDRegImm),
    {12}(op: 'ADDRegMem'; Func: VADDRegMem),
    {13}(op: 'SUBRegReg'; Func: VSUBRegReg),
    {14}(op: 'SUBRegImm'; Func: VSUBRegImm),
    {15}(op: 'SUBRegMem'; Func: VSUBRegMem),
    {16}(op: 'MulEaxReg'; Func: VMulEaxReg),
    {17}(op: 'DivEaxReg'; Func: VDivEaxReg),
    {18}(op: 'ANDRegReg'; Func: VANDRegReg),
    {19}(op: 'ANDRegImm'; Func: VANDRegImm),
    {20}(op: 'ANDRegMem'; Func: VANDRegMem),
    {21}(op: 'ORRegReg'; Func: VORRegReg),
    {22}(op: 'ORRegImm'; Func: VORRegImm),
    {23}(op: 'ORRegMem'; Func: VORRegMem)
  );

Function ExecuteVM(Code: Pointer; Size: DWord):TVMCONTEXT;
var
  Ins: TINST;
  Op: Byte;
  Stack: Pointer;
begin
  with result do begin

    {Setup Machine}
    for op:= 0 to 7 do Reg[op] := 0;

    GetMem(Stack, 1024*1024*2);
    Reg[REGISTER_ESP] := DWord(Stack);

    _eip := DWord(Code);

    {Execute Cycle}
    while (_eip <= (DWord(Code)+Size) -1 ) do begin
      Op := pByte(_eip)^;
      Ins := inst_table1[Op];
      codesite.Send('%s / %s', [inttohex(Op, 2), Ins.op]);
      Ins.Func(@result);
      if (Op = 0) then exit;
    end;

    FreeMem(Stack, 1024*1024*2);
  end;
end;

const
Temp:Array [0..12] of byte =(
   $08,$00,$05,$00,$00,$00,   //mov     eax, 5
   $0B,$00,$05,$00,$00,$00,  //add     eax, 5
   $00                       //ret
);      

begin
  ExecuteVM(@temp[0], sizeof(temp));
end.