// fix render path selection void PatchRenderPath(void) { // 0 none // 1 1x // 2 2 // 3 2a (96) // 4 2b (96) // 5 2a // 6 2b // 7 3 #if RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525 for(UInt32 i = 0; i < 6; i++) SafeWrite8(0x00B4F94D + i, 0x90); // nop SafeWrite32(0x00B4F953 + 6, 7); // render path goes here #elif RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525ng for(UInt32 i = 0; i < 6; i++) SafeWrite8(0x00B4FCBD + i, 0x90); // nop SafeWrite32(0x00B4FCC3 + 6, 7); // render path goes here #else #error #endif }
static void FixEditorFont(void) { // try something nice, otherwise fall back on SYSTEM_FIXED_FONT fontHandle = CreateFontIndirect(&kLucidaConsole9); if(fontHandle) { fontInfo = kLucidaConsole9; } else { fontHandle = GetStockObject(SYSTEM_FIXED_FONT); GetObject(fontHandle, sizeof(fontInfo), &fontInfo); } #if CS_VERSION == CS_VERSION_1_0 UInt32 basePatchAddr = 0x004F4491; #elif CS_VERSION == CS_VERSION_1_2 UInt32 basePatchAddr = 0x004FEAB9; #else #error unhandled cs version #endif SafeWrite8(basePatchAddr + 0, 0xFF); SafeWrite8(basePatchAddr + 1, 0x15); SafeWrite32(basePatchAddr + 2, (UInt32)&pModScriptWindow); SafeWrite8(basePatchAddr + 6, 0x90); }
bool Cmd_OutputLocalMapPicturesOverride_Execute(COMMAND_ARGS) { UInt8 oldGrids = *(SInt8*)kuGridsSquareAddr; bool bDoHook = (sGridsToLoad_Override != -1); if (bDoHook) { // temporarily modify uGridToLoad //*kuGridsSquareAddr = sGridsToLoad_Override; SafeWrite8(kuGridsSquareAddr, sGridsToLoad_Override); // install hook // not needed WriteRelJump(kOLMPPatchAddr, (UInt32)&GridCellArray_GetGridEntry_Hook); } Cmd_OutputLocalMapPictures_Execute(PASS_COMMAND_ARGS); if (bDoHook) { // restore original uGridsToLoad //*kuGridsToLoadAddr = oldGrids; SafeWrite8(kuGridsSquareAddr, oldGrids); // uninstall hook // not needed WriteRelCall(kOLMPPatchAddr, kGridCellArray_GetGridEntry); } return true; }
void PatchEndOfLineCheck(bool bDisableCheck) { if (bDisableCheck) SafeWrite8(kEndOfLineCheckPatchAddr, 0xEB); // unconditional (short) jump else SafeWrite8(kEndOfLineCheckPatchAddr, 0x73); // conditional jnb (short) }
void PatchEndOfLineCheck(bool bDisableCheck) { if (bDisableCheck) WriteRelJump(kEndOfLineCheckPatchAddr, kEndOfLineCheckJumpAddr); else { SafeWrite8(kEndOfLineCheckPatchAddr, 0x0F); SafeWrite8(kEndOfLineCheckPatchAddr + 1, 0x83); SafeWrite32(kEndOfLineCheckPatchAddr + 2, kEndOfLineCheckJumpDelta); } }
static void FixErrorReportBug(void) { // bethesda passes strings containing user input to printf-like functions // this causes crashes when the user input contains tokens printf is interested in // so we fix it // move the entire block of code before the call to printf down, add a new argument pointing to "%s" const UInt32 kBlockMoveDelta = 5; #error const UInt32 kBlockMoveSrc = 0x00500001; // inside ShowCompilerError, one past last referebnce #error const UInt32 kBlockMoveDst = kBlockMoveSrc + kBlockMoveDelta; #error const UInt32 kBlockMoveSize = 0x00500035 - kBlockMoveSrc; #error const UInt32 kFormatStrPos = 0x0092BBE4; // "%s" #error const UInt32 kStackFixupPos = 0x0B + 2; #error const UInt32 kPCRelFixups[] = { 0x00 + 1, 0x06 + 1, 0x28 + 1 }; UInt8 tempBuf[kBlockMoveSize]; memcpy(tempBuf, (void *)kBlockMoveSrc, kBlockMoveSize); // jumps/calls are pc-relative, we're moving code so fix them up *((UInt32 *)&tempBuf[kPCRelFixups[0]]) -= kBlockMoveDelta; *((UInt32 *)&tempBuf[kPCRelFixups[1]]) -= kBlockMoveDelta; *((UInt32 *)&tempBuf[kPCRelFixups[2]]) -= kBlockMoveDelta; // added a new arg, so we need to clean it off the stack tempBuf[kStackFixupPos] += 4; SafeWriteBuf(kBlockMoveDst, tempBuf, kBlockMoveSize); SafeWrite8(kBlockMoveSrc + 0, 0x68); // push "%s" SafeWrite32(kBlockMoveSrc + 1, kFormatStrPos); }
UInt32 WriteRelCall(UInt32 jumpSrc, UInt32 jumpTgt) { // call rel32 SafeWrite8(jumpSrc, 0xE8); jumpSrc += 1; UInt32 oldTgt = SafeWrite32(jumpSrc, jumpTgt - jumpSrc - 4); return jumpSrc + oldTgt + 4; }
UInt32 WriteRelJump(UInt32 jumpSrc, UInt32 jumpTgt) { // jmp rel32 SafeWrite8(jumpSrc, 0xE9); jumpSrc += 1; UInt32 oldTgt = SafeWrite32(jumpSrc, jumpTgt - jumpSrc - 4); return jumpSrc + oldTgt + 4; }
void _stdcall RegAnimCombatCheck(DWORD newValue) { char oldValue = reg_anim_combat_check; reg_anim_combat_check = (newValue > 0); if (oldValue != reg_anim_combat_check) { SafeWrite8(0x459C97, reg_anim_combat_check); // reg_anim_func SafeWrite8(0x459D4B, reg_anim_combat_check); // reg_anim_animate SafeWrite8(0x459E3B, reg_anim_combat_check); // reg_anim_animate_reverse SafeWrite8(0x459EEB, reg_anim_combat_check); // reg_anim_obj_move_to_obj SafeWrite8(0x459F9F, reg_anim_combat_check); // reg_anim_obj_run_to_obj SafeWrite8(0x45A053, reg_anim_combat_check); // reg_anim_obj_move_to_tile SafeWrite8(0x45A105, reg_anim_combat_check); // reg_anim_obj_run_to_tile SafeWrite8(0x45AE53, reg_anim_combat_check); // reg_anim_animate_forever } }
void Hook_Script_Init() { WriteRelJump(ExtractStringPatchAddr, (UInt32)&ExtractStringHook); // patch the "apple bug" // game caches information about the most recently retrieved RefVariable for the current executing script // if same refIdx requested twice in a row returns previously returned ref without // bothering to check if form stored in ref var has changed // this fixes it by overwriting a conditional jump with an unconditional one SafeWrite8(kResolveRefVarPatchAddr, 0xEB); // game also caches information about the most recently retrieved local numeric variable for // currently executing script. Causes issues with function scripts. As above, overwrite conditional jump with unconditional SafeWrite8(kResolveNumericVarPatchAddr, 0xEB); // hook code in the vanilla expression parser's subroutine to fix the buffer overflow WriteRelJump(kExpressionParserBufferOverflowHookAddr_1, (UInt32)&ExpressionParserBufferOverflowHook_1); WriteRelJump(kExpressionParserBufferOverflowHookAddr_2, (UInt32)&ExpressionParserBufferOverflowHook_2); // hook ExtractArgs() to handle commands normally compiled with Cmd_Default_Parse which were instead compiled with Cmd_Expression_Parse ExtractArgsOverride::Init_Hooks(); }
void GameplayPatches(void) { // originally supposed to be 100 /decimal/ but oops UInt8 kPickpocketChance[] = { 0xB8, 0x00, 0x01, 0x00, 0x00, // mov eax, 0x0100 0xC3 // retn }; ApplyPatch(0x00598DB0, kPickpocketChance, sizeof(kPickpocketChance)); SafeWrite8(0x008F0850, 0xC3); // disable achievements }
void __stdcall ToggleOverride(bool bOverride) { static const UInt32 patchLoc = 0x005C67E0; // editor default parse routine (g_defaultParseCommand in CommandTable) (F3:0x005C01F0) // ToggleOverride() only gets invoked when we parse a begin or end statement, so set mode accordingly s_currentMode = kOverride_BlockType; // overwritten instructions static const UInt8 s_patchedInstructions[5] = { 0x81, 0xEC, 0x30, 0x02, 0x00 }; // same first five bytes as Oblivion if (bOverride) { WriteRelJump(patchLoc, (UInt32)&Hook_Cmd_Default_Parse); } else { for (UInt32 i = 0; i < sizeof(s_patchedInstructions); i++) { SafeWrite8(patchLoc+i, s_patchedInstructions[i]); } } }
// fix dinput code so it doesn't acquire the keyboard/mouse in exclusive mode // bBackground Mouse works on startup, but when gaining focus that setting is ignored // there's probably a better way to fix the bug but this is good enough void PatchCoopLevel(void) { #if RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525 SafeWrite8(0x00A227A1 + 1, 0x16); SafeWrite8(0x00A229CB + 1, 0x06); SafeWrite8(0x00A23CAD + 1, 0x06); #elif RUNTIME_VERSION == RUNTIME_VERSION_1_4_0_525ng SafeWrite8(0x00A22371 + 1, 0x16); SafeWrite8(0x00A2259B + 1, 0x06); SafeWrite8(0x00A2387D + 1, 0x06); #else #error #endif }
void AnimationsAtOnceInit(signed char aniMax) { if (aniMax <= 32) return; AniLimitFixActive = true; int i; //allocate memory to store larger animation struct arrays anim_set = new BYTE[2656*(aniMax+1)]; sad = new BYTE[3240*(aniMax+1)]; //set general animation limit check (old 20) aniMax-12 -- +12 reserved for PC movement(4) + other critical animations(8)? SafeWrite8(0x413C07, aniMax-12); //PC movement animation limit checks (old 24) aniMax-8 -- +8 reserved for other critical animations?. for (i = 0; i < sizeof(AnimPCMove)/4; i++) { SafeWrite8(AnimPCMove[i], aniMax-8); } //Max animation limit checks (old 32) aniMax for (i = 0; i < sizeof(AnimMaxCheck)/4; i++) { SafeWrite8(AnimMaxCheck[i], aniMax); } //Max animations checks - animation struct size * max num of animations (old 2656*32=84992) for (i = 0; i < sizeof(AnimMaxSizeCheck)/4; i++) { SafeWrite32(AnimMaxSizeCheck[i], 2656*aniMax); } //divert old animation structure list pointers to newly alocated memory //struct array 1/////////////////// //old addr 0x54C1B4 SafeWrite32(0x413A9E, (DWORD)anim_set); //old addr 0x54C1C0 for (i = 0; i < sizeof(fake_anim_set_C)/4; i++) { SafeWrite32(fake_anim_set_C[i], 12+(DWORD)anim_set); } //old addr 0x54CC14 for (i = 0; i < sizeof(anim_set_0)/4; i++) { SafeWrite32(anim_set_0[i], 2656+(DWORD)anim_set); } //old addr 0x54CC18 for (i = 0; i < sizeof(anim_set_4)/4; i++) { SafeWrite32(anim_set_4[i], 2656+4+(DWORD)anim_set); } //old addr 0x54CC1C for (i = 0; i < sizeof(anim_set_8)/4; i++) { SafeWrite32(anim_set_8[i], 2656+8+(DWORD)anim_set); } //old addr 0x54CC20 for (i = 0; i < sizeof(anim_set_C)/4; i++) { SafeWrite32(anim_set_C[i], 2656+12+(DWORD)anim_set); } //old addr 0x54CC24 for (i = 0; i < sizeof(anim_set_10)/4; i++) { SafeWrite32(anim_set_10[i], 2656+16+(DWORD)anim_set); } //old addr 0x54CC28 for (i = 0; i < sizeof(anim_set_14)/4; i++) { SafeWrite32(anim_set_14[i], 2656+20+(DWORD)anim_set); } //old addr 0x54CC38 SafeWrite32(0x413F29, 2656+36+(DWORD)anim_set); //old addr 0x54CC3C for (i = 0; i < sizeof(anim_set_28)/4; i++) { SafeWrite32(anim_set_28[i], 2656+40+(DWORD)anim_set); } //old addr 0x54CC48 SafeWrite32(0x415C35, 2656+52+(DWORD)anim_set); //struct array 2/////////////////// //old addr 0x530014 for (i = 0; i < sizeof(sad_0)/4; i++) { SafeWrite32(sad_0[i], (DWORD)sad); } //old addr 0x530018 for (i = 0; i < sizeof(sad_4)/4; i++) { SafeWrite32(sad_4[i], 4+(DWORD)sad); } //old addr 0x53001C for (i = 0; i < sizeof(sad_8)/4; i++) { SafeWrite32(sad_8[i], 8+(DWORD)sad); } //old addr 0x530020 for (i = 0; i < sizeof(sad_C)/4; i++) { SafeWrite32(sad_C[i], 12+(DWORD)sad); } //old addr 0x530024 for (i = 0; i < sizeof(sad_10)/4; i++) { SafeWrite32(sad_10[i], 16+(DWORD)sad); } //old addr 0x530028 for (i = 0; i < sizeof(sad_14)/4; i++) { SafeWrite32(sad_14[i], 20+(DWORD)sad); } //old addr 0x53002C for (i = 0; i < sizeof(sad_18)/4; i++) { SafeWrite32(sad_18[i], 24+(DWORD)sad); } //old addr 0x530030 for (i = 0; i < sizeof(sad_1C)/4; i++) { SafeWrite32(sad_1C[i], 28+(DWORD)sad); } //old addr 0x530034 for (i = 0; i < sizeof(sad_20)/4; i++) { SafeWrite32(sad_20[i], 32+(DWORD)sad); } //old addr 0x530038 for (i = 0; i < sizeof(sad_24)/4; i++) { SafeWrite32(sad_24[i], 36+(DWORD)sad); } //old addr 0x53003A SafeWrite32(0x416903, 38+(DWORD)sad); //old addr 0x53003B for (i = 0; i < sizeof(sad_27)/4; i++) { SafeWrite32(sad_27[i], 39+(DWORD)sad); } //old addr 0x53003C for (i = 0; i < sizeof(sad_28)/4; i++) { SafeWrite32(sad_28[i], 40+(DWORD)sad); } }
void SafeWriteCall(uint32_t src, uint32_t tgt) { SafeWrite8(src, 0xE8); SafeWrite32(src + 1, tgt - src - 1 - 4); }
void WriteRelCall(UInt32 jumpSrc, UInt32 jumpTgt) { // call rel32 SafeWrite8(jumpSrc, 0xE8); SafeWrite32(jumpSrc + 1, jumpTgt - jumpSrc - 1 - 4); }
void MakeCall(DWORD addr, void* func, bool jump) { SafeWrite8(addr, jump?0xe9:0xe8); HookCall(addr, func); }
void ApplyPatch(UInt32 base, UInt8 * buf, UInt32 len) { for(UInt32 i = 0; i < len; i++) SafeWrite8(base + i, buf[i]); }
void SafeWriteJump(uint32_t src, uint32_t tgt) { SafeWrite8(src, 0xE9); SafeWrite32(src + 1, tgt - src - 1 - 4); }
void WriteRelJump(UInt32 jumpSrc, UInt32 jumpTgt) { // jmp rel32 SafeWrite8(jumpSrc, 0xE9); SafeWrite32(jumpSrc + 1, jumpTgt - jumpSrc - 1 - 4); }