Tuesday, March 2, 2010

HadesMem

Just in-case anyone reading this doesn't follow either MMOwned or Game Deception's forums, I've released a memory hacking library, similar to 'BlackMagic' by Shynd, except aimed at C++.

Anyway, for the full description and details, check the release thread on GD here.

Thursday, February 18, 2010

I'm Still Alive

Yes, I'm still alive.

Just been busier than normal (on account of moving temporarily to another country). I'll have some stuff to post soon though.

Sunday, January 17, 2010

Beware when hooking window procedures returned by GetWindowLongPtr

I'm currently rewriting (read: improving) a bunch of stuff for Hades, and one of those things is the window management. Previously I was using a messy system in which I used window subclassing in order to 'hook' the window procedure of the display window(s) of the game.

The problem with this approach is that window subclassing is quite 'ugly', and it required me to hook several APIs, for which the implementation was also quite 'ugly'.

I solved this by moving to a detour-based system on the window procedure for the game's display window. Whilst there are some obvious problems with this approach too (which I will not get into now because they're complex and irrelevant) I believe the pros outweigh the cons.

One problem I ran into whilst implementing this new system however is the behaviour of GetWindowLongPtr when retrieving a window procedure, and how that behaviour changes depending on whether your module is ANSI or Unicode, and whether the target is ANSI or Unicode.

If the character sets don't match, GetWindowLongPtr does not return a true pointer, it returns a special internal handle which is then 'translated' by CallWindowProc. MSDN actually documents this behaviour but I accidentally skimmed over it and ended up reversing this behaviour myself. >_>

Long story short, if you want to detour the window procedure you need the 'real' pointer, so the obvious solution is to call both functions, detect which one is the handle, and throw it away (hence leaving you with the real pointer).

Here's the code to do that, thankfully the handle detection is very simple, I just wish I had read MSDN more closely the first time:

HookWindow-v20100117a

Saturday, December 19, 2009

AIO Bot Driver

AIO Bot uses a driver (or so they say) for some of their Warden protection.

I'm on an x64 machine and I really cbf setting up a kernel debugger on my XP x86 VM, so for now a static analysis will have to suffice.

They seem to perform a single kernelmode hook, it is on ZwQuerySystemInformation. They use it to hide processes and adjust some processor information.

The former they use because their bot uses a process for its GUI. What they don't seem to have realized is:

  • Warden does NOT scan processes.
  • They got the process names wrong in their hook, so even if Warden was looking for them, their hook wouldn't work. (Lol)
  • There are information codes other than SystemProcessInformation which return the exact same list, but with just a tiny bit of extra information. All of these codes must be handled otherwise their hook can by bypassed. (Good luck finding all of them, most are 100% undocumented and will require reversing of the Windows kernel.)
The latter I have no idea about. I was hoping someone with some more kernelmode experience could shed some light on that.

Overall their driver seems to be very poorly written, and is obviously the work of a complete amateur. I mean, shit, I have very little kernel-mode experience and even I could do a better job than this clusterfuck.

Here is the full dump of their hook sub, cleaned up, named, and documented by Kynox and I.

