Don't laugh, its a work in progress and I have just got it to work, but it seems effective. I got gotos and shit lol. Also, the binary scan isn't randomly selected. It was carefully crafted by analyzing the usage of said pointers in the disassembled version and I am pretty confident they should always work. The vector scans kind of depend on certain things being the first in line, so modified raw will screw with it but I will address that later once I get an actual release out again.
I'll dump the whole source of my project when I am done. I figured out how to do everything I want to do now, so it shouldn't take too long.
void MainWindow::attach()
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof (PROCESSENTRY32);
const HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(hProcessSnap, &pe32))
{
do
{
if (wcsicmp(TEXT("Dwarf Fortress.exe"), pe32.szExeFile) == 0)
{
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
const HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe32.th32ProcessID);
if (Module32First(hSnapShot, &me32))
{
do
{
if (wcsicmp(TEXT("Dwarf Fortress.exe"), me32.szModule) == 0)
{
dfsize = (uint32_t)me32.modBaseSize;
dfbase = (uint32_t)me32.modBaseAddr;
hDF = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pe32.th32ProcessID);
CloseHandle(hSnapShot);
CloseHandle(hProcessSnap);
goto dffound;
}
} while (Module32Next (hSnapShot, &me32));
}
CloseHandle(hSnapShot);
}
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
actionLog("Unable to find Dwarf Fortress.exe!");
return;
dffound:
actionLog(QString("Dwarf Fortress.exe found at 0x" % (QString::number(dfbase,16)) % " with a size of " %
QString::number(dfsize) % " bytes."));
const uint8_t * __restrict memory8 = (uint8_t*)malloc(dfsize);
const uint32_t * __restrict memory32 = (uint32_t*)memory8;
ReadProcessMemory(hDF, (void *)dfbase, (void *)memory8, dfsize, 0);
uint32_t *dfvector = 0;
uint32_t trash = 0;
char className[256] = {0};
char *string = 0;
uint32_t strsize = 0;
uint32_t strmode = 0;
uint32_t size = 0;
for (unsigned int a = 0; a < ((dfsize/4)-100); a++)
{
//
const uint32_t vectorBase = *(memory32+a);
const uint32_t vectorPos = *(memory32+a+1);
const uint32_t vectorCap = *(memory32+a+2);
const uint32_t vectorNull = *(memory32+a+3);
if (vectorNull != 0) goto vectorsearchdone;
if (vectorBase == 0) goto vectorsearchdone;
if (vectorPos == 0) goto vectorsearchdone;
if (vectorCap == 0) goto vectorsearchdone;
if ((vectorBase % 4) != 0) goto vectorsearchdone;
if ((vectorPos % 4) != 0) goto vectorsearchdone;
if ((vectorCap % 4) != 0) goto vectorsearchdone;
if (vectorBase > vectorPos) goto vectorsearchdone;
if (vectorBase > vectorCap) goto vectorsearchdone;
if (vectorPos > vectorCap) goto vectorsearchdone;
size = vectorPos - vectorBase;
if (size > 100000) goto vectorsearchdone;
if (size == 0) goto vectorsearchdone;
dfvector = (uint32_t *) malloc(size);
if(ReadProcessMemory(hDF, (void *)vectorBase, (void *)dfvector, size, 0))
{
trash = 0;
className[0] = '\0';
for (uint32_t c = 0; c < (size / 4); c++)
{
if(!ReadProcessMemory(hDF, (void *)*(dfvector+c), (void *)&trash, 4, 0))
{
free ((uint32_t *)dfvector);
goto vectorsearchdone;
}
}
strsize = readDWord(*(dfvector) + 0x10);
strmode = readDWord(*(dfvector) + 0x14);
if (strsize > 255)
{
free ((uint32_t *)dfvector);
goto vectorsearchdone;
}
if (strmode == 0x0F)
{
ReadProcessMemory(hDF, (void *)*(dfvector), (void *)&className, strsize, 0);
className[strsize] = '\0';
}
if (strmode == 0x1F)
{
ReadProcessMemory(hDF, (void *)*(dfvector), (void *)&trash, 4, 0);
ReadProcessMemory(hDF, (void *)trash, (void *)&className, strsize, 0);
className[strsize] = '\0';
}
if ((inorganicPointer == 0) && (strcmp(className,"IRON") == 0))
{
inorganicPointer = (a*4) + dfbase;
actionLog("Inorganic Pointer Found: " % QString::number(inorganicPointer, 16));
for (trash = 0; trash < (size / 4); trash++)
{
string = readSTLString(*(dfvector+trash));
inorganicMaterials.push_back(QString(string));
free (string);
}
}
if ((organicAllPointer == 0) && ((strcmp(className,"MEADOW-GRASS") == 0) || (strcmp(className,"MUSHROOM_HELMET_PLUMP") == 0)))
{
organicAllPointer = (a*4) + dfbase;
actionLog("Organic All Pointer Found: " % QString::number(organicAllPointer, 16));
for (trash = 0; trash < (size / 4); trash++)
{
string = readSTLString(*(dfvector+trash));
organicMaterials.push_back(QString(string));
free (string);
}
}
if ((organicPlantPointer == 0) && (strcmp(className,"MUSHROOM_HELMET_PLUMP") == 0))
{
organicPlantPointer = (a*4) + dfbase;
actionLog("Organic Plant Pointer Found: " % QString::number(organicPlantPointer, 16));
}
if ((organicTreePointer == 0) && (strcmp(className,"MANGROVE") == 0))
{
organicTreePointer = (a*4) + dfbase;
actionLog("Organic Tree Pointer Found: " % QString::number(organicTreePointer, 16));
}
if ((creatureTypePointer == 0) && (strcmp(className,"TOAD") == 0))
{
creatureTypePointer = (a*4) + dfbase;
actionLog("Creature Type Pointer Found: " % QString::number(creatureTypePointer, 16));
for (trash = 0; trash < (size / 4); trash++)
{
string = readSTLString(*(dfvector+trash));
creatureTypes.push_back(QString(string));
free (string);
}
}
if ((reactionPointer == 0) && (strcmp(className,"TAN_A_HIDE") == 0))
{
reactionPointer = (a*4) + dfbase;
actionLog("Reaction Pointer Found: " % QString::number(reactionPointer, 16));
for (trash = 0; trash < (size / 4); trash++)
{
string = readSTLString(*(dfvector+trash));
reactionTypes.push_back(QString(string));
free (string);
}
}
free ((uint32_t *)dfvector);
actionLog("Possible vector found at: " % QString::number((a*4)+dfbase,16) % " Dwarf Fortress.exe+0x" % QString::number(a*4,16) % " (0x" %
QString::number((a*4)+0x400000,16) %") size: " % QString::number(size/4) % " " % QString(className));
}
else
{
free ((uint32_t *)dfvector);
}
vectorsearchdone:
// not a bug here, the stuff we're looking for is always in the first 1/4th of memory space while vectors can be found later
if ((memory8[a] == 0x8b) && (memory8[a+1] == 0x15) && (memory8[a+6] == 0x8b) && (memory8[a+7] == 0x34) &&
(memory8[a+8] == 0x8a) && (memory8[a+9] == 0x85) && (memory8[a+10] == 0xf6) && (memory8[a+11] == 0x74) &&
(memory8[a+12] == 0x0f) && (memory8[a+13] == 0xe8))
{
managerPointer = *((uint32_t*)(memory8+a+2));
actionLog("Manager Pointer Found: " % QString::number(managerPointer, 16));
}
if ((memory8[a] == 0x2b) && (memory8[a+1] == 0x35) && (memory8[a+6] == 0x57) && (memory8[a+7] == 0xc1) &&
(memory8[a+8] == 0xfe) && (memory8[a+9] == 0x02) && (memory8[a+10] == 0x4e) && (memory8[a+11] == 0x78) &&
(memory8[a+12] == 0x20) && (memory8[a+13] == 0xbf))
{
itemPointer = *((uint32_t*)(memory8+a+2));
actionLog("Item Pointer Found: " % QString::number(itemPointer, 16));
}
}
free((uint8_t *)memory8);
if (managerPointer && itemPointer && inorganicPointer && organicAllPointer && organicPlantPointer && organicTreePointer &&
creatureTypePointer && reactionPointer)
{
actionLog("All vectors successfully found!");
}
else
{
actionLog("Failure finding all vectors! :(");
}
otherMaterials.push_back("INORGANIC");
otherMaterials.push_back("AMBER");
otherMaterials.push_back("CORAL");
otherMaterials.push_back("GLASS_GREEN");
otherMaterials.push_back("GLASS_CLEAR");
otherMaterials.push_back("GLASS_CRYSTAL");
otherMaterials.push_back("WATER");
otherMaterials.push_back("COAL");
otherMaterials.push_back("POTASH");
otherMaterials.push_back("ASH");
otherMaterials.push_back("PEARLASH");
otherMaterials.push_back("LYE");
otherMaterials.push_back("MUD");
otherMaterials.push_back("VOMIT");
otherMaterials.push_back("SALT");
otherMaterials.push_back("FILTH_B");
otherMaterials.push_back("FILTH_Y");
otherMaterials.push_back("UNKNOWN_SUBSTANCE");
otherMaterials.push_back("GRIME");
otherMaterials.push_back("CREATURE_1");
return;
}