Archive

Archive for May, 2009

WoWMimic PvPAdvance v14

May 29th, 2009

Bored, so I took a look at the new version of WoWMimic PvPAdvance to see what they changed. Unfortunately v13 wouldn’t run on my PC,  so I don’t have anything to base it off, but when the next version comes out at least I will. I’m not surprised at all that there have been bans for this tool, its anti-detection is even worse than WOWMimic itselfs.

What they’re currently doing:

  1. Unlinking the module.

No. Seriously. That seems to be it.

They’re not hooking VirtualQuery (or any of its lower-level code paths), and they’re not even nulling out their PE header. This means that a Warden scan that is CURRENTLY IMPLEMENTED can be used to detect their module, all the Warden dev needs to do is add a new hash.

My guess is that with the bans from the previous version they made minor changes to their code, which changed the module hash at the point Warden was scanning, noticed they weren’t getting bans anymore, and assumed they fixed the problem. That, or they’re too lazy to fix it properly. Either way they’re idiots.

Epic fail. Quite disappointing really, that only took a minute or two to check and now I’m bored again.

WardenMimic v20090528a

May 28th, 2009

New version of WardenMimic for v47 of WoWMimic.

N/A DL.

If you havn’t already you may want to check out my post detailing the changes to WoWMimic in v47 here.

Please let me know if you experience a false positive or false negative. For version 47 ONLY, do not report flase negatives for any other versions.

WoWMimic v47 Changes

May 27th, 2009

Many of you will know by now that WoWMimic v47 is out. A few interesting changes, nothing really substantial though.

  1. GetCursorPos and SetCursorPos are now also hooked using VEH.
  2. ZwQueryVirtualMemory is now hooked at the return statement so values are modified AFTER the function is called. They have fixed one hole, but introduced another. Still hooked with VEH.
  3. ZeGetContextThread hook is still present but not longer activated. They have also updated their hook body, fixing one hole, but again, introducing another (see if you can spot it).
  4. They have implemented some VERY lame ‘obfuscation’ attempts. Really quite a poor job, 5 minutes tops to figure out the mess, or 30 or so seconds if you know what you’re looking at.

All in all quite disappointing. They broke the previous version of WardenMimic but only because they changed the offset at which they were hooking, and I was being nice and lowering the false positive rate by putting in lots of checks to detect only that exact build. Anyway, new WardenMimic incoming soon (when I don’t feel lazy).

Update:

Thanks to Harko for pointing out that GetCursorPos and SetCursorPos are still hooked with JMP hooks. It seems they implemented support for it in their VEH but didn’t actually hook it using VEH for some reason. Much like their unused changes to NtGetContextThread. Kinda retarded really….

Full code:

PrivatePaste Copy

; MimicVectoredHandler

169B379E | 55            | PUSH    EBP                         | ; Standard stack frame setup

169B379F | 8BEC          | MOV     EBP, ESP                    | ; Standard stack frame setup

169B37A1 | 81C4 00FFFFFF | ADD     ESP, -100                   | ; Sub ESP 100. Room for local variables.

169B37A7 | 60            | PUSHAD                              | ; Preserve all registers

169B37A8 | E8 00000000   | CALL    169B37AD                    | ; Obfuscation. ‘Calls’ next line and pushes the address of that line onto stack.

169B37AD | 5B            | POP     EBX                         | ; Pop address (of current line) back off and into EBX

169B37AE | 81EB 75164000 | SUB     EBX, 401675                 | ; Subtract 401675 from EBX (169B37AD) (Final: 165B2138)

169B37B4 | 8B75 08       | MOV     ESI, DWORD PTR [EBP+8]      | ; Get pExceptionInfo

169B37B7 | 8B7E 04       | MOV     EDI, DWORD PTR [ESI+4]      | ; Get pExceptionInfo->pContext

169B37BA | 8B36          | MOV     ESI, DWORD PTR [ESI]        | ; Get pExceptionInfo->pExceptionRecord

169B37BC | 8B87 B8000000 | MOV     EAX, DWORD PTR [EDI+B8]     | ; Get EIP

169B37C2 | 3B83 CD104000 | CMP     EAX, DWORD PTR [EBX+4010CD] | ; Compare EIP to address of GetCursorPos.

169B37C8 | 75 0E         | JNZ     169B37D8                    | ; If not equal go to ContinueSearchRet

169B37CA | 8D83 F8164000 | LEA     EAX, DWORD PTR [EBX+4016F8] | ; Get address of GetCursorPos_Hook