NTSTATUS __stdcall ZwQuerySystemInformation_Hook(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength)
{
  PVOID pCurrentEntry; // [email protected]
  PVOID pPreviousEntry; // [email protected]
  unsigned int TempIdleTime1; // [email protected]
  unsigned __int8 TempIdleTimeFlag1; // [email protected]
  unsigned int TempKernelTime1; // [email protected]
  unsigned __int8 TempKernelTimeFlag1; // [email protected]
  unsigned __int8 TempIdleTimeFlag2; // [email protected]
  unsigned __int8 TempKernelTimeFlag2; // [email protected]
  int IdleTimeTemp2; // [email protected]
  unsigned __int8 IdleTimeTemp3; // [email protected]
  NTSTATUS TrampResult; // [sp+1Ch] [bp+10h]@1

  pCurrentEntry = SystemInformation;
  // Call original API
  TrampResult = ZwQuerySystemInformationTramp(
                  SystemInformationClass,
                  SystemInformation,
                  SystemInformationLength,
                  ReturnLength);
  // Check if original API succeeded
  if ( TrampResult >= 0 )
  {
    // Check for SystemProcessInformation
    if ( SystemInformationClass == 5 )
    {
      pPreviousEntry = 0;
      if ( SystemInformation )
      {
        do
        {
          // Check pCurrent->ImageName.Buffer
          if ( *((_DWORD *)pCurrentEntry + 15) )
          {
            // Check for the presence of a couple of unknown processes.
            // This conditional will always fail because there are no processes used by these names!
            if ( !strncmp(*((const char **)pCurrentEntry + 15), (const char *)L"wow007", 12)
              || !strncmp(*((const char **)pCurrentEntry + 15), (const char *)L"wowmf", 10) )
            {
              // Do something with pCurrentEntry->UniqueProcessId
              sub_11151(*((_DWORD *)pCurrentEntry + 17));
              // Modify pCurrentEntry->IdleTime
              TempIdleTime1 = *((_DWORD *)pCurrentEntry + 10);
              TempIdleTimeFlag1 = TempIdleTime1 >= -(_DWORD)qword_120F8;
              LODWORD(qword_120F8) = TempIdleTime1 + qword_120F8;
              HIDWORD(qword_120F8) += *((_DWORD *)pCurrentEntry + 11) + TempIdleTimeFlag1;
              // Modify pCurrentEntry->KernelTime
              TempKernelTime1 = *((_DWORD *)pCurrentEntry + 12);
              TempKernelTimeFlag1 = TempKernelTime1 >= -(_DWORD)qword_120E8;
              LODWORD(qword_120E8) = TempKernelTime1 + qword_120E8;
              HIDWORD(qword_120E8) += *((_DWORD *)pCurrentEntry + 13) + TempKernelTimeFlag1;
              // Advance to next entry if there are still entries to process
              if ( pPreviousEntry )
              {
                if ( *(_DWORD *)pCurrentEntry )
                  *(_DWORD *)pPreviousEntry += *(_DWORD *)pCurrentEntry;
                else
                  *(_DWORD *)pPreviousEntry = 0;
              }
            }
          }
          else
          {
            // Modify pCurrentEntry->IdleTime and pCurrentEntry->KernelTime even on unnamed processes
            TempIdleTimeFlag2 = (_DWORD)qword_120F8 >= (unsigned int)-*((_DWORD *)pCurrentEntry + 10);
            *((_DWORD *)pCurrentEntry + 10) += qword_120F8;
            *((_DWORD *)pCurrentEntry + 11) += HIDWORD(qword_120F8) + TempIdleTimeFlag2;
            TempKernelTimeFlag2 = (_DWORD)qword_120E8 >= (unsigned int)-*((_DWORD *)pCurrentEntry + 12);
            *((_DWORD *)pCurrentEntry + 12) += qword_120E8;
            *((_DWORD *)pCurrentEntry + 13) += HIDWORD(qword_120E8) + TempKernelTimeFlag2;
            qword_120E8 = 0i64;
            qword_120F8 = 0i64;
          }
          // Advance to next entry if there are still entries to process
          pPreviousEntry = pCurrentEntry;
          if ( *(_DWORD *)pCurrentEntry )
            pCurrentEntry = (char *)pCurrentEntry + *(_DWORD *)pCurrentEntry;
          else
            pCurrentEntry = 0;
        }
        while ( pCurrentEntry );
      }
    }
    else
    {
      // SystemProcessorPerformanceInformation
      if ( SystemInformationClass == 8 )
      {
        // Increase IdleTime
        IdleTimeTemp2 = (unsigned __int64)(qword_120F8 + qword_120E8) >> 32;
        IdleTimeTemp3 = (_DWORD)qword_120F8 + (_DWORD)qword_120E8 >= (unsigned int)-*(_DWORD *)SystemInformation;
        *(_DWORD *)SystemInformation += qword_120F8 + qword_120E8;
        *((_DWORD *)SystemInformation + 1) += IdleTimeTemp2 + IdleTimeTemp3;
      }
    }
  }
  return TrampResult;
}



AIO Bot

The AIO Bot thread on MMOwned is about to be deleted, so I'm recording here what happened for posterities sake (and to expose it to anyone who does not read MMOwned).

Basically, AIO Bot is a new bot that was advertised on MMOwned. They made quite a few bold claims that Kynox and myself decided to verify. Turns out they were lying.

Kynox has also done a write up on his blog, available here.

This bot has zero Warden protection, and it is in fact WORSE than WoWMimic in its current form. Its pretty much a clone of WoWMimic v1.

Proof of their module being injected:


Proof of their hooks:
Microsoft (R) Windows Debugger Version 6.11.0001.404 X86
Copyright (c) Microsoft Corporation. All rights reserved.

