Results 1 to 12 of 12

Thread: Small modification to v2 Stealth Sniffer (XOR before key send)

Threaded View

  1. #1
    Registered User
    Join Date
    Dec 2001
    Posts
    144

    Small modification to v2 Stealth Sniffer (XOR before key send)

    I've been reading some of the other threads, and people are expressing interest in obscuring the key a bit before it is sent.

    Lostinspace included some new SEQ-side code to allow for SEQ to "de XOR" a key that has been obfuscated by XORing prior to transmission.

    I've made a small modification to Maggotboy's 2.05 sniffer code to allow the addition of another parameter at the end of the command line. This additional parameter takes the form of an 8-byte hexadecimal value (0x1234567812345678). The modifications allow the sniffer to XOR the key by this value prior to sending. To send the key straight away, enter 0 for the last value.

    Additional conversations have included the consideration of offsetting the transmitted key somewhere in a larger UDP packet. Sorry -- I didn't get to this one yet!

    I'm posting this code separately. If Maggotboy wants to include it as part of his main thread, that's is fine. If he chooses not to, I won't be insulted. Either way, this code will do the trick for you.

    NOTE: This code does NOT work yet in LCC (of course). This has been tested under VS.Net.

    code starts:
    =============================
    /* eqsniffer2.cpp written by Maggotboy

    Revision 2.06 (from MisterSpock)
    Adds the ability to pass an additional parameter (64 bit, 8 byte) value.
    The sniffer will XOR the key by this value prior to transmitting. If you have made
    LostInSpace's changes to SEQ, you can specify in EQ the same XOR value, and get the
    correct key. To send the key unencrypted, enter 0 for the final parameter.

    Example to XOR the key by 0x1234567812345678:
    rundll32 eqsniffer2.dll,InstallHook 192.168.1.1 12345 eqgame.exe 0x0078AAD0 0x1234567812345678

    or to not XOR the key at all:
    rundll32 eqsniffer2.dll,InstallHook 192.168.1.1 12345 eqgame.exe 0x0078AAD0 0x00



    Revision 2.05

    HOW IT WORKS

    This DLL takes advantage of the built-in hooking mechanism of Windows 9x/NT. The DLL hooks into
    keyboard processing messages on all processes in the system using a global keyboard hook. This
    allows the DLL to sit in the address space of all processes that handle keyboard events.

    When the DLL detects that it has latched onto EQGAME.EXE, it does several things ... First, it
    de-hooks itself from the global keyboard hook chain. Then it hooks into the main message pump
    of EQ's main thread. As messages get processed by the game through the normal mechanisms, the
    DLL will be checking the game's memory and sending the encryption key to SEQ when it changes.

    The ways of detecting this program's presence are incredibly complex, and by changing the program
    around before you compile it, you pretty-much eliminate most feasible detection methods.

    IMPORTANT NOTES ON V2
    V2 is more uber stealthy than V1. It is identical in form and function to V1 up to the point
    where it gets loaded into the EQ game's address space. V2 allocates some executable memory,
    injects some code into it, and then DROPS OUT! The DLL disappears, and EQ will never even know
    it was there to begin with.

    COMPILING THE PROGRAM
    Before you compile this program, you need to take several steps in creating a project for it...

    VS.NET Users
    Create a new WIN32 Project
    Project Options, choose DLL Project
    Create the project and copy eqsniffer.cpp and eqsniffer.def into the new folder for it.
    Remove stdafx.h, stdafx.cpp and ReadMe.txt from the project.
    Right-click the project and add the eqsniffer.cpp and eqsniffer.def files to it.
    Right-click the project, and go into Properties
    Change the Configuration to "All Configurations"
    Expand the C/C++ options
    Under "General"
    - Debug Information Format: Disabled
    - Detect 64-bit portability issues: No
    Under "Code Generation"
    - Enable String Pooling: Yes
    - Enable Minimal Rebuild: No
    - Enable C++ Exceptions: No
    - Runtime Library: Single Threaded
    - Buffer Security Check: No
    - Enable Function-Level Linking: Yes
    Under "Precompiled Headers"
    - Create/Use Precompiled Header: Not Using Precompiled Headers
    Expand the Linker options
    Under "Input"[/B]
    - Module Definition File: eqsniffer.def
    Under "Debug"
    - Generate Debug Info: No

    MS VC++ 6.0 Users
    Create a WIN32 DLL Project
    For the options, select Empty Project
    Copy the eqsniffer.cpp and eqsniffer.def file into the project folder.
    Add eqsniffer.cpp and eqsniffer.def to the project (right-click and select "Add Files to project"
    Right-click the project and select Settings
    Change "Settings For" to "All Configurations"
    In the C++ Tab ...
    Category: General
    - Debug Info: None
    Category: C++ Language
    - Enable Exception Handling: UNCHECKED
    - Enable run-time type information: UNCHECKED
    - Disable construction displacements: UNCHECKED
    Category: Code Generation
    - Use run-time library: Single Threaded
    Category: Customize
    - Enable function-level linking: CHECKED
    - Eliminate duplicat strings: CHECKED
    Switch to the "Link" Tab
    Category: General
    - Generate Debug info: UNCHECKED

    As more people get up and running with different compilers I will incorporate those instructions into the CPP file.

    Edit the eqsniffer.def file, and at the top where it says "LIBRARY eqsniffer" change
    the name to the name of your project (no DLL extension).

    ***** The following steps are optional, but highly recommended in order to make your
    ***** build unique and deter Verant from being able to detect the program. The program is
    ***** quite stealthy on its own, but the steps below will give you some added security.

    Rename HookProc, InstallProc and ReleaseProc to something obscure in the DEF file while
    you're there.

    Open the eqsniffer.cpp file and find where the "#define EQHOOKPROC" statement is down below.
    Rename the functions to the same names you gave in the .DEF file in step 4.

    For example ... if you renamed HookProc to TCPNotify, the #define statement would
    read:

    #define EQHOOKPROC TcpNotify

    Do this for all 3 functions, making sure they match the names in the .DEF file.


    RUNNING EQ WITH THE HOOK
    First, you have to get this program up and running.

    To install the hook, use this command line as a template:

    RUNDLL32.EXE mysniffer.dll,InstallHook <ipaddr> <port> <filename> <memaddr>

    Replace "mysniffer.dll" with whatever name you gave the DLL
    Replace "InstallHook" with whatever name you gave to the InstallHook procedure from
    steps 4-5 above.

    <ipaddr> The IP Address of your SEQ box
    <port> The port to send UDP packets to the SEQ box on
    <filename> Either EQGAME.EXE or TESTEQGAME.EXE or any partial derivitive of.
    The code uses strstr() to see if this sequence is in the actual
    filename of the process being attached (case-insensitive)
    <memaddr> The memory address to read the key from ... 0x0078AAD0

    Example:
    RUNDLL32.EXE mysniffer.dll,InstallHook 192.168.1.10 666 eqgame.exe 0x0078AAD0

    RUN EQ normally after the hook has been installed. There's no time limit or restrictions
    on when you can run it. This code will automatically latch onto it and take care of the rest.

    REMOVING THE HOOK:
    Removing the hook is only necessary if you installed it but never ran a program that
    matched the search criteria (in our case, "eqgame.exe"). If you ran that program, the
    hook auto-terminates, so there's no need for manual removal.

    RUNDLL32.EXE mysniffer.dll,ReleaseHook

    Again, rename "mysniffer.dll" to the name of your DLL, and rename "ReleaseHook" to
    whatever name you called it from steps 4-5 above.

    Revision 2.05
    - Fixed my call to GetTempFileName() -- accidentally passed a NULL for the directory name
    where it is supposed to not be NULL according to the MSDN docs.

    Revision 2.04
    - Changed the InjectCode() routine to inject the entire code section of the DLL rather
    than just the code for the InternalHookProc. This was done because many compilers use
    jump tables at the beginning of the code section, and the pointer to the InternalHookProc
    was actually at the beginning of the code section rather than at the end. Also, there
    were some cases where references were being made to code further up in memory, which did
    not exist when the code was injected.
    - Added the _SNIFFDEBUG #define to allow debug output to appear even in release builds.
    Commment the line out when you're done testing the sniffer and ready to use it for real.

    Revision 2.03
    - Added more debugging code to try and isolate why the DLL isn't being released properly
    - Added a safety variable gsh_bInjected to prevent multiple injections of the code into the game

    Revision 2.02
    - Fixed a bug in the offset code calculation code that allocated WAY TOO DAMN MUCH MEMORY!
    - Removed one line of the assembly code that wasn't really necessary to begin with.
    - Slightly modified the beginning of the 2 lines of assembly to fix a Borland compiler issue.

    Revision 2.01
    - Fixed a bug in DllMain that prevented the DLL from loading. TRUE, FALSE, they're the
    same, right?

    Revision 2.0
    - Sneakiness has improved! (200) This version uses a memory-injection technique to inject
    its payload into the process's virtual memory. Once it injects its payload, it drops out
    completely so there's no residual DLL in memory while the game runs.

    Revision 1.3
    - The DLL automatically releases itself from the global hook chain when it successfully hooks
    to the matching process. When it hooks into the target process, it uses a local-only hook.
    - Changed the way the hooking mechanism works. The global hook is triggered by a keypress
    rather then a mouse move.
    - Removed the Timer from the sniffer. The DLL now uses a WH_GETMESSAGE hook local to the target
    process, which hooks into the main thread's message queue. No timer is necessary, and the
    sniffer has improved invisibility
    - Got rid of rand() and srand() for lighter code. Uses GetTickCount() now to get the XOR seed.

    Revision 1.2
    - Removed the try/catch and replaced it with the easier IsBadReadPtr() API call to determine
    whether or not the mem addr is readible.
    - Modified the DoEQProcessing() loop to only open a socket if the key changes. Oops!

    Revision 1.1
    - Added _MSC_VER checks around the __try and __catch exception handlers to avoid non-MS compiler problems
    - Added function prototypes to avoid problems when the code is rearranged.
    - Added #define's to define the name of the HookProc, InstallHook and ReleaseHook methods for easy renaming.
    - Added a #define for the update interval, defaulting to 500ms (half a second). Since this DLL lives
    in the same address space as the game, it doesn't have the overhead of out-of-process methods and therefore
    doesn't require as much time and effort and API calls to get the key. Therefore 500ms is quite acceptable.
    */

    /*
    TODO:
    - Change the name of the InstallHook, ReleaseHook and HookProc functions.
    - Edit the EQSNIFFER.DEF file and update it to reflect the above changes.
    - Rearrange the items in the shared data segment, add some filler nonsense
    variables, etc.
    */

    #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
    #define STRICT

    #define _SNIFFDEBUG // Comment this line out when compiling for release build!

    #include <windows.h>
    #include <tchar.h>
    #include <winsock.h>
    #include <stdlib.h>

    // Includes the WINSOCK library without having to tweak linker settings
    #pragma comment(lib,"wsock32.lib")

    // These are the names of the 3 exported functions. Rename them
    // to something else here and in the corresponding .DEF file.
    // Example:
    // #define EQHOOKPROC TcpNotify
    // Don't forget to change the EQHookProc entry in the .DEF file to TcpNotify

    #define EQHOOKPROC HookProc
    #define INSTALLHOOK InstallHook
    #define RELEASEHOOK ReleaseHook

    // V2
    // This offset determines where the new code is injected in the allocated
    // memory block. This number will be bit-shifted to get a good
    // aligned offset for the code. You may make the number anything from
    // 0x00 - 0xFF (0 - 255 in decimal notation)
    #define INJECT_OFFSET 0x04

    // *** V2 ADDITIONS ***
    // typedef's for functions we're going to call within our injected code
    typedef SIZE_T (WINAPI *VIRTUALQUERY) (LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T);
    typedef BOOL (WINAPI *ISBADREADPTR) (CONST VOID *,UINT_PTR);
    typedef SOCKET (PASCAL FAR *CREATESOCKET) (int, int, int);
    typedef int (PASCAL FAR *SENDTO) (SOCKET, const char FAR *, int, int, const struct sockaddr FAR *, int);
    typedef int (PASCAL FAR *CLOSESOCKET) (SOCKET);
    typedef LRESULT (WINAPI *CALLNEXTHOOKEX) (HHOOK, int, WPARAM, LPARAM);

    // *** V2 ADDITIONS ***
    // This data structure holds data necessary for the injected code to function.
    // When the DLL drops out, the injected code must hold its own without the benefit of
    // API calls (other than those referenced here) or C-runtimes.
    typedef struct _injectstruct
    {
    LPVOID pvmem; // Mem address to read in the process
    SOCKADDR_IN addr; // Socket address to communicate with SEQ
    ULONGLONG ullLastKey; // The last encryption key transmitted
    HHOOK hHook; // Hook handle for passing messages on
    ULONGLONG sentxor; // Value by which the transmitted key will be XORed

    // These are API function pointers which must be explicitly pre-determined
    // because once the DLL drops out, the injected code will be orphaned
    // and won't have a lookup table.
    VIRTUALQUERY func_VirtualQuery;
    ISBADREADPTR func_IsBadReadPtr;
    CREATESOCKET func_socket;
    SENDTO func_sendto;
    CLOSESOCKET func_closesocket;
    CALLNEXTHOOKEX func_CallNextHookEx;
    } INJECTSTRUCT, *LPINJECTSTRUCT;

    /*
    In the shared data segment below, rearrange the items as they appear, and
    don't be afraid to add more nonsense globals with nonsense values, such as
    DWORD gsh_dwFiller = 0xBEEFD00D;
    And so on and so forth.
    */

    // Shared data segment across all processes attached to the DLL
    #pragma data_seg(".shared")
    HHOOK gsh_hHook = NULL; // Global handle to our place in the hook chain
    TCHAR gsh_szEvent[MAX_PATH] = {_T("\0")}; // Global named event for signalling termination
    SOCKADDR_IN gsh_SEQAddr = {0}; // Socket address of the SEQ box
    LPVOID gsh_pvEQKey = NULL; // Memory address to read the key from
    DWORD gsh_xorby = 0; // Random number to XOR the strings and memory loc by to randomize it.
    TCHAR gsh_szFileName[MAX_PATH] = {_T("\0")}; // Filename (EQGAME.EXE or TESTEQGAME.EXE) to test for.
    BOOL gsh_bInjected = FALSE; // Safety measure to prevent multiple injections
    ULONGLONG gsh_sentxor = 0x0000000000000000; // Global value - transmitted key XOR
    #pragma data_seg()

    // Module handle for this DLL (process dependent)
    HMODULE g_hMod = NULL;

    // Function prototypes. These first few funcs remain static and don't require any name change
    // because they are not exported.
    BOOL APIENTRY DllMain (HANDLE, DWORD, LPVOID);
    void xormem (LPVOID, DWORD, DWORD);
    BOOL InjectCode ();
    LRESULT WINAPI InternalHookProc(int, WPARAM, LPARAM);

    // These prototypes use the #define'd names above and declare the 3 exported functions.
    LRESULT CALLBACK EQHOOKPROC (int, WPARAM, LPARAM);
    void CALLBACK INSTALLHOOK (HWND, HINSTANCE, LPTSTR, int);
    void CALLBACK RELEASEHOOK (HWND, HINSTANCE, LPTSTR, int);

    // DLL Entrypoint. Records our module handle.
    BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    {
    if (dwReason == DLL_PROCESS_ATTACH)
    {
    TCHAR szModule[MAX_PATH];
    TCHAR szCmp[MAX_PATH];
    g_hMod = (HMODULE)hModule;

    // Get the process's filename
    GetModuleFileName(NULL, szModule, MAX_PATH);
    CharUpper(szModule);

    // Get the filename we're going to be comparing it to, and de-XOR it.
    CopyMemory(szCmp, gsh_szFileName, MAX_PATH);
    xormem(szCmp, gsh_xorby, MAX_PATH);

    // Check to see if the process is the EQ game
    if (_tcsstr(szModule, szCmp) != 0 && szCmp[0])
    {
    #ifdef _SNIFFDEBUG
    OutputDebugString(_T("Found EQ Process!\n"));
    #endif
    // V2 - Injects the sniffer code into memory, then releases the hook and exits with
    // a FALSE message, which prevents the DLL from loading into the actual game's process space.
    // The process will be none the wiser and will never even know the DLL was loading to begin with.
    if (!gsh_bInjected) InjectCode();

    gsh_bInjected = TRUE;

    RELEASEHOOK(NULL, (HINSTANCE)hModule, NULL, 0);

    return FALSE;
    }
    #ifdef _SNIFFDEBUG
    else
    {
    TCHAR szMsg[MAX_PATH];
    wsprintf(szMsg, _T("Ignoring process attach request for %s\n"), szModule);
    OutputDebugString(szMsg);
    }
    #endif

    // Clear out our temp variable for safety sake.
    ZeroMemory(szCmp, MAX_PATH);
    ZeroMemory(szModule, MAX_PATH);
    }

    return TRUE;
    }

    // RUNDLL32 entrypoint to install the hook procedure.
    // RUNDLL32.EXE <dllname>, InstallHook <ipaddr> <port> <eqgame.exe> <memaddr>
    void CALLBACK INSTALLHOOK(HWND hWnd, HINSTANCE hInst, LPTSTR pszCmdLine, int nCmdShow)
    {
    if (!gsh_hHook) // Only do this if the hook isn't already installed
    {
    HANDLE hEvent;
    int n = 0;
    LPTSTR pszTok;

    gsh_xorby = GetTickCount(); // XOR our globals as a simplistic scrambler to prevent memory reading

    pszTok = _tcstok(pszCmdLine, _T(" "));
    while(pszTok)
    {
    switch(n)
    {
    case 0:
    gsh_SEQAddr.sin_family = AF_INET;
    gsh_SEQAddr.sin_addr.s_addr = inet_addr(pszTok);
    break;
    case 1:
    gsh_SEQAddr.sin_port = htons(_ttoi(pszTok));
    break;
    case 2:
    lstrcpy(gsh_szFileName, pszTok);
    CharUpper(gsh_szFileName);
    xormem(gsh_szFileName, gsh_xorby, MAX_PATH);
    break;
    case 3:
    gsh_pvEQKey = (LPVOID)_tcstoul(pszTok, NULL, 16);
    xormem(&gsh_pvEQKey, gsh_xorby, sizeof(gsh_pvEQKey));
    break;
    case 4:
    gsh_sentxor = _strtoui64(pszTok, NULL, 16);
    break;
    }
    n ++;
    pszTok = _tcstok(NULL, _T(" "));
    }
    if (n < 5) return; // Not enough arguments.

    // Get a temporary variable to hold the name of the global event.
    GetTempFileName(_T("."), NULL, 0, gsh_szEvent);
    DeleteFile(gsh_szEvent);

    #ifdef _SNIFFDEBUG
    TCHAR szMsg[MAX_PATH];
    wsprintf(szMsg, _T("Creating event handle \"%s\"\n"), &gsh_szEvent[2]);
    OutputDebugString(szMsg);
    #endif

    // Create an event handle to wait on.
    hEvent = CreateEvent(NULL, FALSE, FALSE, &gsh_szEvent[2]);
    if (hEvent)
    {
    // Set the global hook procedure
    gsh_hHook = SetWindowsHookEx(WH_KEYBOARD, EQHOOKPROC, g_hMod, 0);

    // Put RUNDLL32.EXE to sleep and wait for the event to be triggered.
    WaitForSingleObject(hEvent, INFINITE);

    // Close the event
    CloseHandle(hEvent);

    // Unhook the windows event hook
    UnhookWindowsHookEx(gsh_hHook);
    gsh_hHook = NULL;
    }
    #ifdef _SNIFFDEBUG
    else
    {
    OutputDebugString(_T("Unable to create event handle!\n"));
    }
    #endif
    }
    }

    // RUNDLL32 entrypoint to release the hook procedure.
    // This function merely opens the global event and triggers it, which causes the
    // waiting RUNDLL32 instance to wake up and release the hook.
    void CALLBACK RELEASEHOOK(HWND hWnd, HINSTANCE hInst, LPSTR pszCmdLine, int nCmdShow)
    {
    if (gsh_hHook) // Only do this if the hook is installed.
    {
    #ifdef _SNIFFDEBUG
    TCHAR szMsg[MAX_PATH];
    wsprintf(szMsg, _T("Opening global event \"%s\"\n"), &gsh_szEvent[2]);
    OutputDebugString(szMsg);
    #endif
    // Open the event by name
    HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, TRUE, &gsh_szEvent[2]);
    if (hEvent != NULL)
    {
    SetEvent(hEvent); // Set the event to active, which wakes up the original hook installer.
    CloseHandle(hEvent); // Close our copy of the event handle before exiting.
    }
    #ifdef _SNIFFDEBUG
    else
    {
    TCHAR szMsg[MAX_PATH];
    wsprintf(szMsg, _T("Unable to open global event \"%s\"\n"), &gsh_szEvent[2]);
    OutputDebugString(szMsg);
    }
    #endif
    }
    }

    // Global hook procedure which captures all mouse events for all processes.
    LRESULT CALLBACK EQHOOKPROC(int nCode, WPARAM wParam, LPARAM lParam)
    {
    // Do-nothing hook procedure ...
    return CallNextHookEx(gsh_hHook, nCode, wParam, lParam);
    }

    // V2 - Allocates memory, injects our sniffer code into it, and gets it started.
    BOOL InjectCode()
    {
    LPVOID pvCode;
    LPVOID pvMem;
    INJECTSTRUCT inj;
    LPVOID pvStart;
    DWORD dwLen;
    MEMORY_BASIC_INFORMATION mbi;
    DWORD dwOffset = MAKELONG(MAKEWORD(0, INJECT_OFFSET), 0);
    DWORD dwFuncOffset;

    // The start of the function we're injecting
    pvStart = (LPVOID)InternalHookProc;

    // Figure out how large our memory block is that contains our sniffer code.
    VirtualQuery(pvStart, &mbi, sizeof(mbi));
    dwFuncOffset = (DWORD)pvStart - (DWORD)mbi.BaseAddress;

    // Determine the length of the code to inject, and add the size of the offset to it.
    dwLen = (DWORD)mbi.RegionSize + dwOffset;

    #ifdef _SNIFFDEBUG
    TCHAR szMsg[MAX_PATH];
    wsprintf(szMsg, _T("Injecting code length %d ...\n"), dwLen);
    OutputDebugString(szMsg);
    #endif

    // Allocate a writeable memory block in preparation for injection ...
    pvCode = VirtualAlloc(NULL, dwLen, MEM_COMMIT, PAGE_READWRITE);
    if (!pvCode) return FALSE; // Failed to allocate memory

    #ifdef _SNIFFDEBUG
    wsprintf(szMsg, _T("Code allocated at 0x%8.8X\n"), pvCode);
    OutputDebugString(szMsg);
    #endif

    // Get the memory address to sniff for, and de-xor it.
    pvMem = gsh_pvEQKey;
    xormem(&pvMem, gsh_xorby, sizeof(pvMem));

    // Clear and fill out the struct with pointers to our API calls and some other useful stuff
    // such as the SEQ box socket addr, the memory pointer to sniff, etc.
    ZeroMemory(&inj, sizeof(inj));
    inj.addr = gsh_SEQAddr;
    inj.pvmem = pvMem;
    inj.ullLastKey = MAXDWORD;
    inj.sentxor = gsh_sentxor; // pass the injected code the value by which to XOR the key before sending
    inj.func_VirtualQuery = (VIRTUALQUERY) GetProcAddress(GetModuleHandle(_T("KERNEL32")), "VirtualQuery");
    inj.func_IsBadReadPtr = (ISBADREADPTR) GetProcAddress(GetModuleHandle(_T("KERNEL32")), "IsBadReadPtr");
    inj.func_socket = (CREATESOCKET) GetProcAddress(GetModuleHandle(_T("WSOCK32")), "socket");
    inj.func_sendto = (SENDTO) GetProcAddress(GetModuleHandle(_T("WSOCK32")), "sendto");
    inj.func_closesocket = (CLOSESOCKET) GetProcAddress(GetModuleHandle(_T("WSOCK32")), "closesocket");
    inj.func_CallNextHookEx = (CALLNEXTHOOKEX)GetProcAddress(GetModuleHandle(_T( "USER32")), "CallNextHookEx");

    // Write the injection struct to the beginning of the memory page.
    CopyMemory(pvCode, &inj, sizeof(inj));

    // Copy our DLL code into the memory page starting at the offset specified.
    CopyMemory((LPBYTE)pvCode + dwOffset, mbi.BaseAddress, dwLen - dwOffset);

    // Mark the code's memory to allow execution.
    VirtualProtect(pvCode, dwLen, PAGE_EXECUTE_READWRITE, &dwLen);

    #ifdef _SNIFFDEBUG
    OutputDebugString(_T("Setting hook procedure...\n"));
    #endif

    // Set a hook into the message pump of the process's main thread.
    ((LPINJECTSTRUCT)pvCode)->hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)((LPBYTE)pvCode + dwOffset + dwFuncOffset), NULL, GetCurrentThreadId());

    return TRUE;
    }

    // XOR routine to scramble our in-memory variables to prevent sniffing
    void xormem(LPVOID pvmem, DWORD dwXorVal, DWORD dwSize)
    {
    while (dwSize > 3)
    {
    ((LPDWORD)pvmem)[0] ^= dwXorVal;
    dwSize -=4 ;
    pvmem = &((LPDWORD)pvmem)[1];
    }

    while (dwSize > 1)
    {
    ((LPWORD)pvmem)[0] ^= LOWORD(dwXorVal);
    dwSize -= 2;
    pvmem = &((LPWORD)pvmem)[1];
    }

    if (dwSize) ((LPBYTE)pvmem)[0] ^= (LOBYTE(LOWORD(dwXorVal)));
    }

    /* Called periodically while EQ is running to keep the encryption key updated.
    This code is injected into allocated memory in the address space of the main process.
    It is not executed where it is originally intended.

    Because of this, we cannot call any API calls directly! Instead, we have to rely on
    a pointer to some memory above this codeblock which gives us pointers to the API calls we
    need, along with state information so we can make some decisions.

    Remember, the DLL that injected this code is no longer resident in the main process, so
    we do not have it to fall back on! This function must be entirely self-contained, and any
    API calls must be provided by the structure at the beginning of this memory block.
    */
    LRESULT WINAPI InternalHookProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
    LPVOID pvmem;
    SOCKET s = INVALID_SOCKET;
    ULONGLONG ullKey = 0;
    LPINJECTSTRUCT pinj;
    SOCKADDR_IN addr;
    DWORD dwOffset = MAKELONG(MAKEWORD(0, INJECT_OFFSET), 0);
    ULONGLONG sentval; // will hold the final transmitted value (key ^ xorvalue)

    // Gets the EIP register, essentially.
    // We need to know where in memory we are, in order to find out where our INJECTSTRUCT is.
    __asm {
    call $ + 5
    pop pvmem
    }

    // Round the number down a bit to account for function call overhead
    pvmem = (LPVOID)((DWORD)pvmem & 0xFFFF0000);

    // Get the position of the struct containing our needed junk
    pinj = (LPINJECTSTRUCT)((DWORD)pvmem);

    // Execute this code, provided the given pointer references memory we can actually read.
    if (!pinj->func_IsBadReadPtr(pinj->pvmem, sizeof(ULONGLONG)))
    {
    ullKey = ((ULONGLONG *)pinj->pvmem)[0]; // Retrieve the key from memory

    if (ullKey != pinj->ullLastKey) // If its different from the last key, send it to SEQ.
    {
    addr = pinj->addr;
    sentval = (ULONGLONG)ullKey ^ pinj->sentxor; // xor the key with the selected xor value

    s = pinj->func_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s != SOCKET_ERROR)
    {
    // Send the 8 bytes along to the SEQ box
    pinj->func_sendto(s, (char *)&sentval, sizeof(ULONGLONG), 0, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN));
    pinj->func_closesocket(s);
    }
    // Record the XOR'd key for future reference.
    pinj->ullLastKey = ullKey;
    }
    }
    return pinj->func_CallNextHookEx(pinj->hHook, nCode, wParam, lParam);
    }




    ========================
    end of code

    Attached is a zip file. I've called it eqsniffer206 to distinguish it from the main release. Hope this is okay, Maggotboy
    Attached Files Attached Files

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

You may post new threads
You may post replies
You may post attachments
You may edit your posts
HTML code is Off
vB code is On
Smilies are On
[IMG] code is Off