View Full Version : Виртуелно, виртуелно и машински

October 18th, 2007, 10:16
VirtualMachines are really boring, the real art of unpacking is changed with pointless vm reversing. It's really pointless as same result are achived with appending vm, but some authors really crack me up:

(88) mov vm_reg298, 11B0A5B4h
(39) add vm_reg298, 00000060h
(97) mov vm_reg298, [vm_reg298]
(DB) mov vm_reg244, 01101640
(64) add vm_reg244, vm_reg298
(6C) mov vm_regDC, 01107414h
(64) add vm_regDC, vm_reg298
(97) mov vm_regDC, [vm_regDC]
(85) mov vm_reg1A4, vm_reg1C
(26) add vm_reg244, 000000C4h
(97) mov vm_reg2FC, [vm_reg244]
(C3) add vm_reg2FC, vm_regDC
(25) add vm_reg1A4, vm_reg2FC
(38) sub vm_reg244, 000000C4h
(DE) mov vm_reg1A4, [vm_reg1A4]
(A9) mov vm_reg80, vm_reg1C
(F4) add vm_reg244, 000000C8h
(D0) mov vm_reg2FC, [vm_reg244]
(C3) add vm_reg2FC, vm_regDC
(37) add vm_reg80, vm_reg2FC
(B3) sub vm_reg244, 000000C8h
(19) mov vm_reg80, [vm_reg80]
(98) mov vm_regAC, vm_reg1C
(5E) add vm_reg244, 000000CCh
(56) mov vm_reg2FC, vm_reg244
(C3) add vm_reg2FC, vm_regDC
(C3) add vm_regAC, vm_reg2FC
(72) sub vm_reg244, 000000CCh
(19) mov vm_regAC, [vm_regAC]
(66) mov vm_reg1F4, vm_reg1C
(4E) add vm_reg244, 000000D0h
(97) mov vm_reg2FC, [vm_reg244]
(64) add vm_reg2FC, vm_regDC
(C3) add vm_reg1F4, vm_reg2FC
(B3) sub vm_reg244, 000000D0h
(A6) mov vm_reg1F4, [vm_reg1F4]
(85) mov vm_reg2F4, vm_reg1C
(4E) add vm_reg244, 000000D4h
(D6) mov vm_reg2FC, [vm_reg244]
(37) add vm_reg2FC, vm_regDC
(64) add vm_reg2F4, vm_reg2FC
(52) sub vm_reg244, 000000D4
(A6) mov vm_reg2F4, [vm_reg2F4]
(66) mov vm_regF4, vm_reg1C
(26) add vm_reg244, 000000D8h
(97) mov vm_reg2FC, [vm_reg244]
(64) add vm_reg2FC, vm_regDC
(93) push vm_reg8

(43) mov vm_reg10, 00000000h <---- silent update in vm_context

(0B) add vm_reg3F4, AD3AC892h <---- wrongly decoded instruction, due to "silent" update

This disassembly doesn't give too much hint when doing it staticaly, but when performing it in the live process it makes much more sense. Well especially part where magic filed in vm_context is silently updated... funny... with static tracing this can be located easily as you will get bunch of wrong disasm(last instruction in static tracing), but with properly decoded vm (eg. emulated in live process where we have access to whole progy memory) this lille trick wouldn't even be noticed + we could simply put (in case of emulation) our code instead of making file 40mb larger. Does this count as an owning? Or we have to restore x86 opcodes back... let me know

for comparing reasons, vm emulator 38kb, all stuff dumped ~20mb... in both cases protection is defeated, but... we make user friendly dump with extra 38kb of code, neet isn't it

anyway I'm off to play some poker... that thingie is addictive

aaaaaand game goes on:

(24) mov vm_reg3C8, 0424448Bh
(11) mov vm_reg3CC, 08244C8Bh
(24) mov vm_reg3D0, 0004C969h
(DB) mov vm_reg3D4, 30800000
(DA) mov vm_reg3D8, FAE240F1
(AA) mov vm_reg3DC, 505A5958h
(AA) mov vm_reg3E0, 9090C351h
(24) mov vm_reg320, F1F17899h
(24) mov vm_reg324, 85706DF1h
(DB) mov vm_reg328, F179F5D5
(6C) mov vm_reg32C, 6C61F1F1h
(E2) mov vm_reg330, D5957CA9h
(11) mov vm_reg334, D5ED780Dh
(9F) mov vm_reg338, 2ED453FEh
(D8) mov vm_reg33C, 7A0E0E0Eh
(E2) mov vm_reg340, 957CD5EDh
(6C) mov vm_reg344, 3270F5D5h
(DA) mov vm_reg348, F1F1F1A9
(24) mov vm_reg34C, D5DD70A5h
(AA) mov vm_reg350, F1F1F1F1h
(24) mov vm_reg354, F5D5957Ch
(AA) mov vm_reg358, 70A5F278h
(E2) mov vm_reg35C, F195D5DDh
(F9) mov vm_reg360, 957CF1F1h
(D8) mov vm_reg364, 1D70F5D5h
(DA) mov vm_reg368, F1F1F1F5
(AA) mov vm_reg36C, 4AD5ED78h
(E2) mov vm_reg370, 1220F5E8h
(E2) mov vm_reg374, 02700D82h
(DB) mov vm_reg378, 3653F99B
(43) mov vm_reg37C, AAD5EDD8h
(E2) mov vm_reg380, 61616132h
(11) mov vm_reg388, 00000019h
(66) mov vm_reg38C, vm_reg14
(1A) add vm_reg38C, 00000320h
(93) push vm_reg388
(93) push vm_reg38C
(98) mov vm_reg38C, vm_reg14
(9B) add vm_reg38C, 000003C8h
(8F) call vm_reg38C
(F9) mov vm_reg388, 4A35B626h
(87) sub vm_reg2FC, vm_reg58
(C3) add vm_regF4, vm_reg2FC