169B37D0 | 8987 B8000000 | MOV     DWORD PTR [EDI+B8], EAX     | ; Move address into EIP

169B37D6 | EB 4C         | JMP     169B3824                    | ; Go to ContinueExecRet

169B37D8 | 3B83 D1104000 | CMP     EAX, DWORD PTR [EBX+4010D1] | ; Compare EIP to address of SetCursorPos

169B37DE | 75 0E         | JNZ     169B37EE                    | ; If not equal go to ContinueSearchRet

169B37E0 | 8D83 2D174000 | LEA     EAX, DWORD PTR [EBX+40172D] | ; Get address of SetCursorPos_Hook

169B37E6 | 8987 B8000000 | MOV     DWORD PTR [EDI+B8], EAX     | ; Move address into EIP

169B37EC | EB 36         | JMP     169B3824                    | ; Go to ContinueExecRet

169B37EE | 3B83 84134000 | CMP     EAX, DWORD PTR [EBX+401384] | ; Compare EIP to address of ZwQueryVirtualMemory_Retn

169B37F4 | 75 0E         | JNZ     169B3804                    | ; If not equal go to ContinueSearchRet

169B37F6 | 8D83 50174000 | LEA     EAX, DWORD PTR [EBX+401750] | ; Get address of ZwQueryVirtualMemory_Hook

169B37FC | 8987 B8000000 | MOV     DWORD PTR [EDI+B8], EAX     | ; Move address into EIP

169B3802 | EB 20         | JMP     169B3824                    | ; Go to ContinueExecRet

169B3804 | 3B83 8C134000 | CMP     EAX, DWORD PTR [EBX+40138C] | ; Compare EIP to address of ZwGetContextThread_Hook. Currently not used/enabled.

169B380A | 75 0E         | JNZ     169B381A                    | ; If not equal go to ContinueSearchRet

169B380C | 8D83 88174000 | LEA     EAX, DWORD PTR [EBX+401788] | ; Get address of ZwGetContextThread_Hook.

169B3812 | 8987 B8000000 | MOV     DWORD PTR [EDI+B8], EAX     | ; Move address into EIP

169B3818 | EB 0A         | JMP     169B3824                    | ; Go to ContinueExecRet

169B381A | 61            | POPAD                               | ; Restore registers

169B381B | B8 00000000   | MOV     EAX, 0                      | ; Move EXCEPTION_CONTINUE_SEARCH into return value

169B3820 | C9            | LEAVE                               | ; Standard function prologue

169B3821 | C2 0400       | RETN    4                           | ; Return

169B3824 | 61            | POPAD                               | ; Restore registers

169B3825 | B8 FFFFFFFF   | MOV     EAX, -1                     | ; Move EXCEPTION_CONTINUE_EXECUTION into return value

169B382A | C9            | LEAVE                               | ; Standard function prolugue

169B382B | C2 0400       | RETN    4                           | ; Return

; GetCursorPos_Hook

169B3830 | E8 00000000      | CALL    169B3835                    | ; Obfuscation. ‘Calls’ next line and pushes the address of that line onto stack.

169B3835 | 5A               | POP     EDX                         | ; Pop address (of current line) back off and into EDX

169B3836 | 81EA FD164000    | SUB     EDX, 4016FD                 | ; Subtract 4016FD from EDX (169B3835) (Final: 165B2138)

169B383C | 83BA 09104000 01 | CMP     DWORD PTR [EDX+401009], 1   | ; Compare some internal flag to 1

169B3843 | 75 15            | JNZ     169B385A                    | ;

169B3845 | 8B4C24 04        | MOV     ECX, DWORD PTR [ESP+4]      | ; Get lpPoint

169B3849 | 8B82 0D104000    | MOV     EAX, DWORD PTR [EDX+40100D] | ; Get custom mouse x

169B384F | 8901             | MOV     DWORD PTR [ECX], EAX        | ; Set lpPoint->x to custom mouse x

169B3851 | 8B82 11104000    | MOV     EAX, DWORD PTR [EDX+401011] | ; Get custom mouse y

169B3857 | 8941 04          | MOV     DWORD PTR [ECX+4], EAX      | ; Set lpPoint->y to custom mouse y

169B385A | 8B82 CD104000    | MOV     EAX, DWORD PTR [EDX+4010CD] | ; Get address of GetCursorPos

169B3860 | 83C0 02          | ADD     EAX, 2                      | ; Jump over invalid instruction

