docs doc x86 stolen functions


stolen functions - introduction
--------------------------------------------------------------------

When the game enters VM, all registers and eflags are saved into VM
ram, then before execution of the real code, they are copied into VM
regs, then saved back to RAM after all.



stolen functions - types
--------------------------------------------------------------------

There are 2 known types of the stolen functions:
1) Code blocks
2) Emulated opcodes
a) VM emulated opcode
b) Nop slider opcode (ops not supported by the VM emul)



stolen functions - Code blocks
--------------------------------------------------------------------

As an example I will use "The Suffering - Ties that bind".
As you can see, the game hes 2 modules protected:
SufferingTTB.exe
SufferingTTB.rfl

The .exe has no stolen functions, just import table protection so
we skip it.
The .rfl file is a .dll, has more than 10 stolen functions,
it will be our target.

With logger attached, we can see the following log output while
game is running:

VM Enter ID: A5D2592A
Decoding block at: 0654019C => Multi-exit type
0654019C: push ebx
0654019D: mov ebx, dword ptr ss:[esp+8]
065401A1: test ebx, ebx
065401A3: push esi
065401A4: push edi
065401A5: mov esi, ecx
065401A7: jl 06540231
065401AD: mov ecx, dword ptr ds:[6EB20B8]
065401B3: cmp ebx, dword ptr ds:[ecx+1C]
065401B6: jge 06540231
065401BC: mov edi, ebx
065401BE: and edi, 3FF
065401C4: imul edi, dword ptr ds:[ecx+18]
065401C8: mov ecx, dword ptr ds:[ecx+4]
065401CB: mov eax, ebx
065401CD: cdq
065401CE: and edx, 3FF
065401D4: add eax, edx
065401D6: sar eax, A
065401D9: mov edx, dword ptr ds:[ecx+eax*4]
065401DC: mov eax, dword ptr ds:[edi+edx+1C]
065401E0: add edi, edx
065401E2: test eax, eax
065401E4: js 065401EC
065401E6: mov edx, dword ptr ds:[edi]
065401E8: mov ecx, edi
065401EA: call dword ptr ds:[edx]
065401EC: cmp dword ptr ds:[edi+8], A
065401F0: jnz 06540231
065401F6: mov ecx, dword ptr ds:[edi+4]
065401F9: mov eax, dword ptr ds:[ecx]
065401FB: push ebp
065401FC: push -1
065401FE: push 32
06540200: call dword ptr ds:[eax+8]
06540203: mov ebp, dword ptr ds:[eax]
06540205: mov eax, dword ptr ds:[esi+8]
06540208: xor ecx, ecx
0654020A: test eax, eax
0654020C: jle 06540223
0654020E: mov edx, dword ptr ds:[esi]
06540210: add edx, 4
06540213: cmp dword ptr ds:[edx], ebx
06540215: je 0654022D
0654021B: inc ecx
0654021C: add edx, C
0654021F: cmp ecx, eax
06540221: jl 06540213
06540223: or eax, FFFFFFFF
06540226: push 0
-> Exit-point reached (exitcode=0)
06540228: jmp 06540190
0654022D: mov eax, ecx
0654022F: jmp 06540226
06540231: push 1
-> Exit-point reached (exitcode=1)
06540233: jmp 06540190

So this is the original game code block, decrypted in the VMs runtime,
executed and at the end, we see 2 exit points, that lead into the VM
yet again, but the exit value makes a difference - tells the VM where
to go next, in other words, what would be the next block to decrypt/exec.

So here it comes:

Decoding block at: 06560208 => Single-exit type
06560208: cmp eax, -1
0656020B: mov edi, dword ptr ss:[esp+18]
0656020F: mov dword ptr ss:[esp+14], edi
-> Exit-point reached, exiting
065609E8: jmp 06560202

Decoding block at: 06511B18 => Multi-exit type
06511B18: jnz 06511B5F
06511B1E: push ebx
06511B1F: mov ecx, esi
06511B21: call 06D01000
06511B26: test eax, eax
06511B28: jnz 06511B33
06511B2A: push ebx
06511B2B: lea ecx, dword ptr ds:[esi+C]
06511B2E: call 06D017D0
06511B33: cmp edi, 1
06511B36: jg 06511B45
06511B38: push ebx
06511B39: mov ecx, esi
06511B3B: call 06D010B0
06511B40: cmp eax, 1
06511B43: jnz 06511B5B
06511B45: push 9710D816
06511B4A: push ebx
06511B4B: call 06D018C0
06511B50: add esp, 8
06511B53: test eax, eax
06511B55: je 06511B5B
06511B57: push 0
-> Exit-point reached (exitcode=0)
06511B59: jmp 06511B0C
06511B5B: push 1
-> Exit-point reached (exitcode=1)
06511B5D: jmp 06511B0C
06511B5F: test ebp, ebp
06511B61: push 2
-> Exit-point reached (exitcode=2)
06511B63: jmp 06511B0C

