// Searches for predetermined patterns discovered through debugging // in the file_data (of Engine.dll), and replaces them with new values // to provide the changed physics behaviour // The patterns and replacements are all defined in pattern.h bool PatchMemory(PBYTE file_data, const size_t file_size, PatchType type) { // Find the file position of the y force pattern size_t up_match = PatternSearch(file_data, file_size, kUpForce, sizeof(kUpForce), kUpForceMask); // Find the file position of the physics cap pattern size_t cap_match = PatternSearch(file_data, file_size, kForceCap, sizeof(kForceCap), kForceCapMask); if (!up_match || !cap_match) { return false; } // memcpy is called with search patterns instead of predefined replacements // when it makes sense to ensure memory blocks are at their default values switch (type) { case kSuperRocketRagdolls: memcpy(file_data+up_match, kUpForceRocket, sizeof(kUpForceRocket)); memcpy(file_data+cap_match, kForceCapRocket, sizeof(kForceCapRocket)); break; case kSuperFlyingBodies: memcpy(file_data+up_match, kUpForce, sizeof(kUpForce)); memcpy(file_data+cap_match, kForceCapSuperFlying, sizeof(kForceCapSuperFlying)); break; case kLesserFlyingBodies: memcpy(file_data+up_match, kUpForce, sizeof(kUpForce)); memcpy(file_data+cap_match, kForceCapLesserFlying, sizeof(kForceCapLesserFlying)); break; case kOriginal: memcpy(file_data+up_match, kUpForce, sizeof(kUpForce)); memcpy(file_data+cap_match, kForceCap, sizeof(kForceCap)); break; default: return false; break; } return true; }
void* PatternSearchModule(module_info_t* module, const char* pattern, const char* mask) { void* res = NULL; for (int i = 0; i < module->entries; i++) { if (!(module->permissions[i] & PG_READ)) continue; size_t size = module->address_end[i] - module->address_start[i]; res = PatternSearch((void*)module->address_start[i], size, pattern, mask); if (res) break; } return res; }
// NOTE: Some functions can easily and reliably be found on the VM_Call table instead. void SearchVmFunctions(void) { int failed = 0; // For some reason, the module doesn't show up when reading /proc/self/maps. // Perhaps this needs to be called later? In any case, we know exactly where // the module is mapped, so I think this is fine. If it ever breaks, it'll // be trivial to fix. G_AddEvent = (G_AddEvent_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_G_ADDEVENT, MASK_G_ADDEVENT); if (G_AddEvent == NULL) { DebugPrint("ERROR: Unable to find G_AddEvent.\n"); failed = 1; } else DebugPrint("G_AddEvent: %p\n", G_AddEvent); CheckPrivileges = (CheckPrivileges_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_CHECKPRIVILEGES, MASK_CHECKPRIVILEGES); if (CheckPrivileges == NULL) { DebugPrint("ERROR: Unable to find CheckPrivileges.\n"); failed = 1; } else DebugPrint("CheckPrivileges: %p\n", CheckPrivileges); ClientConnect = (ClientConnect_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_CLIENTCONNECT, MASK_CLIENTCONNECT); if (ClientConnect == NULL) { DebugPrint("ERROR: Unable to find ClientConnect.\n"); failed = 1; } else DebugPrint("ClientConnect: %p\n", ClientConnect); ClientSpawn = (ClientSpawn_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_CLIENTSPAWN, MASK_CLIENTSPAWN); if (ClientSpawn == NULL) { DebugPrint("ERROR: Unable to find ClientSpawn.\n"); failed = 1; } else DebugPrint("ClientSpawn: %p\n", ClientSpawn); G_Damage = (G_Damage_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_G_DAMAGE, MASK_G_DAMAGE); if (G_Damage == NULL) { DebugPrint("ERROR: Unable to find G_Damage.\n"); failed = 1; } else DebugPrint("G_Damage: %p\n", G_Damage); Touch_Item = (Touch_Item_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_TOUCH_ITEM, MASK_TOUCH_ITEM); if (Touch_Item == NULL) { DebugPrint("ERROR: Unable to find Touch_Item.\n"); failed = 1; } else DebugPrint("Touch_Item: %p\n", Touch_Item); LaunchItem = (LaunchItem_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_LAUNCHITEM, MASK_LAUNCHITEM); if (LaunchItem == NULL) { DebugPrint("ERROR: Unable to find LaunchItem.\n"); failed = 1; } else DebugPrint("LaunchItem: %p\n", LaunchItem); Drop_Item = (Drop_Item_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_DROP_ITEM, MASK_DROP_ITEM); if (Drop_Item == NULL) { DebugPrint("ERROR: Unable to find Drop_Item.\n"); failed = 1; } else DebugPrint("Drop_Item: %p\n", Drop_Item); G_StartKamikaze = (G_StartKamikaze_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_G_STARTKAMIKAZE, MASK_G_STARTKAMIKAZE); if (G_StartKamikaze == NULL) { DebugPrint("ERROR: Unable to find G_StartKamikaze.\n"); failed = 1; } else DebugPrint("G_StartKamikaze: %p\n", G_StartKamikaze); G_FreeEntity = (G_FreeEntity_ptr)PatternSearch((void*)((pint)qagame + 0xB000), 0xB0000, PTRN_G_FREEENTITY, MASK_G_FREEENTITY); if (G_FreeEntity == NULL) { DebugPrint("ERROR: Unable to find G_FreeEntity.\n"); failed = 1; } else DebugPrint("G_FreeEntity: %p\n", G_FreeEntity); //bg_itemlist = qagame + 0x2CB8A0; bg_itemlist = (gitem_t*)PatternSearch((void*)((pint)qagame + 0x2CB000), 0xB0000, PTRN_BG_ITEMLIST, MASK_BG_ITEMLIST); if (bg_itemlist == NULL) { DebugPrint("ERROR: Unable to find bg_itemlist.\n"); failed = 1; } else { DebugPrint("bg_itemlist: %p\n", bg_itemlist); for (bg_numItems = 1; bg_itemlist[ bg_numItems ].classname; bg_numItems++); DebugPrint("bg_numItems: %d\n", bg_numItems); } if (failed) { DebugPrint("Exiting.\n"); exit(1); } }