*** wait with pending attach
Symbol search path is: srv*
Executable search path is:
ModLoad: 00400000 011cd000   C:\Users\Public\Games\World of Warcraft\WoW.exe
ModLoad: 77280000 77400000   C:\Windows\SysWOW64\ntdll.dll
ModLoad: 76d80000 76e80000   C:\Windows\syswow64\kernel32.dll
ModLoad: 75690000 756d6000   C:\Windows\syswow64\KERNELBASE.dll
ModLoad: 6b790000 6b858000   C:\Windows\system32\OPENGL32.dll
ModLoad: 75130000 751dc000   C:\Windows\syswow64\msvcrt.dll
ModLoad: 74f90000 75030000   C:\Windows\syswow64\ADVAPI32.dll
ModLoad: 769d0000 769e9000   C:\Windows\SysWOW64\sechost.dll
ModLoad: 76b90000 76c80000   C:\Windows\syswow64\RPCRT4.dll
ModLoad: 74df0000 74e50000   C:\Windows\syswow64\SspiCli.dll
ModLoad: 74de0000 74dec000   C:\Windows\syswow64\CRYPTBASE.dll
ModLoad: 75cd0000 75d60000   C:\Windows\syswow64\GDI32.dll
ModLoad: 754c0000 755c0000   C:\Windows\syswow64\USER32.dll
ModLoad: 75bd0000 75bda000   C:\Windows\syswow64\LPK.dll
ModLoad: 75b30000 75bcd000   C:\Windows\syswow64\USP10.dll
ModLoad: 6cfb0000 6cfd2000   C:\Windows\system32\GLU32.dll
ModLoad: 73830000 73917000   C:\Windows\system32\DDRAW.dll
ModLoad: 74150000 74156000   C:\Windows\system32\DCIMAN32.dll
ModLoad: 769f0000 76b8d000   C:\Windows\syswow64\SETUPAPI.dll
ModLoad: 75400000 75427000   C:\Windows\syswow64\CFGMGR32.dll
ModLoad: 75430000 754bf000   C:\Windows\syswow64\OLEAUT32.dll
ModLoad: 751e0000 7533c000   C:\Windows\syswow64\ole32.dll
ModLoad: 75d60000 75d72000   C:\Windows\syswow64\DEVOBJ.dll
ModLoad: 71d60000 71d73000   C:\Windows\system32\dwmapi.dll
ModLoad: 725d0000 725d9000   C:\Windows\system32\VERSION.dll
ModLoad: 75c70000 75cd0000   C:\Windows\syswow64\IMM32.dll
ModLoad: 755c0000 7568c000   C:\Windows\syswow64\MSCTF.dll
ModLoad: 76c80000 76d74000   C:\Windows\syswow64\WININET.dll
ModLoad: 750c0000 75117000   C:\Windows\syswow64\SHLWAPI.dll
ModLoad: 75120000 75123000   C:\Windows\syswow64\Normaliz.dll
ModLoad: 74e50000 74f85000   C:\Windows\syswow64\urlmon.dll
ModLoad: 75a10000 75b2c000   C:\Windows\syswow64\CRYPT32.dll
ModLoad: 77250000 7725c000   C:\Windows\syswow64\MSASN1.dll
ModLoad: 756e0000 758d9000   C:\Windows\syswow64\iertutil.dll
ModLoad: 75940000 75975000   C:\Windows\syswow64\WS2_32.dll
ModLoad: 75980000 75986000   C:\Windows\syswow64\NSI.dll
ModLoad: 6d100000 6d130000   C:\Windows\system32\DINPUT8.dll
ModLoad: 75d80000 769c9000   C:\Windows\syswow64\SHELL32.dll
ModLoad: 10000000 10069000   C:\Users\Public\Games\World of Warcraft\DivxDecoder.dll
ModLoad: 72ed0000 72f02000   C:\Windows\system32\WINMM.dll
ModLoad: 74900000 74914000   C:\Windows\system32\MSACM32.dll
ModLoad: 73c90000 73c99000   C:\Windows\system32\HID.DLL
ModLoad: 720b0000 720fb000   C:\Windows\system32\apphelp.dll
ModLoad: 6d080000 6d0fb000   C:\Windows\AppPatch\AcSpecfc.DLL
ModLoad: 75030000 750b4000   C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7600.16385_none_ebf82fc36c758ad5\COMCTL32.dll
ModLoad: 73c00000 73c79000   C:\Windows\system32\mscms.dll
ModLoad: 72f10000 72f27000   C:\Windows\system32\USERENV.dll
ModLoad: 74b10000 74b1b000   C:\Windows\system32\profapi.dll
ModLoad: 72410000 72422000   C:\Windows\system32\MPR.dll
ModLoad: 75990000 75a0b000   C:\Windows\syswow64\COMDLG32.dll
ModLoad: 59f60000 5a1a0000   C:\Windows\system32\msi.dll
ModLoad: 72020000 720ac000   C:\Windows\AppPatch\AcLayers.DLL
ModLoad: 72530000 72581000   C:\Windows\system32\WINSPOOL.DRV
ModLoad: 72d90000 72db1000   C:\Windows\system32\ntmarta.dll
ModLoad: 758f0000 75935000   C:\Windows\syswow64\WLDAP32.dll
ModLoad: 71fa0000 72020000   C:\Windows\system32\uxtheme.dll
ModLoad: 655f0000 657b3000   C:\Windows\system32\d3d9.dll
ModLoad: 73be0000 73be6000   C:\Windows\system32\d3d8thk.dll
ModLoad: 6f0d0000 6f9c5000   C:\Windows\system32\nvd3dum.dll
ModLoad: 002f0000 002fc000   C:\Program Files (x86)\Ad Muncher\AM31318.dll
ModLoad: 041f0000 0432b000   C:\Windows\system32\nvapi.dll
ModLoad: 01260000 01288000   C:\Program Files (x86)\NVIDIA Corporation\3D Vision\nvStereoApiI.dll
ModLoad: 03100000 03153000   C:\Program Files (x86)\NVIDIA Corporation\3D Vision\nvSCPAPI.dll
ModLoad: 75340000 7536d000   C:\Windows\syswow64\WINTRUST.dll
ModLoad: 74840000 74865000   C:\Windows\system32\powrprof.dll
ModLoad: 75be0000 75c63000   C:\Windows\syswow64\CLBCatQ.DLL
ModLoad: 74b80000 74bb9000   C:\Windows\System32\MMDevApi.dll
ModLoad: 74990000 74a85000   C:\Windows\System32\PROPSYS.dll
ModLoad: 74930000 74966000   C:\Windows\system32\AUDIOSES.DLL
ModLoad: 74b50000 74b80000   C:\Windows\system32\wdmaud.drv
ModLoad: 74980000 74984000   C:\Windows\system32\ksuser.dll
ModLoad: 74970000 74977000   C:\Windows\system32\AVRT.dll
ModLoad: 74920000 74928000   C:\Windows\system32\msacm32.drv
ModLoad: 748f0000 748f7000   C:\Windows\system32\midimap.dll
ModLoad: 71e00000 71f9e000   C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7600.16385_none_421189da2b7fabfc\comctl32.dll
ModLoad: 724a0000 724e4000   C:\Windows\system32\dnsapi.DLL
ModLoad: 72500000 7251c000   C:\Windows\system32\iphlpapi.DLL
ModLoad: 724f0000 724f7000   C:\Windows\system32\WINNSI.DLL
ModLoad: 73d70000 73d95000   C:\Windows\system32\peerdist.dll
ModLoad: 72cf0000 72d0b000   C:\Windows\system32\AUTHZ.dll
ModLoad: 0e780000 0e7c2000   C:\Windows\system32\nvLsp.dll
ModLoad: 758e0000 758e5000   C:\Windows\syswow64\PSAPI.DLL
ModLoad: 72600000 7263c000   C:\Windows\system32\mswsock.dll
ModLoad: 725e0000 725e5000   C:\Windows\System32\wshtcpip.dll
ModLoad: 74510000 74562000   C:\Windows\system32\RASAPI32.dll
ModLoad: 744f0000 74505000   C:\Windows\system32\rasman.dll
ModLoad: 744e0000 744ed000   C:\Windows\system32\rtutils.dll
ModLoad: 72790000 72796000   C:\Windows\system32\sensapi.dll
ModLoad: 71cd0000 71ce0000   C:\Windows\system32\NLAapi.dll
ModLoad: 71c50000 71c56000   C:\Windows\system32\rasadhlp.dll
ModLoad: 725f0000 725f6000   C:\Windows\System32\wship6.dll
ModLoad: 71c60000 71c84000   C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live\WLIDNSP.DLL
ModLoad: 71bf0000 71c28000   C:\Windows\System32\fwpuclnt.dll
eax=7eef8000 ebx=00000000 ecx=00000000 edx=7731f50a esi=00000000 edi=00000000
eip=7729000c esp=1592ff5c ebp=1592ff88 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!DbgBreakPoint:
7729000c cc              int     3
0:034> .reload
Reloading current modules
................................................................
.............................
0:034> u kernel32!LoadLibraryA
kernel32!LoadLibraryA:
76d94bc6 e9552d3f9b      jmp     12187920
76d94bcb 837d0800        cmp     dword ptr [ebp+8],0
76d94bcf 53              push    ebx
76d94bd0 56              push    esi
76d94bd1 57              push    edi
76d94bd2 7417            je      kernel32!LoadLibraryA+0xae (76d94beb)
76d94bd4 68004cd976      push    offset kernel32!`string' (76d94c00)
76d94bd9 ff7508          push    dword ptr [ebp+8]
0:034> u user32!GetCursorPos
USER32!GetCursorPos:
754e0e0d e98e69ca9c      jmp     121877a0
754e0e12 6a69            push    69h
754e0e14 6a01            push    1
754e0e16 ff7508          push    dword ptr [ebp+8]
754e0e19 e8a65cffff      call    USER32!NtUserCallTwoParam (754d6ac4)
754e0e1e 5d              pop     ebp
754e0e1f c20400          ret     4
754e0e22 33c0            xor     eax,eax
0:034> u user32!SetPhysicalCursorPos
USER32!SetPhysicalCursorPos:
75519f13 e958d9c69c      jmp     12187870
75519f18 6a75            push    75h
75519f1a ff750c          push    dword ptr [ebp+0Ch]
75519f1d ff7508          push    dword ptr [ebp+8]
75519f20 e89fcbfbff      call    USER32!NtUserCallTwoParam (754d6ac4)
75519f25 5d              pop     ebp
75519f26 c20800          ret     8
75519f29 90              nop

Quote from Kynox:
"*Edit*: Why do you have a gameguard bypass in a WoW hack? This whole thing seems to be some giant troll.

[CODE]

The above returns kernel32's imagebase, instead of loading "npggNT.des" which is a GameGuard DLL."

Code accompanying Kynox's post:
.text:10007920 sub_10007920    proc near               ; DATA XREF: DllMain(x,x,x)+382o
.text:10007920
.text:10007920 lpLibFileName   = dword ptr  4
.text:10007920
.text:10007920                 push    esi
.text:10007921                 mov     esi, [esp+4+lpLibFileName]
.text:10007925                 push    offset aNpggnt_des ; "npggNT.des"
.text:1000792A                 push    esi             ; char *
.text:1000792B                 call    _strstr
.text:10007930                 add     esp, 8
.text:10007933                 test    eax, eax
.text:10007935                 jz      short loc_10007946
.text:10007937                 pop     esi
.text:10007938                 mov     [esp+lpLibFileName], offset aKernel32_dll_0 ; "Kernel32.dll"
.text:10007940                 jmp     ds:GetModuleHandleA
.text:10007946 ; ---------------------------------------------------------------------------
.text:10007946
.text:10007946 loc_10007946:                           ; CODE XREF: sub_10007920+15j
.text:10007946                 push    0               ; dwFlags
.text:10007948                 push    0               ; hFile
.text:1000794A                 push    esi             ; lpLibFileName
.text:1000794B                 call    ds:LoadLibraryExA
.text:10007951                 pop     esi
.text:10007952                 retn    4
.text:10007952 sub_10007920    endp

Wednesday, December 9, 2009

LuaNinja for WoW v3.3.0

I've updated LuaNinja for WoW v3.3.0. Download it here.

Have fun you dirty cheaters.

Protector

Project:
Protector

Description:
Allows arbitrary processes to be set as critical or non-critical. This can be used to unprotect malicious software abusing the feature, or to protect security software you use in order to add an extra layer of defence in depth.

Features:

  • Native IA32 support.
  • Native AMD64 support.
  • GUI available.
Compatibility:
Should work on all Windows versions after and including Windows XP SP2. Support for anything else is unofficial.

In order to run the GUI you may need to install the .NET Framework 4.0 Beta 2. You may download it here (or, if you want the complete version, not just the minimal build required to run client apps, you may get it here).

Notes:
Binaries only for this release. Source may come at a later date.

Suggestions and constructive criticisms are appreciated as always.

This may not appear elsewhere without permission, but may be linked to.

Releases:
v20091209a - Initial release. No known issues.