• [Delphi] Simple Code Virtualization (Virtual Machine / Emulator)

    Code Virtualization apayah ? masa gak tau sih .. Ituloh teknologi digunakan packer (program proteksi) agar kode kita sulit dianalisa. Konsepnya code virtualization simple sih, cukup translate code ke virtualmachine code dan mengeksekusinya pada virtualmachine, heheh simple kan ? Tentu saja tidak karena virtualmachine sendiri itu saya tidak tau bentuk-nya bagaimana .

    Virtual Machine atau Mesin Virtual atau Emulator adalah mesin yang mengeksekusi code sesuai apa yang dilakukan mesin asli (real Cpu). Dalam Pengeksekusian kode pada real cpu yang dilakukan adalah fetching (mengambil/menarik data misal opcode) dan melakukan eksekusi berdasarkan opcode, nah hall inilah yang dilakukan oleh virtual machine. Ada banyak opcode dan tentu saja korelasinya dengan register, flag dan lain2 (silahkan baca2 buku assembly biar jelasnya).


    Tujuan dari pembuatan sample itu karena kurangnya contoh dan penjelasan tentang teknologi virtualmachine or emulator, semoga berguna dan memberikan penjelasan tentang dunia virtualization itu sendiri. Oh ya Code dibawah tentu saja tidak bisa dikatakan virtual machine yang bagus, selain belum mencakup semua execution opcode, cpuflag, jump+, juga belum ada virtualmemory (bagi yang ingin buat emulator). Tapi gak papalah namanya juga sample, iya nda sih ?. Oh ya here u go codenya


    Code:
    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.

    silahkan comment kalau ada yang kurang dimengerti or ada saran buat kodenya.. kan lumayan tuh kalau di diskusiin ..
    Comments 2 Comments
    1. tjupliest's Avatar
      tjupliest -
      ada yang kurang minta di sourcecode nya...hahahahahahaha
    1. janglapuk's Avatar
      janglapuk -
      keren!
      lebih keren lagi klo ada dump hasil virtual memory-nya (dalam bentuk hex), jadi kelihatan mana opcode standar dan mana yang sudah virtualized.