169B3863 | FFE0             | JMP     NEAR EAX                    | ; Jump to GetCursorPos (+2)

; SetCursorPos_Hook

169B3865 | E8 00000000      | CALL    169B386A                    | ; Obfuscation. ‘Calls’ next line and pushes the address of that line onto stack.

169B386A | 5A               | POP     EDX                         | ; Pop address (of current line) back off and into EDX

169B386B | 81EA 32174000    | SUB     EDX, 401732                 | ; Subtract 401732 from EDX (169B386A) (Final: 165B2138)

169B3871 | 83BA 09104000 01 | CMP     DWORD PTR [EDX+401009], 1   | ; Compare some internal flag to 1

169B3878 | 75 03            | JNZ     169B387D                    | ; Jump if not equal to RetnCallOrig

169B387A | C2 0800          | RETN    8                           | ; Return without calling original

169B387D | 8B82 D1104000    | MOV     EAX, DWORD PTR [EDX+4010D1] | ; Get address of SetCursorPos

169B3883 | 83C0 02          | ADD     EAX, 2                      | ; Jump over invalid instruction

169B3886 | FFE0             | JMP     NEAR EAX                    | ; Jump to SetCursorPos (+2)

; ZwQueryVirtualMemory_Hook

169B3888 | E8 00000000      | CALL    169B388D                    | ; Obfuscation. ‘Calls’ next line and pushes the address of that line onto stack.

169B388D | 5A               | POP     EDX                         | ; Pop address (of current line) back off and into EDX

169B388E | 81EA 55174000    | SUB     EDX, 401755                 | ; Subtract 401755 from EDX (169B388D) (Final: 165B2138)

169B3894 | 50               | PUSH    EAX                         | ; Preserve EAX

169B3895 | 8B4424 14        | MOV     EAX, DWORD PTR [ESP+14]     | ; Get pMemoryBasicInformation

169B3899 | 8B48 04          | MOV     ECX, DWORD PTR [EAX+4]      | ; Get pMemoryBasicInformation->Allocationbase

169B389C | 3B8A 21104000    | CMP     ECX, DWORD PTR [EDX+401021] | ; Compare to MimicModuleBase

169B38A2 | 75 18            | JNZ     169B38BC                    | ; If not equal jump to LocRetn

169B38A4 | C700 00000000    | MOV     DWORD PTR [EAX], 0          | ; Zero out pMemoryBasicInformation->BaseAddress

169B38AA | C740 04 00000000 | MOV     DWORD PTR [EAX+4], 0        | ; Zero out pMemoryBasicInformation->AllocationBase

169B38B1 | C740 10 00000100 | MOV     DWORD PTR [EAX+10], 10000   | ; Set pMemoryBasicInformation->State to MEM_FREE

169B38B8 | 58               | POP     EAX                         | ; Restore EAX

169B38B9 | C2 1800          | RETN    18                          | ; Return

169B38BC | 58               | POP     EAX                         | ; Restore EAX

169B38BD | C2 1800          | RETN    18                          | ; Return

; ZwGetContextThread_Hook

169B38C0 | 8B4C24 08        | MOV     ECX, DWORD PTR [ESP+8] | ; Get pContext

169B38C4 | C741 04 00000000 | MOV     DWORD PTR [ECX+4], 0   | ; Zero out DR0

169B38CB | C741 08 00000000 | MOV     DWORD PTR [ECX+8], 0   | ; Zero out DR1

169B38D2 | C741 0C 00000000 | MOV     DWORD PTR [ECX+C], 0   | ; Zero out DR2

169B38D9 | C741 10 00000000 | MOV     DWORD PTR [ECX+10], 0  | ; Zero out DR3

169B38E0 | C2 0800          | RETN    8                      | ; Return

Preventing Recursion in API Hooks

May 26th, 2009

I’m sure many have ran across the same issue I did recently, and that is that when doing API hooking of low-level functions (e.g. the NT API) code that is inserted into the hook function (e.g. logging code) will end up calling the same function and cause a stack overflow.

Greyman had a good idea which I’ve used, and put together an example for. Credits to Greyman for the idea.

Basically, you use TLS to hold a flag so that the offending code (the code causing the infinite recursion)  is only executed once per call. The following code should work under all major Windows compilers, but is using a nonstandard compiler extension so may not work cross-platform (which is not a concern for a low level project anyway). Using LdrGetProcedureAddress as an example because using any of the standard output functions will cause the recursive call (printf, std::cout, etc):