Decoding block at: 06560208 => Code-end type
06560208: mov edi, dword ptr ds:[esi+8]
0656020B: mov ecx, dword ptr ds:[esi+4]
0656020E: lea eax, dword ptr ds:[edi+1]
06560211: cmp ecx, eax
06560213: jge 06560221
06560215: push 3
06560217: push C
06560219: push eax
0656021A: mov ecx, esi
0656021C: call 06E6A1A0
06560221: mov eax, dword ptr ds:[esi+8]
06560224: mov ecx, dword ptr ds:[esi]
06560226: inc eax
06560227: mov dword ptr ds:[esi+8], eax
0656022A: lea eax, dword ptr ds:[edi+edi*2]
0656022D: shl eax, 2
06560230: test ebp, ebp
06560232: mov dword ptr ds:[eax+ecx+4], ebx
06560236: jle 0656023E
06560238: cmp dword ptr ss:[esp+18], ebp
0656023C: jg 06560242
0656023E: mov ebp, dword ptr ss:[esp+14]
06560242: mov edx, dword ptr ds:[esi]
06560244: mov dword ptr ds:[eax+edx+8], ebp
06560248: mov eax, ebp
0656024A: pop ebp
0656024B: pop edi
0656024C: pop esi
0656024D: pop ebx
0656024E: retn 8





stolen functions - Emulated opcodes (VM emulated opcode)
--------------------------------------------------------------------

You can find many examples how this was solved in the sf3_ext.dll
by reading its source, but I will paste here some examples.
The target is GTLDemo, function ID: 3033F7FE

;VM Enter ID: 3033F7FE
sub esp, 74
push ebx
push ebp
push esi
push edi
call [006BD4B4 + IB]
mov esi, [006BD4D8 + IB]
mov eax, [0098D08C + IB]
push 00000065
push eax
mov [0098D05C + IB], 00000030
mov [0098D070 + IB], eax
mov [0098D084 + IB], 0070FA28 + IB
mov [0098D064 + IB], 004DCEE0 + IB
mov [0098D060 + IB], 00000040
call esi
mov edi, [006BD068 + IB]
[....]

I will skip the first opcode, since its "Nop slider" or if you prefer
"SmartEmu" type.

-> push ebx

014b4872 (00497818): mov reg_01a8, fffffffc
014b4873 (00497824): add reg_0160, reg_01a8 reg_0160 = 0012f5fc, reg_01a8 = fffffffc, res = 0012f5f8
014b4874 (0049782c): push reg_0158 src = 7ffd8000

reg_01a8 = temp reg
reg_0160 = esp
reg_0158 = ebx

So as it seems, esp is increased by -4, and the ebx pushed.

push ebp:
014b4875 (00497834): mov reg_01a8, fffffffc
014b4876 (00497840): add reg_0160, reg_01a8 reg_0160 = 0012f5f8, reg_01a8 = fffffffc, res = 0012f5f4
014b4877 (00497848): push reg_0168 src = 00000008

push esi:
014b4878 (00497850): mov reg_01a8, fffffffc
014b4879 (0049785c): add reg_0160, reg_01a8 reg_0160 = 0012f5f4, reg_01a8 = fffffffc, res = 0012f5f0
014b487a (00497864): push reg_0170 src = 00000300

push edi:
014b487b (0049786c): mov reg_01a8, fffffffc
014b487c (00497878): add reg_0160, reg_01a8 reg_0160 = 0012f5f0, reg_01a8 = fffffffc, res = 0012f5ec
014b487d (00497880): push reg_0178 src = 00000400


call [006BD4B4 + IB]:
014b487e (00497888): mov reg_01a8, 006bd4b4
014b487f (00497894): add reg_01a8, reg_01a0 reg_01a8 = 006bd4b4, reg_01a0 = 00000000, res = 006bd4b4
014b4880 (0049789c): mov reg_0190, reg_01a8 reg_01a8 = 006bd4b4
014b4881 (004978a4): mov reg_0198, [reg_0190] reg_0190 = 006bd4b4, [reg_0190] = 07250311
014b4882 (004978ac): push reg_0198 src = 07250311
014b4883 (004978b4): push reg_0030 src = 00000216
014b4884 (004978bc): mov reg_0640, reg_0160 reg_0160 = 0012f5ec
[....]
014b48ff (00424388): jmp reg_0640 addr = 07810268
07810268: 58 pop eax
07810269: 5b pop ebx
0781026a: 89 7b 3c mov [ebx+60], edi
0781026d: 89 43 68 mov [ebx+104], eax
07810270: 61 popad
07810271: 9d popfd
07810272: 8d 64 24 04 lea esp, [esp+4]
07810276: ff 54 24 fc call [esp+252]
0781027a: 9c pushfd
0781027b: 60 pushad
0781027c: e8 00 00 00 00 call 0x07810281
07810281: 5b pop ebx
07810282: 8b 5b e3 mov ebx, [ebx+227]
[....]

