Archive

Posts Tagged ‘vectored exception handling’

New ‘Anti-detection’ in WoWMimic v.46

May 24th, 2009

With WoWMimic v.46 being out for a while now and still no update for my detector, I figured I’d explain some of the changes made because I’m bored.

First things first, credits to Harko and Kynox for working with me on this.

The WoWMimic devs have removed a lot of their previous API hooks and left only the following:

  • GetCursorPos
  • SetCursorPost
  • NtGetContextThread
  • NtQueryVirtualMemory

The hooks on GetCursorPos and SetCursorPos have nothing to do with anti-detection and are just there to allow them to use the mouse properly from their injected DLL, so I am not interested in those. What I am interested in is NtGetContextThread, NtQueryVirtualMemory, and their new hooking method.

Rather than use an inline jump hook like previous builds they have gotten a little smarter and use vectored exception handling by inserting an invalid instruction at the start of the APIs. The reason this is a smarter approach is that it’s harder to track down the hook functions at runtime and hence harder to hash them. A downside of this approach though is that its very easy to identify their unique hook. Also, its still possible to manually walk the VEH linked list and find their VEH and hence their hook functions. Then again, there’s nothing stopping WoW registering a VEH above mimics (which happens if you run mimic before logging in) then using that to intercept the hooked APIs and handle it before mimic can.

Currently their vectored exception handler does three things:

  • Manage the NtQueryVirtualMemory hook
  • Manage the NtGetContextThread hook
  • Manage an unknown hook (seems to be an unused hwbp hook)

Their NtQueryVirtualMemory hook is simple. It stops Warden from RVA hashing their module using its regular module scan by returning modified data pages in their module’s memory range.

The NtGetContextThred is also quite simple. It hides hardware breakpoints by overwriting the ContextFlags in the context structure passed to the API.

The third and unknown hook seems simply to be a skeleton for a hardware breakpoint hook (hence the NtGetContextThread hook). What’s interesting though is that currently it appears to be totally unused.

Whilst WoWMimic is still HIGHLY detectable (its a fairly trivial process to detect it), they are at least making some progress. Still though, it’s far from safe so don’t use it on any accounts you value.

Appendix:

In case anyone is interested, I have dumped their VectoredHandler and API hooks. They are fully commented so even if you’re not great with ASM or Windows internals it should be easy to follow. (You will want to copy all the text into a larger window because the blog has a small width and its very difficult to read the code when it’s line-wrapped)

; LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo)

23C4E9E0 | 8B4424 04          | MOV     EAX, DWORD PTR [ESP+4]    | ; Access ExceptionInfo

23C4E9E4 | 8B40 04            | MOV     EAX, DWORD PTR [EAX+4]    | ; Access ExceptionInfo->ContextRecord

23C4E9E7 | 8B88 B8000000      | MOV     ECX, DWORD PTR [EAX+B8]   | ; Access ExceptionInfo->ContextRecord->Eip

23C4E9ED | 3B0D EC1EC923      | CMP     ECX, DWORD PTR [23C91EEC] | ; Compare to some address (always zero on my machine. seems to be for an unused HWBP hook.)

23C4E9F3 | 75 12              | JNZ     23C4EA07                  | ; If not equal jump to NtQueryVirtualMemory check

23C4E9F5 | 8B0D E41EC923      | MOV     ECX, DWORD PTR [23C91EE4] | ; Get unknown address (always zero on my machine. seems to be for an unused HWBP hook.)

23C4E9FB | 8988 B8000000      | MOV     DWORD PTR [EAX+B8], ECX   | ; Move unknown address into EIP

23C4EA01 | 83C8 FF            | OR      EAX, FFFFFFFF             | ; Set return value to EXCEPTION_CONTINUE_EXECUTION

23C4EA04 | C2 0400            | RETN    4                         | ; Return

23C4EA07 | 3B0D D41EC923      | CMP     ECX, DWORD PTR [23C91ED4] | ; Check if EIP is NtQueryVirtualMemory

23C4EA0D | 75 12              | JNZ     23C4EA21                  | ; If not eual jump to NtGetContextThread check