NTSTATUS NTAPI APIHook::LdrGetProcedureAddress_Hook( IN HMODULE ModuleHandle,

IN PANSI_STRING FunctionName OPTIONAL, IN WORD Ordinal OPTIONAL,

OUT PVOID *FunctionAddress )

{

// Use TLS to prevent recursive function calls when logging

static __declspec(thread) bool Logging = false;

// Get the true address of the function

NTSTATUS RetVal =

((tLdrGetProcedureAddress)(PROC)(sm_LdrGetProcedureAddress))

(ModuleHandle,FunctionName,Ordinal,FunctionAddress);

// Don’t call function recursively when logging

if (Logging)

return RetVal;

// Start logging wrapper

Logging = true;

// Function pointer

PVOID pFunc = (FunctionAddress ? *FunctionAddress : 0);

// Log API call

if (Config::Get()->ShouldLogFunctions())

{

try

{

// Guard against structured exceptions

SehGuard Guard;

// Create string from c-style string

// Note: Will thrown an access violation if c-style string isn’t a

// valid pointer

std::string FunctionNameTemp(FunctionName->Buffer);

// If we get to this point the string is valid so log it.

DBGPRNT(boost::str(boost::format(”LdrGetProcedureAddress: Module”

” = %p, Name = %s. Return = %p.\n”) %ModuleHandle

%FunctionNameTemp %pFunc).c_str());

}

catch (const SehException& /*e*/)

{

// If we get here the string is invalid so we assume it’s an

// ordinal and log it as such

DBGPRNT(boost::str(boost::format(”LdrGetProcedureAddress: Module”

” = %p,  Ordinal = %u. Return = %p.\n”) %ModuleHandle %Ordinal

%pFunc).c_str());

}

}

// End logging wrapper

Logging = false;

// Check we got a valid pointer back

if (!FunctionAddress)

return RetVal;

// Dereference pointer and get actual function pointer

FARPROC pfn = (FARPROC)(*FunctionAddress);

// Is it one of the functions that we want hooked?

APIHook* p = sm_pHead;

for (; (pfn != NULL) && (p != NULL); p = p->m_pNext)

{

if (pfn == p->m_pOrig)

{

// The address to return matches an address we want to hook

// Return the hook function address instead

pfn = p->m_pHook;

break;

}

}

return RetVal;

}

In the above code DBGPRNT is just a macro used to call ‘printf’ if a certain compiler flag is enabled, or omit the code entirely if the flag is disabled. Implemented that way for performance reasons. Irrelevant details aside though, its easy to see how the implementation and how simple it is to use. Obviously thread-safe due to the variable being thread-local so it shouldn’t interfere with anything, I’ve yet to have any problems with it. Tested on both IA-32 and AMD64.

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

Presenting: WardenMimic

May 21st, 2009

Releasing the initial version of my latest project, dubbed WardenMimic. Its purpose is to basically ‘mimic’ Warden and try and detect WoWMimic. It will be fully in-process so it works within the constraints of Warden itself. Releasing it as a binary so the devs have to work for it this time, they’ve had enough charity handouts.

Simply run the loader, point it to WoW, and the module will spawn a console and let you know whether its detected WoWMimic or not. Go back to the loader, hit enter again, and the module will be unloaded for your convenience.

I will continually update this for any new WoWMimic builds until I get bored or they really pick up their game and make it too much trouble for me to bother (keeping in mind I’m a very lazy person).

No DL

P.S. Has recieved limited testing. If it crashes please post your system specs (os, architecture, etc etc) plus a crash dump.

Credits:

Huge credits to both Harko and Kynox for their help/input/etc.

Hardcoded IPC Name Still There

May 21st, 2009

It seems that whilst the WoWMimic folks have ‘kinda’ listened to Kynox, Harko, Myself, etc. they still have selective hearing. Although they’ve started hooking VirtualQueryEx (they still haven’t worked out to hook the NT API it seems) the hardcoded IPC name seems to still be there.

That means that this still works: In-process WoWMimic Detection

On a nicer note though it seems that they have finally realized that they are not immune to Warden. Granted, they learned this the hard way (it seems that either WoW or Warden is detecting it in some shape or form), but at least it finally happened.

Still no WoWMimic build

May 17th, 2009

Come on WoWMimic devs, push a new build! I’m getting bored here.

More WoWMimic Detection Code

May 15th, 2009