Let's see what is going on when reg38C is executed:

seg000:018C03C8 mov eax, [esp+4]
seg000:018C03CC mov ecx, [esp+8]
seg000:018C03D0 imul ecx, 4
seg000:018C03D6 __more_bre_dekriptujeme: ; CODE XREF: seg000:018C03DAj
seg000:018C03D6 xor byte ptr [eax], 0F1h
seg000:018C03D9 inc eax
seg000:018C03DA loop __more_bre_dekriptujeme
seg000:018C03DC pop eax
seg000:018C03DD pop ecx
seg000:018C03DE pop edx
seg000:018C03DF push eax
seg000:018C03E0 push ecx
seg000:018C03E1 retn

and code which is being decrypted:

seg000:018C0320 push 89h ; ''
seg000:018C0325 pushf
seg000:018C0326 xor dword ptr [esp+4], 88h
seg000:018C032E nop
seg000:018C032F popf
seg000:018C0330 pop eax
seg000:018C0331 lea esp, [esp-4]
seg000:018C0335 mov [esp], ebx
seg000:018C0338 cpuid
seg000:018C033A and eax, 0FFFFFFDFh
seg000:018C033F mov ebx, [esp]
seg000:018C0342 lea esp, [esp+4]
seg000:018C0346 add ebx, 58h ; 'X'
seg000:018C034C push esp
seg000:018C034D sub dword ptr [esp], 0
seg000:018C0354 lea esp, [esp+4]
seg000:018C0358 mov [ebx], eax
seg000:018C035A push esp
seg000:018C035B sub dword ptr [esp], 64h ; 'd'
seg000:018C0362 lea esp, [esp+4]
seg000:018C0366 sub esp, 4
seg000:018C036C mov [esp], ebx
seg000:018C036F loc_18C036F: ; CODE XREF: seg000:018C0374j
seg000:018C036F mov ebx, 0E3D10419h
seg000:018C0374 jnb short near ptr loc_18C036F+3
seg000:018C0376 xor ebx, 0C7A2086Ah
seg000:018C037C sub [esp], ebx
seg000:018C037F pop ebx
seg000:018C0380 retn

basicaly this is hiden cpuid check, and value of cpuid is stored to vm_reg58, later on in virtual machine, right after call vm_reg we have this code:

(87) sub vm_reg2FC, vm_reg58
(C3) add vm_regF4, vm_reg2FC

vm_reg2FC already has imm+cpuid value, so here we have yet another vm anti-dump...

some API redirection:

(85) mov vm_regF0, vm_reg1C
(7A) add vm_regF0, 00000024h <-- eip offset
(D0) mov vm_regF0, [vm_regF0] <-- get ret addy
(B4) mov vm_regF4, vm_reg1C
(C4) add vm_regF4, 00000028h
(F0) mov [vm_regF4], vm_regF0 <-- save ret addy
(34) single-step check
(29) mov vm_regF4, vm_reg1C
(A8) add vm_regF4, 00000024h
(F9) mov vm_reg90, 10FC5180h
(19) mov vm_reg90, [vm_reg90] <-- get api from 10FC5180h
(FB) mov [vm_regF4], vm_reg90 <-- save it to eip
(8B) vm_exit <-- and we go on...

API executed from 10FC5180h:

.idata:10FC5180 ; DWORD GetCurrentThreadId(void)
.idata:10FC5180 extrn GetCurrentThreadId:dword

basically when translated to something user friendly = call dword ptr[10FC5180]

game continues

October 18th, 2007, 15:55
owned either way as you fully understand the consequences when applying the method. The original app performance will also be acceptable as that is how it is published with vm in it anyways. owned.

October 18th, 2007, 16:42

October 19th, 2007, 00:37
Maximus, Shame on you!
You posting information_less texts just to fatten your post count (just like THIS VERY SAME ONE I am posting now )

October 19th, 2007, 08:52
So true, you both suck.