I did this today for delmar. It is essentually a down and dirty quickfix for the WinXP/NT/2000/etc... security bullshit issue.
This hack of Mvern's great code (as it stands) waits 4 minutes, then checks for the key and writes to keyfile.dat, then rewrites it every 2.5 minutes thereafter. The trick is that you have to be at the character selection screen before it checks the first time, and you can't leave the character selection screen until it completes it's first check. Make sense? Yea, it's ugly and stupid, but...then again, this is a simple hack.
Read the comments..and no complaining, I'm not a programmer by trade
EDIT:
- Added a routine to write a small file (keyfile.log) each time that contains just the time that the keyfile.dat was last created.
Code:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>
#include <time.h>
//---------------------------------------------------------------------------
int HasDecoded = 0; // compiler compatability
HANDLE hProcessSnap = NULL;
HANDLE hProcess;
void readkey (HANDLE hProcess)
{
unsigned long addr = 0x00773b90; // on some compilers (ie, borland builder), this value must be set to 0x773b90
ULONGLONG key;
FILE *fptr_out;
FILE *fptrlog_out;
long t;
time (&t);
if ( ReadProcessMemory (hProcess, (void *)addr, &key, 8, NULL ) == 0)
printf( "ReadProcessMemory on 8 bytes at 0x%08x failed: %u\n", addr, GetLastError());
else
{
// Left this commented out for reference if needed.
// printf( "key:\t0x%016I64x\n", key );
fptr_out = fopen( "keyfile.dat", "wb");
fwrite( &key, 8, 1, fptr_out );
fclose(fptr_out);
fptrlog_out = fopen( "keyfile.log", "wb");
fwrite( ctime(&t), 20, 1, fptrlog_out );
fclose(fptrlog_out);
}
}
void scanproclist ()
{
PROCESSENTRY32 pe32 = {0};
// Take a snapshot of all processes in the system.
if (HasDecoded == 0)
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return;
// Fill in the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32))
{
do
{
LPSTR pCurChar;
char pName[512];
// strip path and leave exe filename
for (pCurChar = (pe32.szExeFile + strlen (pe32.szExeFile)); *pCurChar != '\\\' && pCurChar != pe32.szExeFile - 1; --pCurChar)
strcpy(pName, pCurChar);
strlwr(pName);
if ( (strncmp (pName, "testeqgame", 10) == 0) || (strncmp (pName, "eqgame", 6) == 0) )
{
if (HasDecoded == 0)
{
hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
HasDecoded = 1;
}
if (hProcess == NULL)
{
DWORD dw;
dw = GetLastError();
printf ("OpenProcess failed, error: %u\n", dw);
return;
}
readkey (hProcess);
}
}
while (Process32Next(hProcessSnap, &pe32));
}
return;
}
int main(int argc, char* argv[])
{
Sleep(240000); // Ok..this is the tricky value. This sniffer needs to "attach" to eqgame
// for the FIRST time at the *CHARACTER selection screen*. Therefore, as it is set
// now (at 4 minutes), you need to make sure you're at the char selection screen
// WITHIN 4 minutes, and you don't enter the game until AFTER 4 minutes.
// Make sense? :) ...once it's done it's business the first time (each session),
// it doesn't matter.
// Once you've gotten a feel for it, you can adjust this timer to what works
// best for you. (1000 = 1 second). It's a pain, but this is a simple program!
while (1)
{
scanproclist ();
Sleep(150000); // modify to be every however minutes you wish. It's currently
// set to 2.5 minutes.
}
return 0;
}