Well, we have found yet another hole in WoWMimic that is criminally easy to abuse. Credits to Kynox and Harko for working on this with me.

This code abuses the fact that the WoWMimic idiots are only hooking VirtualQuery, and none of the lower control paths, so we can easily call VirtualQueryEx to verify that the results we get back are untainted. If we find something that has been modified we know we have a hidden page. Mimic only hides the base page, not the entire module, so at the point I’ve marked “Warden function to do hashing goes here”, you simply need to do standard hashing of  data in the page, something which Warden already does (the reason for the hook in the first place).

void FindHiddenPages()

{

std::cout << “Start!” << std::endl << std::hex;

PVOID p1 = 0, p2 = 0;

MEMORY_BASIC_INFORMATION MyMbi = { 0 };

typedef std::vector< std::pair<PVOID,PVOID> > tAddresses;

tAddresses AddressList;

tAddresses Hidden;

while (VirtualQuery(p1,&MyMbi,sizeof(MyMbi)) == sizeof(MyMbi))

{

if (MyMbi.State == MEM_COMMIT && MyMbi.AllocationBase != p2 &&

MyMbi.AllocationBase == MyMbi.BaseAddress)

{

AddressList.push_back(std::make_pair(MyMbi.AllocationBase,MyMbi.BaseAddress) );

}

p2 = MyMbi.AllocationBase;

p1 = reinterpret_cast<PVOID>(reinterpret_cast<DWORD_PTR>(p1) + MyMbi.RegionSize);

}

p1 = p2 = 0;

while (VirtualQueryEx(GetCurrentProcess(),p1,&MyMbi,sizeof(MyMbi)) == sizeof(MyMbi))

{

if (MyMbi.State == MEM_COMMIT && MyMbi.AllocationBase != p2 &&

MyMbi.AllocationBase == MyMbi.BaseAddress)

{

std::pair<PVOID,PVOID> MyAddresses(MyMbi.AllocationBase,MyMbi.BaseAddress);

const tAddresses::const_iterator iCurrent(std::find(AddressList.begin(),AddressList.end(), MyAddresses));

if (iCurrent == AddressList.end())

Hidden.push_back(MyAddresses);

}

p2 = MyMbi.AllocationBase;

p1 = reinterpret_cast<PVOID>(reinterpret_cast<DWORD_PTR>(p1) + MyMbi.RegionSize);

}

for (tAddresses::const_iterator i = Hidden.begin(); i != Hidden.end(); ++i)

{

std::cout << “Hidden page! Allocation Base: ” << i->first

<< “. Base Address: ” << i->second << “.” << std::endl;

// Warden function to do hashing goes here

}

std::cout << “End!” << std::endl << std::dec;

}

On its own, even without hashing, you still have ground for a kick at the very least because hiding memory pages is something that only malicious software normally does. Once you add hashing though you have a guarantee of no false positives so you can go ahead and ban for it.

Yet again it seems that WoWMimic just doesn’t stand up when it comes to the detection test. Don’t trust their website, this thing is trivial to detect.

WoWMimic API Hook List

May 15th, 2009

Here is a list of functions WoWMimic hooks.

Version .44

VirtualQuery

GetCursorPos

SetCursorPos

FindWindowW

FindWindowA

FindWindowExW

FindWindowExA

EnumWindows

EnumChildWindows

Version .43
VirtualQuery
GetCursorPos
SetCursorPos
Its obvious that I’m the cause of the .44 update, but what they don’t seem to realize is twofold:
  1. Warden can follow their hooked code path and hash their function. Obviously its going to have a unique signature. If you find the WoWMimic hook then just ban for it.
  2. Warden can also bypass all their hooks entirely by just doing manual syscall code for each major OS version. That is a very easy thing to do, and no amount of usermode hooking will be able to stop it. (Kernelmode is the only option)

Not only that, but they’re missing half the funcitons they need to hook. All warden needs to do is call VirtualQueryEx and they’ve bypassed the hook. It astounds me how stupid the WoWMimic team is. Lastly, afaik it’s possible to manually walk the VAD tree (I have never attempted it but have seen code that can do it). No amount of API hooking can protect you from that either.

To the WoWMimic devs:
Tip: Unless you decide to elevate to the kernel (which still won’t protect you from stack traces) or actively attack warden (which is a LOT of work and still impossible to get 100% right, even if you’re an expert), you’re screwed. It’s that simple. At the very least, if you’re going to do usermode protection, at least do a decent job, your current half-assed attempt is just plain sad.