23C4EA0F | 8B15 CC1EC923      | MOV     EDX, DWORD PTR [23C91ECC] | ; Get address of NtQueryVirtualMemory hook sub

23C4EA15 | 8990 B8000000      | MOV     DWORD PTR [EAX+B8], EDX   | ; Move address into EIP

23C4EA1B | 83C8 FF            | OR      EAX, FFFFFFFF             | ; Set return value to EXCEPTION_CONTINUE_EXECUTION

23C4EA1E | C2 0400            | RETN    4                         | ; Return

23C4EA21 | 3B0D C41EC923      | CMP     ECX, DWORD PTR [23C91EC4] | ; Check if EIP is NtGetContextThread

23C4EA27 | 75 12              | JNZ     23C4EA3B                  | ; If not equal jump to ‘return 0′

23C4EA29 | 8B0D BC1EC923      | MOV     ECX, DWORD PTR [23C91EBC] | ; Get address of NtGetContextThread hook sub

23C4EA2F | 8988 B8000000      | MOV     DWORD PTR [EAX+B8], ECX   | ; Move address into EIP

23C4EA35 | 83C8 FF            | OR      EAX, FFFFFFFF             | ; Set return value to EXCEPTION_CONTINUE_EXECUTION

23C4EA38 | C2 0400            | RETN    4                         | ; Return

23C4EA3B | 33C0               | XOR     EAX, EAX                  | ; Set return value to EXCEPTION_CONTINUE_SEARCH

23C4EA3D | C2 0400            | RETN    4                         | ; Return

; NtQueryVirtualMemory Hook

; NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress,

;  IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID Buffer,

;  IN ULONG Length, OUT PULONG ResultLength OPTIONAL );

23C2EA52 | 60                 | PUSHAD                            | ; Preserve registers (ESP += 0×20)

23C2EA53 | 8B4424 28          | MOV     EAX, DWORD PTR [ESP+28]   | ; Get BaseAddress (Param2)

23C2EA57 | 3B05 E01EC723      | CMP     EAX, DWORD PTR [23C71EE0] | ; Compare BaseAddress to ModuleStart

23C2EA5D | 72 10              | JB      23C2EA6F                  | ; Take jump if BaseAddress is out of module address range

23C2EA5F | 3B05 DC1EC723      | CMP     EAX, DWORD PTR [23C71EDC] | ; Compare BaseAddres to ModuleEnd

23C2EA65 | 77 08              | JA      23C2EA6F                  | ; Take jump if BaseAddress is out of module address range

23C2EA67 | C74424 28 00000000 | MOV     DWORD PTR [ESP+28], 0     | ; Move zero into BaseAddress

23C2EA6F | 61                 | POPAD                             | ; Restore registers

23C2EA70 | A1 D81EC723        | MOV     EAX, DWORD PTR [23C71ED8] | ; Run overwritten code

23C2EA75 | 8B15 D01EC723      | MOV     EDX, DWORD PTR [23C71ED0] | ; Get address of original func

23C2EA7B | FFE2               | JMP     NEAR EDX                  | ; Call original func

; NtGetContextThread Hook

; NTSTATUS NTAPI NtGetContextThread(IN HANDLE ThreadHandle, OUT PCONTEXT pContext );

23C2EAA2 | 60            | PUSHAD                            | ; Preserve registers

23C2EAA3 | 8B4424 28     | MOV     EAX, DWORD PTR [ESP+28]   | ; Get pContext (Param2)

23C2EAA7 | C700 07000100 | MOV     DWORD PTR [EAX], 10007    | ; Move 0×00010007 into pContext->ContextFlags to hide Debug Registers

23C2EAAD | 61            | POPAD                             | ; Restore registers

23C2EAAE | A1 C81EC723   | MOV     EAX, DWORD PTR [23C71EC8] | ; Run overwritten code

23C2EAB3 | 8B15 C01EC723 | MOV     EDX, DWORD PTR [23C71EC0] | ; Get address of original func

23C2EAB9 | FFE2          | JMP     NEAR EDX                  | ; Call original func