View Full Version : V2 Stealth Code for LCC-Win32 (finally!)
MisterSpock
11-25-2002, 11:39 PM
VERSION 1.1 -- Corrects a problem from the previous version that was causing the keysniffer to spam the seq box under certain conditions. Also caused misinterpretation of certain keys, and seq failed to decode.
**If you built the LCC code before 07:00 EST 11/26, rebuild with this code to correct the problem.**
SNIFFDEBUG commented out by default to avoid accidental sloppy builds where debugging is not needed.
VERSION 1.0 -- Stopped the keypress = crash problem. Now runs under LCC.
Instructions:
Build this code using the same basic steps and instructions as found for version 1 of the LCC code. The key points are to make a small alteration to the .DEF file, check do not include underscores in DLL exports (linker settings), and do not include debugging info.
Code follows:
===========================================
#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
// 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
#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.
// Renamed to LibMain for LCC
BOOL APIENTRY LibMain (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.
// Renamed to LibMain for LCC
BOOL APIENTRY LibMain(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;
}
n ++;
pszTok = _tcstok(NULL, _T(" "));
}
if (n < 4) 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 0x%8.8X ...\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("Virtualmem 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.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.
*/
// ullKey declared as DWORDLONG instead of ULONGLONG
// This stops the crashing on keypress.
// Cast as ULONGLONG does not cause problems, and is preserved to avoid sign bit problems.
LRESULT WINAPI InternalHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPVOID pvmem;
SOCKET s = INVALID_SOCKET;
DWORDLONG ullKey = 0;
LPINJECTSTRUCT pinj;
SOCKADDR_IN addr;
// Gets the EIP register, essentially.
// We need to know where in memory we are, in order to find out where our INJECTSTRUCT is.
// Call $ + 5 should work in AT&T syntax, but doesn't on LCC
_asm("call here");
_asm("here: popl %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(DWORDLONG)))
{
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;
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 *)pinj->pvmem, sizeof(DWORDLONG), 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);
}
MisterSpock
11-26-2002, 06:35 AM
Zip file includes Maggotboy's V2 source and def files modified to work under LCC.
This is version 1.1 of the revision.
SomeYoungGuy
11-26-2002, 09:40 AM
You Rock MisterSpock!!!
/bows
I've been using your Revision of the V1 code flawlessly.
Now when you say to follow the same steps to configure LCC as V1 does that include selecting optimize and usepentium pro in the compiler settings? And all the rest of your walkthrough?
devnul
11-26-2002, 11:54 AM
"ullKey declared as DWORDLONG instead of ULONGLONG
This stops the crashing on keypress.
Cast as ULONGLONG does not cause problems, and is preserved to avoid sign bit problems."
This is the problem where EQ crashes as soon as you hit a key that I could never figure out?
You have any idea why it did not happen for everyone?
I can't wait to try this fix when I get home!
dn
MisterSpock
11-26-2002, 12:34 PM
To the best of my knowledge, this is an idiosyncracy that appears only in LCC.
The type DWORDLONG doesn't appear in the base MS documentation -- ULONG64 and ULONGLONG do. I don't know if DWORDLONG is a GNU standard data type, or if it is unique to LCC.
Either way, I was able to isolate that using ULONGLONG in the declaration was the source of the crash, at least for LCC. I'm in the process of comparing the assembly code between the two versions to see if it sheds some light as to why. Declaring the variable as a DWORDLONG preserves the length of the variable (64 bits), but is signed. Thankfully, casting the variables with ULONGLONG didn't crash!
Is this or something like it the cause for other crashes on keypress? That I do not know. The symptom that occurred in LCC *was* the same as others are experiencing, but that does not indicate that the source of the problem is the same. Honestly, I have NEVER been able to duplicate the crashes on MS compilers, no matter what settings I've used (and in both .NET and VC6).
After lengthy experimentation, and writing some of my own injecting code in LCC, I was 100% certain that I was getting the right value in pvmem (the eip). I was also able to view the memory space of the sniffer *and* the virtual space by not allowing the dll to release. By hand, I was able to verify that the whole pinj struct and other vars were intact and that the injected/offset code matched the resident code before it was copied... All that was left was to verify that the inserted code was actually working.
As I mentioned, I was able to inject my own code without problem, so that eliminated a lot of the potential problems. I just started simplifying the routine down until I isolated the cause of the crash. You could do something as simple as pass it a pointer to the Beep command in the pinj structure, and comment out all declarations other than pvmem and pinj. Comment out the rest of the code except for something like:
pinj->func_Beep(1500,10);
(it has to be properly added to the pinj structure, of course)
and
return(0);
Attach your process to iexplore.exe at 0x00400000, and you should hear a chirp (actually, many chirps) when your code fires upon a message event. If you can get it to do this, you know your basic injection code is working. You can then start adding back in real functionality until you find the culprit.
MisterSpock
11-26-2002, 12:41 PM
SomeYoungGuy:
Yes, the V2 process is essentially identical to V1. The .def file is the same, and the basic compiler/linker settings are the same. The big difference is the few minor code twinks to get lcc to not crash on keypress.
The real keys to getting lcc to compile a dll are:
1) setting up the project as a dll when you first create it
2) making a .def file with the appropriate syntax
3) name your entry point LibMain
4) have the "Do not include underscores in dll exports" checked in the linker settings.
The other settings really only influence the size of the code (debugging symbols) the performance (optimize / pentium pro), and what intermediate files will be generated. The dll will work fine if you forget one of these other ones. However, I always prefer to make the code as small and fast as possible, so I recommend optimize, pentium pro, and no debugging symbols.
Do you get any warnings like this?
ftol.obj: multiple definition of __ftol
first definition is in file c:\lcc\lib\libcrt0.obj
I don't use the gui because I'm more comfortable with the command line. I got it to compile but since I'm not home yet I can't really try it out yet. I did get V1 to compile and it is working fine. I just wanted to try this one too.
I'm curious where you got the info on what to change the assembler code from. I looked all over yesterday and got some code to work but never did test it. I've learned more about assember that I ever wanted thanks to Maggotboy ;)
MisterSpock
11-26-2002, 02:33 PM
I don't receive any warnings during the build process.
I've had the assmebly part fixed for a while now. I did some searching on the net and found some pages that referenced both Intel and AT&T syntax. The trick was to verify that I was getting the EIP correctly after I came up with the syntax that looked like it should work.
To prove this, I wrote a simple exe file that contained nothing more than the assembly code in question. I simply ran this program with my debugger and watched the stack and the EIP. From there, I could verify that pvmem contained the EIP correctly.
Puppit
11-26-2002, 09:07 PM
Thanks for the cool port to lcc Mr. Spock. Did you mean, in your response to SomeYoungGuy to name the entry point LibMain or should it be DllMain? Thanks.
SomeYoungGuy
11-26-2002, 09:49 PM
Great thanx MrSpock
darkgrue
11-27-2002, 12:32 AM
Rolled up MisterSpock's LCC modifications into the main code - this should compile fine in both the MS and LCC environments (I tested both LCC and MS VC++ 6). Although you still have to remove that thrice-dammned "S" in the .DEF file - you can't use pragmas in that file. Includes the additional debug coding I was using to peer into the original V2 code's functionality... and can be disabled by merely commenting out the #define. Lastly, added instructions on how to set up the project in LCC.
Have to say I like the LCC code! It compiles 34K smaller, without any tweaking to the compile options, and it's a free compiler (with a much smaller install). The MS environment is, nice, but when you don't need or want the extra cost or functionality, the extra bells and whistles are a bigger hindrance than help.
Thanks Maggotboy, MisterSpock - nice code!
/* eqsniffer2.cpp written by Maggotboy
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
1. Create a new WIN32 Project
2. Project Options, choose DLL Project
3. Create the project and copy eqsniffer.cpp and eqsniffer.def into the new folder for it.
4. Remove stdafx.h, stdafx.cpp and ReadMe.txt from the project.
5. Right-click the project and add the eqsniffer.cpp and eqsniffer.def files to it.
6. Right-click the project, and go into Properties
7. 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
1. Create a WIN32 DLL Project
2. For the options, select Empty Project
3. Copy the eqsniffer.cpp and eqsniffer.def file into the project folder.
4. Add eqsniffer.cpp and eqsniffer.def to the project (right-click and select "Add Files to project"
5. Right-click the project and select Settings
6. 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
lcc-win32 Users
1. Select Project | Create... and enter the name of your project
2. Under Path | Working Directory, enter the full path to the project directory (e.g.
"C:\lcc\projects\lccsniffer"). Output directory will be automagically generated as a
subdirectory of your Working Directory, or you can set it to something else.
Users, Use versioning system, and Use framework should be left at their defaults ("single", and
unchecked).
Select Type of project as "Dynamic Link Library (dll)".
Select "Create".
3. Answer "No" to "Do you want to use the wizard to generate the application skeleton?"
4. Add this source file *with a .C and not a .CPP file extension (rename if necessary!) to
the project when prompted. Then select "Ok" when the "Source files for project" dialog
appears (the .C file should be the only file in the project).
5. In the Compiler Settings dialog, check "Optimize" and "Use pentium pro instructions"
and uncheck "Debugging support level | Generate debug info".
6. In the Linker settings, add to the "Additional files to be included in the link" dialog "wsock32.lib".
Check "Do not include underscores in dll exports".
Accept the defaults of "Do not include the debug information" (checked), "Type of
output" "DLL", and "Entry point name (for dlls)" "LibMain".
Add to the "Additional arguments to be passed to the linker" dialog the fully-qualified path to the
.DEF file (e.g. "C:\lcc\projects\keq\lccsniffer211.def").
7. Press "Finish" at the Debugger settings dialog.
8. Edit the eqsniffer.def file and change the "SECTIONS" keyword to "SECTION" (i.e. remove the "S").
All compiler users:
Edit the eqsniffer.def file, and at the top where it says "LIBRARY eqsniffer" change
the name to the name of your project (without the .DLL extension).
***** The following steps are optional, but highly recommended in order to make your
***** build unique. 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 eqsniffer2.cpp file (this file) and find where the "#define EQHOOKPROC" statement
is down below. Rename the functions to the same names you gave in the .DEF file.
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 eqsniffer.dll,InstallHook <ipaddr> <port> <filename> <memaddr>
Replace "eqsniffer.dll" with whatever name you gave the DLL/project
Replace "InstallHook" with whatever name you gave to the InstallHook procedure.
<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 eqsniffer.dll,InstallHook 192.168.1.10 10000 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 eqsniffer.dll,ReleaseHook
Again, rename "eqsniffer.dll" to the name of your DLL, and rename "ReleaseHook" to
the correct reference fromt he code and .DEF file.
Revision 2.05DG
- Added additional debugging output.
- Reformatted source to fit my own stylistic preferences. Removed "V2" comments in source to
re-baseline code, as some of the V1 comments aren't applicable to the V2 code.
- Rolled in v1.1 LCC changes by MisterSpock; hopefully, this version should compile correctly
in both the LCC and MS environments.
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.
*/
/*
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. For additional stealth, 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:
// Don't forget to change the EQHookProc entry in the .DEF file to TcpNotify:
// EXPORTS
// InstallHook
// ReleaseHook
// TcpNotify
#define EQHOOKPROC HookProc
#define INSTALLHOOK InstallHook
#define RELEASEHOOK ReleaseHook
// 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
// 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);
// 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; // Memory 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.
// 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;
// Shared data segment across all processes attached to the DLL.
// For additional stealth, 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...
#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.
#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.
#if defined(__LCC__)
// Renamed to LibMain for LCC
BOOL APIENTRY LibMain
#else
BOOL APIENTRY DllMain
#endif
(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) {
#ifdef _SNIFFDEBUG
TCHAR szMsg[MAX_PATH];
OutputDebugString(_T("[DllMain] DllMain() called.\n"));
#endif
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);
#ifdef _SNIFFDEBUG
wsprintf(szMsg, _T("[DllMain] Candidate process filename is: \"%s\"\n"), szModule);
OutputDebugString(szMsg);
#endif
// 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);
#ifdef _SNIFFDEBUG
wsprintf(szMsg, _T("[DllMain] Target process filename is: \"%s\"\n"), szCmp);
OutputDebugString(szMsg);
#endif
// Check to see if the process is the EQ game.
if (_tcsstr(szModule, szCmp) != 0 && szCmp[0]) {
#ifdef _SNIFFDEBUG
OutputDebugString(_T("[DllMain] Found EQ Process!\n"));
#endif
// 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 {
wsprintf(szMsg, _T("[DllMain] Ignoring process attach request for %s\n"), szModule);
OutputDebugString(szMsg);
}
#endif
// Clear out our temp variables, for safety's 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) {
#ifdef _SNIFFDEBUG
TCHAR szMsg[MAX_PATH];
OutputDebugString(_T("[INSTALLHOOK] INSTALLHOOK() called.\n"));
#endif
if (!gsh_hHook) { // Only do this if the hook isn't already installed
#ifdef _SNIFFDEBUG
OutputDebugString(_T("[INSTALLHOOK] gsh_hHook is not set, preparing to install hook...\n"));
#endif
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) {
#ifdef _SNIFFDEBUG
wsprintf(szMsg, _T("[INSTALLHOOK] Reading command token: \"%s\"\n"), pszTok);
OutputDebugString(szMsg);
#endif
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;
}
n ++;
pszTok = _tcstok(NULL, _T(" "));
}
if (n < 4) 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
wsprintf(szMsg, _T("[INSTALLHOOK] 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("[INSTALLHOOK] Unable to create event handle!\n"));
#endif
}
#ifdef _SNIFFDEBUG
else
OutputDebugString(_T("[INSTALLHOOK] gsh_hHook is set, exiting.\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) {
LONG retval;
#ifdef _SNIFFDEBUG
TCHAR szMsg[MAX_PATH];
OutputDebugString(_T("[RELEASEHOOK] RELEASEHOOK() called.\n"));
#endif
if (gsh_hHook) { // Only do this if the hook is installed.
#ifdef _SNIFFDEBUG
OutputDebugString(_T("[RELEASEHOOK] gsh_hHook is set\n"));
wsprintf(szMsg, _T("[RELEASEHOOK] 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.
retval = CloseHandle(hEvent); // Close our copy of the event handle before exiting.
#ifdef _SNIFFDEBUG
if (retval)
OutputDebugString(_T("[RELEASEHOOK] Handle closed.\n"));
else
OutputDebugString(_T("[RELEASEHOOK] Handle close failed!\n"));
#endif
}
#ifdef _SNIFFDEBUG
else {
TCHAR szMsg[MAX_PATH];
wsprintf(szMsg, _T("[RELEASEHOOK] Unable to open global event \"%s\"\n"), &gsh_szEvent[2]);
OutputDebugString(szMsg);
}
#endif
}
#ifdef _SNIFFDEBUG
else
OutputDebugString(_T("[RELEASEHOOK] gsh_hHook is not set\n"));
#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);
}
// 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;
#ifdef _SNIFFDEBUG
TCHAR szMsg[MAX_PATH];
OutputDebugString(_T("[InjectCode] InjectCode() called.\n"));
#endif
// 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
wsprintf(szMsg, _T("[InjectCode] 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("[InjectCode] 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));
#ifdef _SNIFFDEBUG
wsprintf(szMsg, _T("[InjectCode] Set to sniff at 0x%8.8X\n"), pvMem);
OutputDebugString(szMsg);
#endif
// 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.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("[InjectCode] 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 reverse sniffing through obfuscation.
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;
// ullKey declared as DWORDLONG instead of ULONGLONG to resolve the crashing on keypress issue.
// Cast as ULONGLONG does not cause problems, and is preserved to avoid sign bit problems.
DWORDLONG ullKey = 0;
LPINJECTSTRUCT pinj;
SOCKADDR_IN addr;
// Gets the EIP register, essentially.
// We need to know where in memory we are, in order to find out where our INJECTSTRUCT is.
#if defined(__LCC__)
// Call $ + 5 should work in AT&T syntax, but doesn't on LCC.
_asm("call here");
_asm("here: popl %pvmem");
#else
__asm {
call $ + 5
pop pvmem
}
#endif
// 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 it's different from the last key, send it to SEQ.
addr = pinj->addr;
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 *)pinj->pvmem, 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));
}
Puppit
11-27-2002, 08:55 AM
Awesome job guys! Darkgrue's posting of Maggotboys code with MisterSpocks lcc port compiles fine in lcc. Works like a charm :) Thank you all
MisterSpock
11-27-2002, 09:54 AM
Darkgrue,
Awesome work on the combined version!
The reason I kept up the quest to solve the LCC problem was the exact reason you pointed out -- code size. The environment is very spartan, and the resulting code is quite compact. The smallest I was able to get the V2 code with MS was around 30K. With LCC, the code is 8K. Oh -- and the price is right!
fizzlemaster
11-27-2002, 06:51 PM
I'm runnign the lcc version of V2, with optimized setings on compile, I've noticed a jump in packet loss on my system when running the dll type sniffer,
I'm running XP , on a Athlon 1.4gighz, 512meg of pc133,
I was wondering if others notice a between 10% and 20% packet loss when running this sniffer?? I'm hopeing some fine tuneing will squash this, right now I'm takeing the risk of useing telnet to start the keyring2 version each time I zone, then tossing it a CTL-C , All in all it's a small issue, If the dll sniffer was the only option I'd accept the PacketLoss and call it the price of haveing a decodeing SEQ, I was thinking of trying a newer Network card driver, then move on to a Better network card , (From dlink to Intel)
MisterSpock
11-27-2002, 07:35 PM
Hmmm... I have not noticed any additional packet loss from the lcc or the M$ version. I'll look into it and see if I can replicate it.
Kimbler
11-28-2002, 07:21 AM
Thank you for putting a ver free compilers.
Should questions about this go in HELP forum? Not knowing I put it here but if I am wrong let me know and i will post all other questions in the help forum.
I downloaded the Lcc-win32 and followed all the directions to change names to less obvious names with the exception of the file name lccsniffer211.def. I did not see any directions to make this file less noticeable. Did I miss something obvious or is ok to leave this one as is.
I sorta thought ANY file with "sniffer" in it ought to get remaned.
EDIT: I found it in the setting!!!DUH But please coment on WHERE sniffer questions should go please.
Kimbler
11-28-2002, 08:13 AM
Well, I changed the sniffer.def file name to some thing less obvious and changed the Addition arguements to be passed to linker" to the full path name of my new sniffer.def and I get a crash to desttop on any key entry. I read through Maggots posts and saw references to the crash but nothing seems to apply.
Also after I changed the linker path I did recompile. Suggestions?
MisterSpock
11-28-2002, 08:28 AM
You're calling the correct entry point when using rundll32, right?
There are 3 exports by default --
InstallHook
ReleaseHook
HookProc
Make sure you call InstallHook and not HookProc.
Are you using the latest lcc code?
Kimbler
11-28-2002, 09:21 AM
Lcc information:
Wedit Win32 Version 3.3 from Nov 7 2002 so I bet it is not current!!! I will look for most current version.
In my .C file I have
#define EQHOOKPROC Htrigger
#define INSTALLHOOK Itrigger
#define RELEASEHOOK Rtrigger
My DEF file
LIBRARY alcatell
SECTION
.shared READ WRITE SHARED
EXPORTS
Itrigger
Rtrigger
Htrigger
My compiler conf “linker setting” “additional arguments to be passed to the linker is :
D:\lcc\projects\alcatell\alcatell.def
I not to good at this stuff (obvious) but once I followed all the instructions the last thing I did ( it was not explicitly stated in the instructions) was:
From the wedit-alcatell MAIN window I selected ->Complier -> compile alcatell
My run line from Start->RUN
RUNDLL32.EXE D:\lcc\projects\alcatell\lcc\alcatell.dll,Itrigger 192.168.0.7 10000 EQGAME.EXE 0x0078AAD0
Now once I run it everything seems fine except EQ crashes and Other windows programs give me “illegal errors”. I have to reboot to clear everything.
MisterSpock
11-28-2002, 11:25 AM
Select REBUILD ALL from the compiler menu and try again.
Compile doesn't do the linking process. Make and rebuild do.
Kimbler
11-28-2002, 01:12 PM
Well thanks for trying to help but after 8 hours I have gotten nowhere.
I will list what I have done with hopes it might help someone not repeat what I have done.
1. Using Explorer I created a folder D:\lcc\projects\fresh. I do this so I have the files in one spot to work with later.
2. Downloaded the lccsniffer211.zip to D:\lcc\projects\fresh
3. unzipped them to D:\lcc\projects\fresh
4. started lcc and followed the directions for creating a new project named “fresh” using lccsniffer211.c as file added to project.
5. Since I was having so many problems I left a names “as is” no changing the hooknames and such ( I just wanted to see if I could get it run)
6. In LCC main window with lccsniffer211.c open I select rebuild all. At the bottom I get a successful build message (no errors)
7. I close LCC
8. Go to START->RUN enter RUNDLL32.EXE D:\lcc\projects\fresh\lcc\fresh.dll,InstallHook 192.168.0.7 10000 EQGAME.EXE 0x0078AAD0
9. hourglass comes up a few seconds (like 10)
10. open eq hit a key …..crash
11. open WORD hit a key…..illegal operation error
12. Have to reboot to get back to normal.
MisterSpock, Thanks for the great work others are getting to run but there really are people to stupid to figure out something that should be simple….I am one. Thanks for trying to help me. I will keep reading with hopes the light will come on J
Bob the builder
11-28-2002, 06:15 PM
Kimbler,
left a names “as is”
a new project named “fresh” using lccsniffer211.c as file added to project
Try making the .c and .def files the same name as the project
/shrug
Kimbler
11-29-2002, 04:53 AM
Well I gave it another shot this morning very meticuously matching project names and file names. I left the hook names untouched within the code and def files. the only thing I alter with the files was in the def file ->LIBRARY <namethatmatched_DLL,project,defname..all the same>. To be more clear . the project name was lex, dll was lex.dll, def file lex.def. In the lex.def I altered only the first line to read:
LIBRARY lex
SECTION
.shared READ WRITE SHARED
EXPORTS
InstallHook
ReleaseHook
HookProc
In LCC I have carefully followed each instruction. After I finish the last Finish (the project setup) on the debugger screen. I am looking at the lex.c raw code still open. I hit Compiler->Rebuild All and get no errors. I close LCC and START->RUN
RUNDLL32.EXE D:\lcc\projects\lex\lcc\lex.dll,InstallHook 192.168.0.7 10000 EQGAME.EXE 0x0078AAD0.
Still same crash on first keystroke. Since other folks are getting this to run I am beginning to think it is something about my system. I am running 98SE 4.10.2222 A. LCC is Version 3.3.
EDIT: Something I have discovered I do not understand. Even though I UNCHECK "Debugging Support level:Generate debug info" when i go bac to settings it is always rechecked. I can uncheck it close the setting tab and immediatly reenter and it is rechecked. Still looking.....
MisterSpock
11-29-2002, 06:43 AM
Kimbler,
That 'check & uncheck' problem is yet another lcc idiosyncracy. You're not doing anything wrong.
I've not tested the lcc code on Win98SE, so that might very well have something to do with it.
From experience, this code under lcc is *very* touchy. Even small additions and changes can cause it to crash bigtime. If I can get my hands on a win98SE machine, I'll see if I can get the code to work.
Bob the builder
11-29-2002, 06:45 AM
How bout the .c ??
/shrug
should be lex.c and lex.def and then choose Compiler/Make (F9)
dpaschal
11-29-2002, 07:56 AM
I get the following error when trying to compile with lcc under winxp:
Line 5: Keyword expectedMissing exports. Aborting
I did just as the instruction ssaid. And for the .c file, I used the .zip file supplied in this thread. Any tips?
Kimbler
11-29-2002, 08:26 AM
MisterSpock, Thank you! Sorry to cause all the grief.
Bob, Not sure what you are asking. My raw code file is lex.c and I use the REBUILD ALL which I though did everything to make the dll run. If there is some order/combinations like :
Make
compile
rebuild all
I don't know what they should be.
As of right now the only thing I do is Rebuild ALL after I have created the project and adjusted the raw files as the instructions say to do.
MisterSpock
11-29-2002, 09:16 AM
dpaschal,
That error looks like either the .def file is incorrect, or you have included it the wrong way.
It should not appear on the list of files in the project list. You need to specify the full path and name of the .def file in the linker settings. (Settings, Linker, additional parameters).
Kimbler:
I'm sorry this thing isn't running for you. When you get a crash message, is there any info you can find regarding the crash conditions?
For example:
Exception: C0000005
Location: 0x0002601e
etc...
Kimbler
11-29-2002, 11:44 AM
MisterSpock don't be sorry for it not working. It's the other way around I am grateful someone with your talent took the time to help so many of us.
As far as error: the crash to desktop from EQ produces no error messages but here is what is generated when I open Word and hit a key:
WINWORD caused an invalid page fault in
module OFFICEAV.DLL at 018f:100037bf.
Registers:
EAX=810100f8 CS=018f EIP=100037bf EFLGS=00010246
EBX=81bb966c SS=0197 ESP=0062f87c EBP=0062f8a8
ECX=10005060 DS=0197 ESI=025d0000 FS=4827
EDX=0000005c ES=0197 EDI=1000131f GS=0000
Bytes at CS:EIP:
66 89 17 8b 44 24 08 5f c3 88 17 8b 44 24 08 5f
Stack dump:
00000000 10001327 1000131c 1000505c 025d116e 025d0000 00000001 00000000 00000000 025d0000 81bb966c 0062fa70 bff7ddd6 025d0000 00000001 00000000
Hope that helps.
MisterSpock
11-29-2002, 12:55 PM
Kimbler,
Did you point your DLL toward MSWORD, or did it crash Word even when directed at eqgame.exe?
One thing you can try that will help isolate whether the crash happens because of the injected code or due to the hooking procedure is to comment out the following line:
((LPINJECTSTRUCT)pvCode)->hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)((LPBYTE)pvCode + dwOffset + dwFuncOffset), NULL, GetCurrentThreadId());
With this line commented out, the DLL should start, wait for whatever executable you pointed to, and then exit once a key is pressed. However, it will not actually start the injected code and thus won't send a key.
If this eliminates the crashes, then we've effectively isolated it down to the injected code stub.
wizard
11-29-2002, 02:03 PM
After downloading LCC and working with this a bit. i'm sorta stumped..
first off what i did.. i removed all libEQ.a files from my system (there was only one as i am pretty diligent about that) and optained a new one from the azriel trifocus site. and placed it in /usr/lib where i always have..
i then completely removed my showeq directory, and did a fresh download and full compile of showeq from CVS... I've had updates fail me many times in the past where a full checkout worked fine.. my standard procedure at this point is to do a full download and compile each time..
i downloaded your 1.1 version of the sniffer and compiled it with LCC.. i made no changes to any of it except to change the name in the .DEF file and renamed the .C and .DEF to the same name as well.. i wanted to test it and see if i could make it work before i made any other changes. I ran make received no errors and copied the created .DLL file to the windows directory.
i made a shortcut that runs RUNDLL32 myname.dll,InstallHook 192.168.0.254 26543 eqgame.exe 0x0078AAD0
i am running win98SE, I can load W2K (which i have been meaning to) as it seems most of the people having issues are on WIN98SE.
whenever I use the shortcut i get an hourglass for 5-10 seconds.. however if i go to a command prompt and type it manually its almost instantaneous. now the next part is intermittent and happens no matter which way i load the DLL..
i start up eq and select my character at the character select screen.. I am watching the console window on showeq at this point watching for the key to be found.. of course i set the port to look for the key on to 26543 as well..
one of 2 things happen.. i see on the console screen it loading the Guild data.. if i Don't immediately see the Loading zone lines after the guild lines i get dropped back to the server select screen and a subsequent 1018 error for a minute or 2 which tells me enough is getting loaded that the game thinks i am in the game. if THAT doesn't happen i get all the way in but no decode.
now somtimes when i exit EQ and check my task list rundll is in it.. and other times its not.. it NEVER is if i crash to server select.. if it is running the releasehook does NOT remove it. there have been times it was not in the task list when i didn't crash..
i've been using and was still able to use HOIHOI's sniffer using the same exact IP address and port so i know my seq box is setup correctly and is functional in receiving the key on the port I want and subsequently decodeing the zone.
couple of questions then so i know i am on the right track with my thought process and how this is supposed to work..
1) if when i exit EQ rundll is not in the task list that tells me that the code was successfully injected, the fact that MOST of the time I crash to server select when its NOT in the task list when i exit eq after tells me this is the case.
2) I tried running tcpdump on my linux box to look for the packet coming through.. if it is i should get the key every .5 seconds if i am understanding properly or does it not send the key again if it finds the same one in which case i would need to zone several times to verify it was getting or not getting the key. however tcpdump apparently does not appear anywhere on my linux box.
3) is there an RPM i need to install to get tcpdump on the box or will i be needing to reinstall Redhat?
4) If i compile the DLL with LCC on a win95 box at work is the subsequent DLL thats created able to run on 98/me/2k/xp or do i need to compile it on whatever operating system i intend to use it on?
Thanks for your assistance in advance and thanks for being persistant enough to get a free compiler version working for a lot of people.. I'm sure i've done something wrong at this point, but without tcpdump to verify if my linux box is receiving the key or not when i THINK it successfully injects itself i'm at a loss as to how to proceed.. i'll rebuild the linux box if i have to, gives me the incentive to load RH 8.0 instead and that way i will be 100% sure i have no remnants of an older version of SEQ or libEQ.a floating around.. if there are any i certainly can;t find them at this point and the fact that other sniffers work tells me that side of things is good to go..
vylesilencer
11-29-2002, 06:02 PM
Wanted to throw my hat in the ring for crashing on keypress.
I've very carefully followed the instructions provided, using same .def name, .c name and all compiles without error. Compiling on a 2K Pro SP2 workstation, and running the DLL on an XP Pro SP1 box. Both Keyboard and Mouse on the gaming system are USB, I'm wondering if this might be part of the problem? The system I run EQ on is extremely clean. Like the others, I am getting no error codes to give you, I just get the friendly MS dialog box stating the program is closing.
My system specs follow:
AMD 1.8g
1 gig system RAM
XP Professional, SP1
Nvidia Geforce 4 ti
Microsoft Natural keyboard, USB
Microsoft Optical mouse, USB
- I do not have the Intellitype or Intellipoint software installed -
Kimbler
11-30-2002, 05:01 AM
MisterSpock,
Did you point your DLL toward MSWORD, or did it crash Word even when directed at eqgame.exe?
I used
RUNDLL32.EXE D:\lcc\projects\lexa\lcc\lexa.dll,InstallHook 192.168.0.7 10000 EQGAME.EXE 0x0078AAD0
From START->RUN (lexa is another try with dif name). Once I run the command I can immediatly (do nothing else) open word and hit a key and get the error message.
Next:
I commented out the line in question with "//" <- line changed from dark to light text (like all comments in lexa.c) then with lexa.c still open I Compiler->Rebulid All get suscessful build message in bottom pane.
From START->RUN
RUNDLL32.EXE D:\lcc\projects\lexa\lcc\lexa.dll,InstallHook 192.168.0.7 10000 EQGAME.EXE 0x0078AAD0
immediately open Word hit a key and get the errors.
Thank you.
Wizard:
i am running win98SE, I can load W2K (which i have been meaning to) as it seems most of the people having issues are on WIN98SE.
Would you mind also giving the build numbers after your version of W98. Since it sounds like you code is getting past where mine gives errors maybe it may be build related (grabing at straws).Mine are 4.10.2222 A <-can be found ->My Computer->Properties on Genearl tab. Thank you
EDIT: After reading VSilencer again I figure I might let you know my mouse is USB, my keyboard is standard.
wizard
11-30-2002, 08:13 AM
98 SE should always be that build number..
i am using standard PS/2 keyboard and mouse.. I haven't crashed to the desktop.. just to server select whenever it seems to inject the code..
verified again last night that HOIHOI's still works for me i am 100% confident that SEQ itself is installed properly, that i have the right libEQ.A.. it finds the Key packet on the same port i am using for this DLL and Decodes perfectly.
SO i am left with this code sometimes injecting but i beleive it is crashing me to server select right about the time it would be sending the key to the SEQ box. i say that from observing at what time the key is sent using the HOIHOI code and the time i am crashing with the .DLL. going to check it a bit more. I might try installing W2K since i got plenty of drive space and dual boot for a time to see if i have the same problems under W2K.
cheese_poker
11-30-2002, 02:20 PM
I got this compiled ok with llc-win32. I can run it per the instructions here. But I am not getting the "unknowns" decoded on the SEQ box.
Is there something I can do to determine whether it is running and attaching to eqgame.exe?
I don't have EQW. Do I have to put a delay in the InstallHook procedure? Or will it wait for EQ to run by itself?
Sorry for the beginner questions. :/
FirstBorn
11-30-2002, 06:23 PM
Kimbler,
I think I may be having the same problem you are. I compiled with no errors and crash after running the Rundll32.exe <Insert hook.dll.code here, Ip address, ETC>
I don't have to do anything but touch a key after I run it and I get windows errors similiar to the ones you are getting (except I haven't started Word, or any program for that matter)
After you run the Rundll32.exe <insert hook.dll code here, IP address, ETC> does yours crash when touching ANY key or key combination?
Let me know,
FirstBorn
Kimbler
12-01-2002, 04:09 AM
Firstborn,
After I run it I am at desktop (which) I can hit a key without any errors. But just so I am clear when I open any other program I don't get a true non recoverable "crash" I just get a series of "this program has performed and illegal opperation". I can Close Word but the same happens for anyother program until I reboot.
FirstBorn
12-01-2002, 11:17 AM
It looks like the problem I was having had to do with some other apps that were running when my system booted up. I cleaned up my registry and removed all unneeded TSR's and my errors have gone away.
Though I still am unable to decode in SEQ, which I think has something to do with my UDP port. I have full GPS functionality but I don't see any active spawns and everything identifies as "unknown". I thought I read something about sometimes having to open the UDP port up in Linux, somewhere on these boards, I'll have to do a little research on it.
In any case check to make sure you don't have any apps or TSR's running that may be causing your errors.
Good luck,
FirstBorn
Puppit
12-01-2002, 02:00 PM
I have found (WinXP Pro) that occasionally I only get GPS but the spawns show up as soon as I enter a new zone. I've also found that Windows shuts down v..e..r..y slowly after I use the program. This is a small problem, however. Once the spawns do appear they remain, despite multiple subsequent zoning.
FirstBorn
12-01-2002, 02:22 PM
Still not getting any decode info, I have GPS functionality but all spawns still listed as unknown. I have tried running one of the "Simpler" keysniffers (Keyring) as a test and it worked fine, so I don't believe its my Linux/SEQ box. I used the same port number that I used in the "simpler" keysniffer when running this code, but still nothing. Have tried zoning muliple times and just leaving EQ running for a while (1/2 hour) to see if spawns would show up, still nothing.
Also when I exit EQ, I notice that Rundll32 is still running when I bring up my close program window. Shouldn't that automatically exit when EQ exits? Its almost like its not attaching to the EQ process correctly?
I don't use EQW and run EQ from the icon on my desktop. I noticed that the Icon points to "Everquest.exe" and not "Eqgame.exe" (although I'm sure Everquest.exe calls EQgame.exe at some point) so I changed my command line (Rundll32.exe <insert hook.dll code here, IP address, ETC>) to point to "Everquest.exe" instead of "Eqgame.exe", same results, no decode.
I also tried changing the IP address that the UDP is sent to from the address of my SEQ box to one outside my internal network (saw it in another post) same results, no decode.
I've recompiled twice with no errors, and copy the resulting DLL to my windows folder before running it.
Anyone have any ideas? Or having similiar problems?
SomeYoungGuy
12-01-2002, 06:37 PM
/bow MisterSpock
Downloaded the source. Complied Flawlessly. Decodes Great!
You're awesome.
One thing I noticed however (nothing show stopping):
I run 2 instances of EQ on my windows machine using EQW.
With your version of V1 what ever instance of EQ I started up first the sniffer locked onto no problem. I have found that V2 is much more fickle. I need to get the first instance to Char select before it will hook onto it. Works great just something I noticed. Wasn't sure if this was bug or a feature 8)
Thanx again.
crichton
12-01-2002, 07:13 PM
Kimbler,
I too recieve the errors in Windows 98SE and I compiled twice with two clean projects. --- Whereas the hoihoi code has worked for me when compiled with MingW. I agree that Win98SE is no longer a development environment yet I appreciate any assistance.
cheese_poker
12-01-2002, 10:21 PM
FirstBorn,
I am having what sounds like an identical problem. I have GPS functionality, but no full decode.
I got TCPDUMP working on my Linux machine, and I am not seeing any UDP packet from my windows machine.
Does anyone know anything to try now? It seems as though the windows machine (the key sniffer) is not sending the key across to the SEQ box.
Dedpoet
12-02-2002, 09:45 AM
What ports are you guys using for sending your key? Are they greater than 10000?
cheese_poker
12-02-2002, 11:31 AM
I was using port 10000.
I kind of gave up on the llc-win32 solution and moved to the hoihoi MinGW one. That one sends packets at port 10000 (and 55555) but my SEQ does not decode the "unknown" spawns still. TCPDUMP sees UDP packets, size 8 (bytes?).
Bleh. I am learning more about the TCPDUMP tool, but not much about why SEQ isn't seing the packets.
FirstBorn
12-02-2002, 04:52 PM
Dedpoet,
I have used a few different UDP ports, 12500, 10000, 15000. none have worked with this code, even though the "older" sniffer works fine on at least 2 of these ports (didn't really try any more than 2)
I'm going to try compiling under MS Visual C/C++ and see if that makes a difference.
I am open to other suggestions if anyone has any though.
I'll let you know the results of my MS compile (it may be a couple of days until I can get an MS compiler from work)
Thanks,
FirstBorn
Puppit
12-02-2002, 08:02 PM
I've had pretty good luck with Win Xp Pro using a linux - Xp wired ethernet connection on a DHCP server than runs my wired/wireless network from a Linksys WAP router. I have been using port 10002 and compiled Mr Spock/Maggotboys code using lcc without problem - I do have to change the "hook" file to address the correct IP assignments - so I check the DHCP server for the current IP addresses each time I log on. Most of my problems have resulted from <doh> forgetting to change the IP address on either the XP or Linux side. Dont know if this helps at all.
Dedpoet
12-03-2002, 09:00 AM
Sorry, FirstBorn. All I can really tell you about my experience with a sniffer is that I compiled Maggotboy's latest code with MSVC++ 6, Service Pack 1 and am running in on Windows XP, Service Pack 1. I am using a random, odd numbered port above 40000 and both my monitored EQ box and my Linux Seq box are on DHCP, but almost always have the same addresses. I can't help much more than that, but that is what is working for me. It worked flawlessly the first time. My guess would be as yours is, use the MS compiler when you can and give that a shot.
JuiCe
12-03-2002, 03:43 PM
I probably did something wrong, but here's the errors I got when compiling with Wedit Win32 v3.3:
msd.obj .text: undefined reference to '_inet_addr@4'
msd.obj .text: undefined reference to '_htons@4'
Molly
12-03-2002, 06:36 PM
i used showeq a long time ago before it was apart of sourceforge and it worked great. i just reactivated my eq account and of course want to use this again.
i have installed 7.2 followed the INSTALL.newbie guide perfectly. I first tried the KeyRing code, and the GPS and my stats should show up in SEQ but all the mobs where unknown. I take it this means the decoder isnt working. I see that the SEQ box is recieveing data and the key from my windows box. so, i look and find this guild. i followed it, named my own program, run it, and it does the same thing. passes the key, shows me with the GPS but all the mobs are unknown.
I use LLC to compile and im running WinXP.
If someone gets a solution to the unknown problem id be really interested :)
Molly
12-03-2002, 07:02 PM
i also noticed the md5sums for libEQ.a were not current, so i updated the file, checked the sums, and i had lastest, tried again and same luck. excat same thing happens
MisterSpock
12-03-2002, 07:33 PM
JuiCe -- make sure you have wsock32.lib included in the list for the linker. Looks like it can't find the symbols for the TCP/IP routines.
Mr. Suspicious
12-03-2002, 07:51 PM
i also noticed the md5sums for libEQ.a were not current, so i updated the file, checked the sums, and i had lastest, tried again and same luck. excat same thing happens
And what do you do everytime you update the LibEQ.a?
RECOMPILE ShowEQ
FirstBorn
12-03-2002, 08:16 PM
OK, Fantastic news! After recompiling the code under MS Visual C/C++ it worked flawlessly.
I still had to zone before I got decode, but after that it worked perfectly.
The DLL is a little bigger than the one compiled under LCC, 36KB MS VC++ compared to 8KB under LCC, but thats nothing.
My only recommendation to those having trouble with the LCC version is to try your luck with another compiler, I know thats not the best news, but it worked for me.
Thanks a million to everyone involved with this code and SEQ!
Good luck,
FirstBorn
MisterSpock
12-03-2002, 09:33 PM
FirstBorn,
LCC is undeniably a twitchy compiler. When it works, it does seem to produce very compact code. However, as you've seen, getting it to behave can be quite a challenge!
Molly
12-03-2002, 09:37 PM
Mr. Suspicious, per your suggestion i did recompile showeq again which went smoothly. I started up the key sniifer, the showeq then the game. seq picked up the key and began decoding, but the same as before. It shows me GPS, but everything else is unknown. and i tried zoning a few times and the same thing. always had the right map, i could see the traffic from eq and the key was picked up, but no decoding :(
im open to more suggestions.
Im running RH 7.2
Mr. Suspicious
12-03-2002, 09:54 PM
I started up the key sniifer, the showeq then the game. seq picked up the key and began decoding, but the same as before. It shows me GPS, but everything else is unknown. and i tried zoning a few times and the same thing. always had the right map, i could see the traffic from eq and the key was picked up, but no decoding
If you only see GPS, then ShowEQ did decrypt Nuttin! Char information and your position and heading on the map, aswell as the information what zone you are in (to determine what map to display) are not encrypted.
If this is what makes you think that the key is picked up by ShowEQ, then rethink: because if ShowEQ picked up the key you would see the mobs / corpses etc. Your initial assumption "seq picked up the key" is wrong.
My money is on:
1) You are not sending the key to ShowEQ (might be your firewall is blocking the traffic)
2) You are sending the key, but to another place *port* then the one you've specified in ShowEQ.
Molly
12-03-2002, 10:29 PM
thanks for the feedback, atleast these problems are making sense. I will double check all my settings. Also, I have been setting the UDP port to listen on inside the ShowEQ Program. Once i set it, i get set_decoder_key: User specified key port:10228
is that the best way to set the port or should it be set somewhere else?
Molly
12-03-2002, 10:32 PM
ahh, there we go, thats the showeq i remember and love.
thanks for the help. i opened showeq, set the port, went to the key sniffer set the ip and port again, saved, start the sniifer, then started eq and all is good :)
i have been working on this since 10am this morning. installed linux a few times, getting all the packages. :P
thanks again
Molly
12-04-2002, 12:41 AM
well, im not using this method but rather the keyring to send over the session key but after zoning it seq does not get the new session key thus does not decode anything.
JuiCe
12-04-2002, 05:07 AM
Under Compiler -> Settings -> Linker Settings there is a field for additional files to be included in the link. I entered wsock32.lib in this field and it compiled without a problem. The file size is 28KB.
JuiCe
12-04-2002, 05:11 AM
I just found that the Generate debug info checkbox had rechecked itself before I compiled the DLL. After unchecking the box, the file size is 8KB.
FirstBorn
12-04-2002, 04:38 PM
Something else I just noticed and thought I'd share with everyone is when I ran the DLL that I compiled under LCC I had problems with it and some of the other drivers that my system was loading on boot-up, mouse drivers for instance, and had to disable them before loading the DLL or crash on a key press afterwards.
The MS VC++ version of the DLL is not causing these problems and runs without comprimising any of the other drivers I have running.
Thought it was worth mentioning.
Good luck to everyone,
Firstborn
cgi-bin
12-05-2002, 01:35 AM
Thought I'd give this a shot. Downloaded the lcc version zip file for the .def and cut an pasted Darkgrue's version into a .c file.
made the recommended modifications to function names... compiled with no problems. Copied to system32 dir.
entered the command into the start->Run box ... used the new offeset (0x0078BCB8) posted today.
Started ShowEQ, changed the port to the one I wanted.
Fired up EQ.
First attempt I crashed right before char select... hmm strange. anyway... rebooted the system for good measure and tried again.
This time EQ loads fine, but no decode... ok hmm... I zone for shits an giggles.... watching my xterm window for seq messages. See message about "Decrypting and dispatching with key: 0xffffffff12ad4dfe" ... so close... I'd read that getting the f's is not good, but at least it seems to be trying.
Logged out and looked though boards again... verified SEQ and libEQ.a are correct versions... tried again.
Watching xterm more closely... when I get to screen to push connect (before you enter user & pw) I see it gets a key of all zeros. I log in... when I get to character select I get another key which actually looked good (no ff's). Enter world... no decode. Zone... another good looking key ... but seq goes nuts... zone blows up... ie. the mapped area shinks really tiny like spawns are popping way out of normal X:Y. xterm shows errors like:
ProcessPacket() Inflate Error: inflateRes=-3 msg=unknown compression method
also see msg=incorrect header check
also see: WARNING: Decoded NewSpawnCode(6b42) (datalen:167 != sizeof(newSpawnStruct):226)
Anyway... I looked to see if anyone had posted anything new in the dev forum about new data sizes, but nothing.
Any ideas? I seem to be pretty close to working, just something is minorly fubared :(
Thanks!
OrangePeelBeef
12-05-2002, 01:52 PM
That sounds like exactly what happens when you send the wrong key to SEQ. It could also happen if your LibEQ.a is not the newest or if they changed the encryption scheme with the patch. So if nobody else is having problems, I would assume its just not snagging the correct key. Verify your offset or use the offset finder to locate it yourself. Obviously the sniffer is sending what it thinks is the key to your seq box. Make sure you are pointing at eqgame.exe and using the correct offset.
cgi-bin
12-06-2002, 12:04 PM
Even though I had 4.3.3 and the most recent libEQ.a I re-compiled, and everything seems to be working fine now. I've gotten one or 2 zone blow-ups, but that happend occasionally before anyway.
I think I got the new libEQ after I compiled last time. I didn't realize you had to have the libEQ before compile, I thought it was like a shared library where it could change w/o having to re-compile.
eqhunter
12-10-2002, 10:32 PM
getting the error using LCC
Entry point DllMain not found
Use the -entry command line option
Help please... read just about everything... if its out there please flame... but please tell me my mistake
Hunter
MisterSpock
12-11-2002, 07:21 AM
This sounds like a problem with the entry point definition in the linker. If you used the v.1.1 code, the entry point is named LibMain.
The lcc linker front-end defaults to LibMain. If you have changed this, but not changed the code, this will be a problem.
Powered by vBulletin® Version 4.1.9 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.