Why +IB? IB is nothing more than "relocation", so if it was a
protected DLL, this would fix the pointer to a real address.
In the logger output Ib means this opcode needs relocation,
hence cracked/resolved code will work properly.

reg_0198 = temp reg, used to push call destination
reg_01a8 = usual temp reg
reg_01a0 = holds relocation fixing value




mov esi, [006BD4D8 + IB]:
014b4932 (002d3cd4): mov reg_01a8, 006bd4d8
014b4933 (002d3ce0): add reg_01a8, reg_01a0 reg_01a8 = 006bd4d8, reg_01a0 = 00000000, res = 006bd4d8
014b4934 (002d3ce8): mov reg_0190, reg_01a8 reg_01a8 = 006bd4d8
014b4935 (002d3cf0): mov reg_0198, [reg_0190] reg_0190 = 006bd4d8, [reg_0190] = 77d41324
014b4936 (002d3cf8): mov reg_0170, reg_0198 reg_0198 = 77d41324


mov ebp, eax:
014b4937 (002d3d00): mov reg_0168, reg_0140 reg_0140 = 00010014


etc.




stolen functions - Emulated opcodes (Nop slider opcode)
--------------------------------------------------------------------

Sometimes, when the vm cannot emulate some opcode using VM-ops,
the SmartEmu/NopSlider is used, example:


(00497490): mov reg_01a0, [vmbase + 004f8970] val = 00000000
014b4810 (004974ac): mov reg_0030, reg_01b8 reg_01b8 = 00000246
014b4811 (004974b4): mov reg_0188, 00000074 <---\
014b4812 (004974c0): mov reg_01a8, 9074ec83 <--- write sub esp, 74h opcode
014b4813 (004974cc): mov reg_01b0, 90909090
014b4814 (004974d8): mov reg_0188, 90909090
014b4815 (004974e4): mov reg_0198, 90909090
014b4816 (004974f0): push reg_0030 src = 00000246
014b4817 (004974f8): mov reg_0640, reg_0160 reg_0160 = 0012f670
014b4818 (00497500): push reg_0140 src = 00000000
014b4819 (00497508): push reg_0148 src = 0098d090
014b481a (00497510): push reg_0150 src = 00000008
014b481b (00497518): push reg_0158 src = 7ffd8000
014b481c (00497520): push reg_0640 src = 0012f670
014b481d (00497528): push reg_0168 src = 00000008
014b481e (00497530): push reg_0170 src = 00000300
014b481f (00497538): push reg_0178 src = 00000400


[....]

014b483f (00497658): add reg_0038, reg_0008 reg_0038 = 00131210, reg_0008 = 00c11000, res = 00d42210
014b4840 (00497660): push reg_0038 src = 00d42210
014b4841 (00497668): jmp reg_0648 addr = 0716159c
0716159c: 58 pop eax
0716159d: 5b pop ebx
0716159e: 89 7b 3c mov [ebx+60], edi
071615a1: 89 43 68 mov [ebx+104], eax
071615a4: 61 popad <-------------\
071615a5: 9d popfd <------------- restore real regs
071615a6: 90 nop
071615a7: 90 nop
071615a8: 83 ec 74 sub esp, 0x74 <--------- emulated opcode moved to the nop slider
071615ab: 90 nop
071615ac: 90 nop
071615ad: 90 nop
071615ae: 90 nop
071615af: 90 nop
071615b0: 90 nop
071615b1: 90 nop
071615b2: 90 nop
071615b3: 90 nop
071615b4: 90 nop
071615b5: 90 nop
071615b6: 90 nop
071615b7: 90 nop
071615b8: 9c pushfd
071615b9: 60 pushad
071615ba: e8 00 00 00 00 call 0x071615BF
071615bf: 5b pop ebx
071615c0: 8b 5b d9 mov ebx, [ebx+217]
071615c3: 8f 43 0c pop [ebx+12]
071615c6: 8f 43 10 pop [ebx+16]
071615c9: 8f 43 14 pop [ebx+20]
071615cc: 8d 64 24 04 lea esp, [esp+4]
071615d0: 8f 43 1c pop [ebx+28]
071615d3: 8f 43 20 pop [ebx+32]
071615d6: 8f 43 24 pop [ebx+36]
071615d9: 8f 43 28 pop [ebx+40]
071615dc: 8f 43 08 pop [ebx+8]
071615df: 89 63 18 mov [ebx+24], esp
071615e2: 8b 7b 3c mov edi, [ebx+60]
071615e5: ff 63 68 jmp [ebx+104]
smart emulation 'sub esp, 0x74'

[....]




Wyszukiwarka

Podobne podstrony:
docs doc x86 blocks
docs doc vm tricks
docs doc module unpacking process
docs doc virtual file system
docs doc overall info
docs doc logger install
function printer end doc
function printer end doc
function printer end doc
function printer start doc
function fdf add doc javascript
function domxml xslt stylesheet doc
function printer start doc
function udm get doc count
function domxml new doc
function printer start doc
function fdf next field name

więcej podobnych podstron