Let’s play with Forsaken World.
Some lyrics before we start. When the FW became available I and other people noticed that this client is different than Perfect World. What exactly? Improved protection and tricky anti-debug technique: hooked API, encrypted files etc. OllyDbg will crash or client goes into infinity loop… Sweet.
This is a draft, smattering explanation with some notes regarding FW protection and anti-debug techniques.
Ok. At the beginning we should check our “minefield” with pogo stick…
1. We start Ollydbg and run FW client. FW freezes
2. We start client, run olly and attach debugger to the client… my olly 2 crashed with lots of exceptions; olly 1.10 with Strong plugin stopped here
0D650000 /EB 10 jmp short 0D650012
0D650002 |6A 00 push 0x0
0D650004 |6A FE push -0x2
0D650006 |FF15 0E00650D call dword ptr [0xD65000E] ; ntdll.RtlExitUserThread
0D65000C ^|EB F4 jmp short 0D650002
0D65000E |9B wait
0D65000F |14 96 adc al, 0x96
0D650011 |7C 68 jl short 0D65007B
0D650013 2000 and byte ptr [eax], al
0D650015 65:0D 33C064FF or eax, 0xFF64C033
0D65001B 306489 20 xor byte ptr [ecx+ecx*4+0x20], ah
0D65001F CC int3
=> 0D650020 90 nop
0D650021 ^ EB DF jmp short 0D650002
3. Now we will load game.exe under clean ollydbg and execute it… and will receive message box with some, as I think, good words about our try. Reload game.exe
00DC4325 /> \C645 C8 01 MOV BYTE PTR SS:[EBP-38],1
00DC4329 |. C745 FC 00000000 MOV DWORD PTR SS:[EBP-4],0
=> 00DC4330 |. CD 2D INT 2D
00DC4332 |. 33C0 XOR EAX,EAX
00DC4334 |. 83C0 02 ADD EAX,2
00DC4337 |. C745 FC FFFFFFFF MOV DWORD PTR SS:[EBP-4],-1
00DC433E \. EB 14 JMP SHORT 00DC4354
00DC4340 /. B8 01000000 MOV EAX,1
00DC4345 \. C3 RETN
00DC4346 /. 8B65 E8 MOV ESP,DWORD PTR SS:[EBP-18]
00DC4349 |. C645 C8 00 MOV BYTE PTR SS:[EBP-38],0
00DC434D |. C745 FC FFFFFFFF MOV DWORD PTR SS:[EBP-4],-1
00DC4354 |> 8B45 C8 MOV EAX,DWORD PTR SS:[EBP-38]
00DC4357 |. 25 FF000000 AND EAX,000000FF
00DC435C |. 85C0 TEST EAX,EAX
00DC435E |. 74 03 JE SHORT 00DC4363
00DC4360 |. 58 POP EAX
00DC4361 |. 5A POP EDX
00DC4362 |. 5E POP ESI
00DC4363 |> 833D 10CD0901 00 CMP DWORD PTR DS:[109CD10],0
00DC436A |. 75 3F JNE SHORT 00DC43AB
=> 00DC436C |. FF15 00D0FC00 CALL DWORD PTR DS:[<&KERNEL32.IsDebuggerPresent>] ; [KERNEL32.IsDebuggerPresent
00DC4372 |. 85C0 TEST EAX,EAX
00DC4374 |. 75 1C JNE SHORT 00DC4392
00DC4376 |. E8 D52D0000 CALL 00DC7150
00DC437B |. 25 FF000000 AND EAX,000000FF
00DC4380 |. 85C0 TEST EAX,EAX
00DC4382 |. 75 0E JNE SHORT 00DC4392
00DC4384 |. E8 472E0000 CALL 00DC71D0
00DC4389 |. 25 FF000000 AND EAX,000000FF
00DC438E |. 85C0 TEST EAX,EAX
00DC4390 |. 74 19 JE SHORT 00DC43AB
00DC4392 |> 6A 00 PUSH 0
00DC4394 |. 68 2C610C01 PUSH 010C612C
00DC4399 |. 68 08610C01 PUSH 010C6108
00DC439E |. 6A 00 PUSH 0
our message box => 00DC43A0 |. FF15 48D1FC00 CALL DWORD PTR DS:[<&USER32.MessageBoxA>] 00DC43A6 |. E9 B82C0000 JMP 00DC7063
You can bypass IsDebuggerPresent and INT 2D;
Some words about INT 2D: this instruction can be used as a general purpose debugger detection method, because when executing the instruction, if no debugger is present, an exception will occur. However, if a debugger is present, no exception will occur, and things get interesting based on the debugger you are using. OllyDbg will actually skip a byte in its disassembly and will cause the analysis to go wrong.
you can nop some JNE and make JMP on 00DC4390
00DC4372 |. 85C0 TEST EAX,EAX
00DC4374 90 NOP
00DC4375 90 NOP
00DC4376 |. E8 D52D0000 CALL 00DC7150
00DC437B |. 25 FF000000 AND EAX,000000FF
00DC4380 |. 85C0 TEST EAX,EAX
00DC4382 90 NOP
00DC4383 90 NOP
00DC4384 |. E8 472E0000 CALL 00DC71D0
00DC4389 |. 25 FF000000 AND EAX,000000FF
00DC438E |. 85C0 TEST EAX,EAX
00DC4390 EB 19 JMP SHORT 00DC43AB
Actually, this isn’t interesting or useful When we run game.exe, it recreates itself as a child process and Finita la comedia. If we trace execution routine, after long-long decryption cycles and memory copying parts, we will get
00DC6E04 E8 57C4FFFF call 00DC3260
00DC6E09 83C4 04 add esp, 0x4
00DC6E0C 8B15 04EC0F01 mov edx, dword ptr [0x10FEC04]
00DC6E12 52 push edx
00DC6E13 A1 B00B0901 mov eax, dword ptr [0x1090BB0]
00DC6E18 05 BC3B0000 add eax, 0x3BBC
=> 00DC6E1D FFD0 call eax ; proccess already created
00DC6E1F 8D4D 84 lea ecx, dword ptr [ebp-0x7C]
00DC6E22 51 push ecx
00DC6E23 6A 00 push 0x0
00DC6E25 8B15 14E00801 mov edx, dword ptr [0x108E014]
00DC6E2B 52 push edx
00DC6E2C 68 103FDD00 push 00DD3F10
At this moment child game.exe process is already created and suspended. And now what? Nothing, it was a long prelude…
How to bypass anti-debugger (anti-attach) protection and how does it works when debugger attaching to the debugee? Anytime a debugger is attaching itself to an aim process (debugee), system creates a new thread, which starts at DbgUiRemoteBreakin (ntdll!DbgUiRemoteBreakin) function in debugee's process space.
When the process is about to be debugged, ntdll!DbgUiDebugActiveProcess calls ntdll!DbgUiIssueRemoteBreakin and this one creates a thread that starts at ntdll!DbgUiRemoteBreakin. The new thread is created via a call to ntdll!RtlCreateUserThread. When started, ntdll!DbgUiRemoteBreakin calls ntdll!DbgBreakPoint which is actually just a pair of 2 instructions: int3 and ret.
So, if application hooks the entry point of the function, it can control the flow of the code being executed…
Let’s approve our statement about hooked DbgUiRemoteBreakin by Forsaken World client.
7C94FFE3 > C2 0C00 retn 0xC
7C94FFE6 F8 clc
7C94FFE7 0095 7CE8BCE8 add byte ptr [ebp-0x17431784], dl
7C94FFED FB sti
7C94FFEE FF64A1 18 jmp dword ptr [ecx+0x18]
7C94FFF2 0000 add byte ptr [eax], al
7C94FFF4 008B 40308078 add byte ptr [ebx+0x78803040], cl
7C94FFFA 0200 add al, byte ptr [eax]
7C94FFFC 75 09 jnz short 7C950007
7C94FFFE F605 D402FE7F 0>test byte ptr [0x7FFE02D4], 0x2
7C950005 74 20 je short 7C950027
7C950007 8365 FC 00 and dword ptr [ebp-0x4], 0x0
7C95000B E8 FE11FBFF call DbgBreakPoint
7C950010 EB 11 jmp short 7C950023
Yeah, instead
7C94FFE3 > 6A 08 push 0x8
7C94FFE5 68 3000957C push 7C950030
7C94FFEA E8 BCE8FBFF call 7C90E8AB
we have retn 0xC. Restoring DbgUiRemoteBreakin will give you opportunity to attach debuggers... but this is only one small part of FW protection
How to open FW client under debugger with hooked DbgUiRemoteBreakin…
Let’s debug the debugger… soon (maybe)
Note: If I forgot something, or if someone wants something to add, you are welcome
Note: Any materials only for educational purpose
by Dwar