diff --git a/MK11Hook/MK11Hook.rc b/MK11Hook/MK11Hook.rc index 0d32fcd..21081ca 100644 Binary files a/MK11Hook/MK11Hook.rc and b/MK11Hook/MK11Hook.rc differ diff --git a/MK11Hook/MK11Hook.vcxproj b/MK11Hook/MK11Hook.vcxproj index 1e4f9e2..f8c7729 100644 --- a/MK11Hook/MK11Hook.vcxproj +++ b/MK11Hook/MK11Hook.vcxproj @@ -215,6 +215,7 @@ + diff --git a/MK11Hook/MK11Hook.vcxproj.filters b/MK11Hook/MK11Hook.vcxproj.filters index 8cd5c40..b20ccc7 100644 --- a/MK11Hook/MK11Hook.vcxproj.filters +++ b/MK11Hook/MK11Hook.vcxproj.filters @@ -407,6 +407,9 @@ Header Files\mk + + Header Files\plugin + diff --git a/MK11Hook/dllmain.cpp b/MK11Hook/dllmain.cpp index 70f1956..31b43d3 100644 --- a/MK11Hook/dllmain.cpp +++ b/MK11Hook/dllmain.cpp @@ -49,7 +49,7 @@ void OnInitializeHook() freopen("CONOUT$", "w", stderr); } - eLog::Message(__FUNCTION__, "INFO: MK11Hook Begin!"); + eLog::Message(__FUNCTION__, "INFO: MK11Hook (%s | %s) Begin!", MK11HOOK_VERSION, __DATE__); eLog::Message(__FUNCTION__, "INFO: Is DirectX12 - %s", IsDX12() ? "Yes" : "No"); Notifications->Init(); @@ -71,17 +71,17 @@ void OnInitializeHook() InjectHook(_pattern(PATID_CameraPositionHook), tramp->Jump(&MKCamera::HookedSetPosition)); InjectHook(_pattern(PATID_CameraRotationHook), tramp->Jump(&MKCamera::HookedSetRotation)); - InjectHook(_pattern(PATID_SetSelectScreen_Hook), tramp->Jump(SetSelectScreen_Hook), PATCH_JUMP); + InjectHook(_pattern(PATID_SetSelectScreen_Hook), tramp->Jump(SetSelectScreen_Hook), HookType::Jump); InjectHook(_pattern(PATID_SetCharacterLadder_Hook), tramp->Jump(SetCharacterLadder_Hook)); - InjectHook(_pattern(PATID_ReadPropertyValue_Hook), tramp->Jump(ReadPropertyValue_Hook), PATCH_JUMP); + InjectHook(_pattern(PATID_ReadPropertyValue_Hook), tramp->Jump(ReadPropertyValue_Hook), HookType::Jump); InjectHook(_pattern(PATID_SetProperty_Hook), tramp->Jump(SetProperty)); InjectHook(_pattern(PATID_Dispatch_Hook), tramp->Jump(Dispatch_Hook)); if (SettingsMgr->bMakeAllAbilities1Slot) - InjectHook(_pattern(PATID_1SlotAbilitiesHook), tramp->Jump(GenericTrueReturn), PATCH_JUMP); + InjectHook(_pattern(PATID_1SlotAbilitiesHook), tramp->Jump(GenericTrueReturn), HookType::Jump); InjectHook(_pattern(PATID_SetKryptCharacter_Hook), tramp->Jump(SetKryptCharacter)); InjectHook(_pattern(PATID_SetKryptCharacterL_Hook), tramp->Jump(SetKryptCharacterL)); @@ -89,7 +89,13 @@ void OnInitializeHook() ReadCall(_pattern(PATID_ProcessDOFSettings), pProcessDOFSettings); - InjectHook(_pattern(PATID_ProcessDOFSettings), tramp->Jump(ProcessDOFSettings), PATCH_CALL); + InjectHook(_pattern(PATID_ProcessDOFSettings), tramp->Jump(ProcessDOFSettings)); + + ReadCall(_pattern(PATID_FightStartupAddModifiers), pPluginFightStartupAddModifiers); + InjectHook(_pattern(PATID_FightStartupAddModifiers), tramp->Jump(PluginFightStartupAddModifiers)); + + MH_CreateHook((void*)_pattern(PATID_FightStartupQueueModifiers), &PluginFightStartupQueueModifiers, (void**)&pPluginFightStartupQueueModifiers); + MH_EnableHook((void*)_pattern(PATID_FightStartupQueueModifiers)); //gamepad if (SettingsMgr->bEnableGamepadSupport) @@ -100,7 +106,7 @@ void OnInitializeHook() uintptr_t xinput_addr = _pattern(PATID_XInputGetState_Hook); xinput_addr += *(unsigned int*)(xinput_addr)+4; - InjectHook(xinput_addr, tramp->Jump(XInputGetState_Hook), PATCH_JUMP); + InjectHook(xinput_addr, tramp->Jump(XInputGetState_Hook), HookType::Jump); } } @@ -169,6 +175,7 @@ extern "C" { __declspec(dllexport) void InitializeASI() { + MH_Initialize(); eLog::Initialize(); if (ValidateGameVersion()) diff --git a/MK11Hook/helper/eAbilityNames.cpp b/MK11Hook/helper/eAbilityNames.cpp index f5c1f83..123c601 100644 --- a/MK11Hook/helper/eAbilityNames.cpp +++ b/MK11Hook/helper/eAbilityNames.cpp @@ -620,16 +620,21 @@ void eAbiltityNames::Init() } -eAbilityNameEntry eAbiltityNames::Get(const char * chrName) +eAbilityNameEntry* eAbiltityNames::Get(const char * chrName) { - std::string input = chrName; - eAbilityNameEntry result; + std::string inName(chrName); + std::transform(inName.begin(), inName.end(), inName.begin(), std::tolower); + + eAbilityNameEntry* result = nullptr; for (unsigned int i = 0; i < m_aAbilityNames.size(); i++) { - if (m_aAbilityNames[i].chr == input) + std::string abilityName(m_aAbilityNames[i].chr); + std::transform(abilityName.begin(), abilityName.end(), abilityName.begin(), std::tolower); + + if (abilityName == inName) { - result = m_aAbilityNames[i]; + result = &m_aAbilityNames[i]; break; } } @@ -637,13 +642,23 @@ eAbilityNameEntry eAbiltityNames::Get(const char * chrName) return result; } +int eAbiltityNames::GetAmount(eAbilityNameEntry* ability) +{ + int amount = 0; + for (int i = 0; i < TOTAL_ABILITIES; i++) + if (ability->abNames[i]) + amount++; + + return amount; +} + eAbilityNameEntry::eAbilityNameEntry() { chr = "char_null"; for (int i = 0; i < TOTAL_ABILITIES; i++) { - abNames[i] = ""; + abNames[i] = nullptr; } } diff --git a/MK11Hook/helper/eAbilityNames.h b/MK11Hook/helper/eAbilityNames.h index d55784a..266aa54 100644 --- a/MK11Hook/helper/eAbilityNames.h +++ b/MK11Hook/helper/eAbilityNames.h @@ -15,6 +15,7 @@ class eAbiltityNames { public: static std::vector m_aAbilityNames; static void Init(); - static eAbilityNameEntry Get(const char* chrName); + static eAbilityNameEntry* Get(const char* chrName); + static int GetAmount(eAbilityNameEntry* ability); }; \ No newline at end of file diff --git a/MK11Hook/mk/Engine.cpp b/MK11Hook/mk/Engine.cpp index 132ff75..7e2a95f 100644 --- a/MK11Hook/mk/Engine.cpp +++ b/MK11Hook/mk/Engine.cpp @@ -104,3 +104,22 @@ void SetCharacterMKX(PLAYER_NUM plr, char* name) CharacterDefinition* chr = (CharacterDefinition*)(ptr + 216); chr->Set(name, 0, 0); } + +void SetCharacterAI(PLAYER_NUM plr, char* script, int level) +{ + PlayerInfo* info = GetInfo(plr); + + if (!info) + return; + + info->MakeDrone(); + + AIDrone* drone = info->GetDrone(); + + if (!drone) + return; + + drone->Set(script, 0); + float difficultyLevel = level; + drone->SetLevel(difficultyLevel); +} diff --git a/MK11Hook/mk/Engine.h b/MK11Hook/mk/Engine.h index f84a134..dbff22c 100644 --- a/MK11Hook/mk/Engine.h +++ b/MK11Hook/mk/Engine.h @@ -24,4 +24,5 @@ unsigned int _hash(const char* input); void GetCharacterPosition(FVector* vec, PLAYER_NUM plr); char* GetCharacterName(PLAYER_NUM plr); -void SetCharacterMKX(PLAYER_NUM plr, char* name); \ No newline at end of file +void SetCharacterMKX(PLAYER_NUM plr, char* name); +void SetCharacterAI(PLAYER_NUM plr, char* script, int level); \ No newline at end of file diff --git a/MK11Hook/mk/MKCamera.cpp b/MK11Hook/mk/MKCamera.cpp index 85cc113..6d683f8 100644 --- a/MK11Hook/mk/MKCamera.cpp +++ b/MK11Hook/mk/MKCamera.cpp @@ -263,6 +263,10 @@ void MKCamera::HookedSetRotation(FRotator * rot) rot->Pitch += 1228; TheMenu->camRot = *rot; break; + case CAMERA_9_16: + rot->Roll += (int)(float)((float)(90.0 * 32767.0) / 180.0); + TheMenu->camRot = *rot; + break; } } SetRotation(rot); diff --git a/MK11Hook/mk/MKModifier.cpp b/MK11Hook/mk/MKModifier.cpp index 9310497..4823856 100644 --- a/MK11Hook/mk/MKModifier.cpp +++ b/MK11Hook/mk/MKModifier.cpp @@ -1,4 +1,5 @@ #include "MKModifier.h" +#include "Engine.h" TagAssistModifier::TagAssistModifier(const char * character) @@ -15,26 +16,26 @@ void TagAssistModifier::Activate(PlayerInfo* info) ((void(__fastcall*)(BaseModifier*, PlayerInfo*))pat)(this, info); } -TagAssistModifierObject * TagAssistModifier::CreateObject() +Modifier* MKModifier::CreateModifier(const char* name) { - static uintptr_t pat = _pattern(PATID_TagAssistModifier_CreateObject); - if (pat) - return ((TagAssistModifierObject*(__fastcall*)(BaseModifier*))pat)(this); - return nullptr; + return new Modifier(name); } -void MKModifier::ActivateModifier(BaseModifier * modifier, MKCharacter * obj) +void MKModifier::ActivateModifier(Modifier* mod, int playerFlags) { - static uintptr_t pat = _pattern(PATID_MKModifier_ActivateModifier); - if (pat) - ((void(__fastcall*)(MKModifier*, BaseModifier*, MKCharacter*))pat)(this, modifier, obj); -} + ModifierObject obj(mod, playerFlags); -void TagAssistModifierObject::Activate(MKCharacter* obj) -{ - static uintptr_t pat = _pattern(PATID_TagAssistModifierObject_Activate); - if (pat) - ((void(__fastcall*)(TagAssistModifierObject*, MKCharacter*))pat)(this, obj); + MKCharacter* p1 = GetObj(PLAYER1); + + if (!p1) + return; + + MKCharacter* p2 = GetObj(PLAYER2); + + if (!p2) + return; + + obj.Activate(p1, p2); } MKModifier* GetModifierManager() @@ -58,4 +59,32 @@ void LoadModifierAssets() static uintptr_t pat = _pattern(PATID_LoadModifierAssets); if (pat) ((void(__fastcall*)(FGGameInfo*, bool))pat)(GetGameInfo(), 1); -} \ No newline at end of file +} + +Modifier::Modifier(const char* name) +{ + static uintptr_t pat = _pattern(PATID_MKModifier_Constructor); + if (pat) + ((void(__fastcall*)(BaseModifier*, const char*, int, int64, int64))pat)(this, name, 1, 0, 0); +} + +void Modifier::GetAssetPath(TArray& path) +{ + static uintptr_t pat = _pattern(PATID_MKModifier_GetAssetPath); + if (pat) + ((void(__fastcall*)(Modifier*, TArray&))pat)(this, path); +} + +ModifierObject::ModifierObject(Modifier* modifier, int flags) +{ + static uintptr_t pat = _pattern(PATID_MKModifierObject_Constructor); + if (pat) + ((void(__fastcall*)(ModifierObject*, BaseModifier*, int))pat)(this, modifier, flags); +} + +void ModifierObject::Activate(MKCharacter* p1, MKCharacter* p2) +{ + static uintptr_t pat = _pattern(PATID_MKModifierObject_Activate); + if (pat) + ((void(__fastcall*)(ModifierObject*, MKCharacter*, MKCharacter*))pat)(this, p1, p2); +} diff --git a/MK11Hook/mk/MKModifier.h b/MK11Hook/mk/MKModifier.h index abb79f1..646a5aa 100644 --- a/MK11Hook/mk/MKModifier.h +++ b/MK11Hook/mk/MKModifier.h @@ -1,28 +1,43 @@ #pragma once #include "../mk/MKCharacter.h" #include "../mk/PlayerInfo.h" +#include "../unreal/TArray.h" #include "../utils.h" class BaseModifier { public: - char data[96] = {}; + char data[112] = {}; }; -class TagAssistModifierObject { +class Modifier : public BaseModifier { public: - void Activate(MKCharacter* obj); + Modifier(const char* name); + + void GetAssetPath(TArray& path); }; +class ModifierObject { +public: + char data[512] = {}; + + ModifierObject(Modifier* modifier, int flags); + + void Activate(MKCharacter* p1, MKCharacter* p2); +}; + + + + class TagAssistModifier : public BaseModifier { public: TagAssistModifier(const char* character); void Activate(PlayerInfo* info); - TagAssistModifierObject* CreateObject(); }; class MKModifier { public: - void ActivateModifier(BaseModifier* modifier, MKCharacter* obj); + static Modifier* CreateModifier(const char* name); + static void ActivateModifier(Modifier* mod, int playerFlags); }; diff --git a/MK11Hook/mk/PlayerInfo.cpp b/MK11Hook/mk/PlayerInfo.cpp index 6196f8f..6b84dba 100644 --- a/MK11Hook/mk/PlayerInfo.cpp +++ b/MK11Hook/mk/PlayerInfo.cpp @@ -28,6 +28,13 @@ float PlayerInfo::GetMeter(eMeterValues type) return *(float*)(meter_ptr + 4); } +void PlayerInfo::MakeDrone() +{ + static uintptr_t pat = _pattern(PATID_PlayerInfo_MakeDrone); + if (pat) + ((void(__fastcall*)(PlayerInfo*))pat)(this); +} + HitCounter PlayerInfo::GetHits() { return *(HitCounter*)((int64)this + 0x430); @@ -47,3 +54,10 @@ void AIDrone::Set(const char* script, int unk) if (pat) ((void(__fastcall*)(AIDrone*, const char*, int))pat)(this, script, unk); } + +void AIDrone::SetLevel(float level) +{ + static uintptr_t pat = _pattern(PATID_AIDrone_SetLevel); + if (pat) + ((void(__fastcall*)(AIDrone*, float))pat)(this, level); +} diff --git a/MK11Hook/mk/PlayerInfo.h b/MK11Hook/mk/PlayerInfo.h index 1191dc3..95944df 100644 --- a/MK11Hook/mk/PlayerInfo.h +++ b/MK11Hook/mk/PlayerInfo.h @@ -46,6 +46,7 @@ struct Gamepad { class AIDrone { public: void Set(const char* script, int unk); + void SetLevel(float level); }; class PlayerInfo { @@ -58,6 +59,8 @@ class PlayerInfo { void RefreshMeter(bool value); float GetMeter(eMeterValues type); + void MakeDrone(); + HitCounter GetHits(); AIDrone* GetDrone(); diff --git a/MK11Hook/plugin/Hooks.cpp b/MK11Hook/plugin/Hooks.cpp index ffd297c..2b08df2 100644 --- a/MK11Hook/plugin/Hooks.cpp +++ b/MK11Hook/plugin/Hooks.cpp @@ -2,8 +2,9 @@ int64 hud_property = 0; -void(__fastcall* pProcessDOFSettings)(int64, int64, int64, int64) = 0; - +void(__fastcall* pProcessDOFSettings)(int64, int64, int64, int64) = nullptr; +void(*pPluginFightStartupAddModifiers)() = nullptr; +void(*pPluginFightStartupQueueModifiers)(int64, int64) = nullptr; void ProcessDOFSettings(int64 settings, int64 a2, int64 newSettings, int64 a4) { @@ -169,7 +170,10 @@ void PluginDispatch() if (TheMenu->m_bAIDroneModifierP1) { if (AIDrone* drone = p1_info->GetDrone()) + { drone->Set(TheMenu->szPlayer1AI, 0); + drone->SetLevel(TheMenu->m_nAIDroneLevelP1); + } } if (TheMenu->m_bEasyKBsP1) @@ -251,7 +255,10 @@ void PluginDispatch() if (TheMenu->m_bAIDroneModifierP2) { if (AIDrone* drone = p2_info->GetDrone()) + { drone->Set(TheMenu->szPlayer2AI, 0); + drone->SetLevel(TheMenu->m_nAIDroneLevelP2); + } } @@ -328,13 +335,11 @@ void PluginDispatch() void PluginFightStartup() { - printf("MK11Hook::Info() | Starting a new fight!\n"); + eLog::Message("MK11Hook::Info()", "Starting a new fight!"); TheMenu->m_bCustomCameraPos = false; TheMenu->m_bCustomCameraRot = false; TheMenu->m_bYObtained = false; - - if (TheMenu->m_bStageModifier) GetGameInfo()->SetStage(TheMenu->szStageModifierStage); @@ -354,34 +359,94 @@ void PluginFightStartup() TagAssistModifier tag(TheMenu->szPlayer1TagAssistCharacter); tag.Activate(GetInfo(PLAYER1)); - TagAssistModifierObject* obj = tag.CreateObject(); - - if (obj) - obj->Activate(GetObj(PLAYER1)); - - GetModifierManager()->ActivateModifier(&tag, GetObj(PLAYER1)); LoadModifierAssets(); - printf("MK11Hook::Info() | P1 Tag Assist: %s\n", TheMenu->szPlayer1TagAssistCharacter); + eLog::Message("MK11Hook::Info()", "P1 Tag Assist: %s", TheMenu->szPlayer1TagAssistCharacter); } if (TheMenu->m_bTagAssistP2) { TagAssistModifier tag(TheMenu->szPlayer2TagAssistCharacter); tag.Activate(GetInfo(PLAYER2)); - TagAssistModifierObject* obj = tag.CreateObject(); - - if (obj) - obj->Activate(GetObj(PLAYER2)); - - GetModifierManager()->ActivateModifier(&tag, GetObj(PLAYER2)); LoadModifierAssets(); - printf("MK11Hook::Info() | P2 Tag Assist: %s\n", TheMenu->szPlayer2TagAssistCharacter); + eLog::Message("MK11Hook::Info()", "P2 Tag Assist: %s", TheMenu->szPlayer2TagAssistCharacter); } + } - printf("MK11Hook::Info() | %s VS %s\n", GetCharacterName(PLAYER1), GetCharacterName(PLAYER2)); PluginInterface::OnFightStartup(); } + +void PluginFightStartupAddModifiers() +{ + if (TheMenu->m_bAIDroneModifierP1) + SetCharacterAI(PLAYER1, TheMenu->szPlayer1AI, TheMenu->m_nAIDroneLevelP1); + if (TheMenu->m_bAIDroneModifierP2) + SetCharacterAI(PLAYER2, TheMenu->szPlayer2AI, TheMenu->m_nAIDroneLevelP2); + + if (!TheMenu->m_bAddGlobalModifiers) + return; + + unsigned int numModifiers = TheMenu->m_ModifiersList.size(); + + std::string modifiersNames = ""; + for (int i = 0; i < numModifiers; i++) + { + ModifierEntry& modifier = TheMenu->m_ModifiersList[i]; + + modifiersNames += modifier.name.c_str(); + modifiersNames += "("; + if (modifier.flag & ModifierEntryFlag_P1) + modifiersNames += "P1"; + if (modifier.flag & ModifierEntryFlag_P2) + modifiersNames += "P2"; + modifiersNames += ")"; + if (!(i == numModifiers - 1)) + modifiersNames += ","; + } + + eLog::Message("MK11Hook::Info()", "Used modifiers: %s", modifiersNames.c_str()); + + for (int i = 0; i < numModifiers; i++) + { + ModifierEntry& modifier = TheMenu->m_ModifiersList[i]; + + if (!modifier.modifierDefinition) + continue; + + MKModifier::ActivateModifier(modifier.modifierDefinition, modifier.flag); + } + + pPluginFightStartupAddModifiers(); +} + +void PluginFightStartupQueueModifiers(int64 ptr, int64 pathArray) +{ + if (TheMenu->m_bAddGlobalModifiers) + { + unsigned int numModifiers = TheMenu->m_ModifiersList.size(); + + for (int i = 0; i < numModifiers; i++) + { + ModifierEntry& modifier = TheMenu->m_ModifiersList[i]; + modifier.modifierDefinition = MKModifier::CreateModifier(modifier.name.c_str()); + + if (modifier.modifierDefinition) + { + TArray path; + modifier.modifierDefinition->GetAssetPath(path); + + static uintptr_t pat = _pattern(PATID_TArray_AddString); + if (pat) + ((void(__fastcall*)(int64, int64))pat)(pathArray, (int64)&path); + } + } + } + + + + if (pPluginFightStartupQueueModifiers) + pPluginFightStartupQueueModifiers(ptr, pathArray); +} diff --git a/MK11Hook/plugin/Hooks.h b/MK11Hook/plugin/Hooks.h index f5ea257..5f7a03f 100644 --- a/MK11Hook/plugin/Hooks.h +++ b/MK11Hook/plugin/Hooks.h @@ -28,4 +28,9 @@ void SetKryptCharacterClass(int64 ptr, char* name, int unk); void PluginDispatch(); -void PluginFightStartup(); \ No newline at end of file +void PluginFightStartup(); +void PluginFightStartupAddModifiers(); +void PluginFightStartupQueueModifiers(int64 ptr, int64 pathArray); + +extern void(*pPluginFightStartupAddModifiers)(); +extern void(*pPluginFightStartupQueueModifiers)(int64, int64); diff --git a/MK11Hook/plugin/Menu.cpp b/MK11Hook/plugin/Menu.cpp index f9aae5b..050b90e 100644 --- a/MK11Hook/plugin/Menu.cpp +++ b/MK11Hook/plugin/Menu.cpp @@ -5,11 +5,13 @@ #include "../helper/eKeyboardMan.h" #include "../helper/eMouse.h" #include "../mk/Scaleform.h" +#include "../mk/MKModifier.h" #include "../gui/notifications.h" #include "../gui/imgui/imgui.h" #include "../gui/gui_impl.h" +#include #include #include #include @@ -17,10 +19,9 @@ using namespace Memory::VP; -static int64 timer = GetTickCount64(); -static int64 func_timer = GetTickCount64(); -char textBuffer[260] = {}; +std::random_device rd; +std::mt19937 mt(rd()); const char* szCharacters[] = { // place npcs first for easy access @@ -622,8 +623,10 @@ const char* szCameraModes[TOTAL_CUSTOM_CAMERAS] = { "First Person", "First Person Mid", "Injustice 2", - "Head Perspective" + "Head Perspective", + "9:16", }; + const char* szCharClasses[TOTAL_CHARACTER_CLASSES] = { "Base", "TestCharacters", @@ -1168,7 +1171,6 @@ void MK11Menu::DrawModifiersTab() ImGui::Separator(); ImGui::Checkbox("Player 2 Tag Assist Modifier", &m_bTagAssistP2); - if (ImGui::BeginCombo("Player 2 Tag Assist Character", szPlayer2TagAssistCharacter)) { for (int n = 0; n < IM_ARRAYSIZE(szKryptCharacters); n++) @@ -1190,67 +1192,7 @@ void MK11Menu::DrawModifiersTab() } if (ImGui::BeginTabItem("Abilities")) { - ImGui::Checkbox("Player 1 Custom Abilities", &m_bP1CustomAbilities); - ImGui::SameLine(); ShowHelpMarker("Set these on select screen! Changing these in game will make moves locked."); - ImGui::Separator(); - - - for (int i = 0; i < sizeof(m_P1Abilities) / sizeof(m_P1Abilities[0]); i++) - { - sprintf(textBuffer, "Ability %d", i + 1); - - ImGui::Checkbox(textBuffer, &m_P1Abilities[i]); - - if (i % 2 == 0) - ImGui::SameLine(); - } - - - if (GetObj(PLAYER1)) - { - if (ImGui::Button("Get##p1")) - { - int abilities = GetObj(PLAYER1)->GetAbility(); - - for (int i = 0; i < sizeof(m_P1Abilities) / sizeof(m_P1Abilities[0]); i++) - { - int id = (int)pow(2, i); - m_P1Abilities[i] = abilities & id; - } - } - - } - ImGui::Separator(); - ImGui::Checkbox("Player 2 Custom Abilities", &m_bP2CustomAbilities); - ImGui::Separator(); - - for (int i = 0; i < sizeof(m_P2Abilities) / sizeof(m_P2Abilities[0]); i++) - { - int val = (int)pow(2, i); - - sprintf(textBuffer, "Ability %d##p2", i + 1); - - ImGui::Checkbox(textBuffer, &m_P2Abilities[i]); - - if (i % 2 == 0) - ImGui::SameLine(); - } - - if (GetObj(PLAYER2)) - { - if (ImGui::Button("Get##p2")) - { - int abilities = GetObj(PLAYER2)->GetAbility(); - - for (int i = 0; i < sizeof(m_P2Abilities) / sizeof(m_P2Abilities[0]); i++) - { - int id = (int)pow(2, i); - m_P2Abilities[i] = abilities & id; - } - } - - } - + DrawModifiers_AbilityTab(); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Skeleton")) @@ -1381,7 +1323,7 @@ void MK11Menu::DrawModifiersTab() } if (ImGui::BeginTabItem("AI")) { - ImGui::TextWrapped("This will only change existing AI's script, it will not make human character be controlled by AI."); + ImGui::TextWrapped("Reload match to change if players are AI controlled."); ImGui::Separator(); ImGui::Checkbox("Change Player 1 AI", &m_bAIDroneModifierP1); @@ -1399,6 +1341,7 @@ void MK11Menu::DrawModifiersTab() ImGui::EndCombo(); } + ImGui::SliderInt("Player 1 AI Level", &m_nAIDroneLevelP1, 0, 19); ImGui::Separator(); ImGui::Checkbox("Change Player 2 AI", &m_bAIDroneModifierP2); @@ -1415,6 +1358,140 @@ void MK11Menu::DrawModifiersTab() } ImGui::EndCombo(); } + ImGui::SliderInt("Player 2 AI Level", &m_nAIDroneLevelP2, 0, 19); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Tower Modifiers")) + { + ImGui::TextWrapped("Add modifiers in game and reload match to prevent potential crashes."); + ImGui::Separator(); + ImGui::Checkbox("Add Tower Modifiers", &m_bAddGlobalModifiers); + ImGui::Separator(); + + enum EModifierFlagType { + ModifierFlagType_Both, + ModifierFlagType_P1Only, + ModifierFlagType_P2Only, + }; + static int flagType = ModifierFlagType_Both; + + + ImGui::TextWrapped("Target"); + ImGui::Separator(); + ImGui::RadioButton("Both", &flagType, ModifierFlagType_Both); ImGui::SameLine(); + ImGui::RadioButton("Player 1 Only", &flagType, ModifierFlagType_P1Only); ImGui::SameLine(); + ImGui::RadioButton("Player 2 Only", &flagType, ModifierFlagType_P2Only); + ImGui::Separator(); + + static char modifierName[256] = {}; + static ImGuiTextFilter filter; + ImGui::Text("Search Modifiers"); + ImGui::PushItemWidth(-FLT_MIN); + filter.Draw("##modlist"); + ImGui::PopItemWidth(); + ImGui::BeginChild("##list", { 0, 125.0f }, true); + { + + for (int i = 0; i < NUM_MODIFIERS; i++) + { + if (filter.PassFilter(szModifiers[i])) + { + bool is_selected = (modifierName == szModifiers[i]); + if (ImGui::Selectable(szModifiers[i], is_selected)) + { + sprintf(modifierName, "%s", szModifiers[i]); + } + } + + + } + } + ImGui::EndChild(); + if (strlen(modifierName) > 0) + ImGui::TextWrapped("Selected: %s", modifierName); + if (ImGui::Button("Add", { -FLT_MIN, 0 })) + { + ModifierEntry entry = {}; + entry.name = modifierName; + switch (flagType) + { + case ModifierFlagType_Both: + entry.flag = ModifierEntryFlag_P1 | ModifierEntryFlag_P2; + entry.bothPlayers = true; + break; + case ModifierFlagType_P1Only: + entry.flag = ModifierEntryFlag_P1; + entry.bothPlayers = false; + break; + case ModifierFlagType_P2Only: + entry.flag = ModifierEntryFlag_P2; + entry.bothPlayers = false; + break; + default: + break; + } + m_ModifiersList.push_back(entry); + } + if (ImGui::Button("Add Random", { -FLT_MIN, 0 })) + { + std::uniform_int_distribution random_dist(0, NUM_MODIFIERS); + + int randomID = random_dist(mt); + + ModifierEntry entry = {}; + entry.name = szModifiers[randomID]; + switch (flagType) + { + case ModifierFlagType_Both: + entry.flag = ModifierEntryFlag_P1 | ModifierEntryFlag_P2; + entry.bothPlayers = true; + break; + case ModifierFlagType_P1Only: + entry.flag = ModifierEntryFlag_P1; + entry.bothPlayers = false; + break; + case ModifierFlagType_P2Only: + entry.flag = ModifierEntryFlag_P2; + entry.bothPlayers = false; + break; + default: + break; + } + m_ModifiersList.push_back(entry); + } + + ImGui::Separator(); + unsigned int numModifiers = m_ModifiersList.size(); + if (numModifiers > 0) + { + ImGui::TextWrapped("Modifiers to activate:"); + ImGui::Separator(); + for (unsigned int i = 0; i < m_ModifiersList.size(); i++) + { + char modifierLabel[64] = {}; + sprintf(modifierLabel, "%d - %s##gm%d", i + 1, m_ModifiersList[i].name.c_str(), i); + char* modifierLabelType = "##"; + if (m_ModifiersList[i].flag & ModifierEntryFlag_P1) + modifierLabelType = "P1##"; + if (m_ModifiersList[i].flag & ModifierEntryFlag_P2) + modifierLabelType = "P2##"; + if (m_ModifiersList[i].flag & ModifierEntryFlag_P1 && m_ModifiersList[i].flag & ModifierEntryFlag_P2) + modifierLabelType = "Both##"; + ImGui::LabelText(modifierLabelType, modifierLabel); + } + if (ImGui::Button("Delete Last", { -FLT_MIN, 0 })) + { + m_ModifiersList.erase(m_ModifiersList.end() - 1); + } + if (ImGui::Button("Clear", { -FLT_MIN, 0 })) + { + m_ModifiersList.clear(); + } + + } + + + ImGui::EndTabItem(); } ImGui::EndTabBar(); @@ -1513,9 +1590,6 @@ void MK11Menu::DrawCameraTab() ImGui::Checkbox("Mouse Control", &m_bMouseControl); } - - - ImGui::Separator(); ImGui::Checkbox("Disable DOF", &m_bDisableDOF); ImGui::Checkbox("Force Camera To Move", &m_bForceCameraUpdate); @@ -2084,22 +2158,27 @@ void MK11Menu::DrawAbilityReference() ImGui::SameLine(); ImGui::BeginChild("##movelist", { 0, -ImGui::GetFrameHeightWithSpacing() }); - eAbilityNameEntry ab; - ab = eAbiltityNames::Get(szKryptCharacters[charID]); - - ImGui::LabelText("ID", "Name"); - ImGui::Separator(); + + eAbilityNameEntry* ab = eAbiltityNames::Get(szKryptCharacters[charID]); - for (unsigned int i = 0; i < TOTAL_ABILITIES; i++) + if (ab) { - if (strlen(ab.abNames[i]) > 0) + ImGui::LabelText("ID", "Name"); + ImGui::Separator(); + + for (unsigned int i = 0; i < eAbiltityNames::GetAmount(ab); i++) { - sprintf(textBuffer, "%d", i + 1); - ImGui::LabelText(textBuffer, ab.abNames[i]); - } + if (strlen(ab->abNames[i]) > 0) + { + static char textBuffer[256] = {}; + sprintf(textBuffer, "%d", i + 1); + ImGui::LabelText(textBuffer, ab->abNames[i]); + } + } } + ImGui::EndChild(); ImGui::End(); } @@ -2172,6 +2251,74 @@ void MK11Menu::DrawAnimationTool() AnimationTool::Draw(); } +void MK11Menu::DrawModifiers_AbilityTab() +{ + ImGui::TextWrapped("Set abilities before going into a fight. Changing these in game will make moves locked, restart match if that happens."); + ImGui::Separator(); + ImGui::Checkbox("Player 1 Custom Abilities", &m_bP1CustomAbilities); + ImGui::Separator(); + DrawModifiers_AbilityTab_List(PLAYER1); + ImGui::Checkbox("Player 2 Custom Abilities", &m_bP2CustomAbilities); + DrawModifiers_AbilityTab_List(PLAYER2); +} + +void MK11Menu::DrawModifiers_AbilityTab_List(PLAYER_NUM player) +{ + static char abilityName[256] = {}; + + bool* abilities = &m_P1Abilities[0]; + if (player == PLAYER2) + abilities = &m_P2Abilities[0]; + + int numAbilities = TOTAL_ABILITIES; + + if (GetObj(player)) + { + eAbilityNameEntry* ability = eAbiltityNames::Get(GetCharacterName(player)); + + if (!ability) + return; + + numAbilities = eAbiltityNames::GetAmount(ability); + + for (int i = 0; i < numAbilities; i++) + { + sprintf(abilityName, "%s##a%d%d", ability->abNames[i], player, i + 1); + + ImGui::Checkbox(abilityName, &abilities[i]); + } + } + else + { + for (int i = 0; i < numAbilities; i++) + { + sprintf(abilityName, "Ability %d##a%d%d", i + 1,player,i + 1); + + ImGui::Checkbox(abilityName, &abilities[i]); + + if (i % 2 == 0) + ImGui::SameLine(); + } + } + + + if (GetObj(player)) + { + if (ImGui::Button("Get Current##p1")) + { + int curAbilities = GetObj(player)->GetAbility(); + + for (int i = 0; i < TOTAL_ABILITIES; i++) + { + int id = (int)pow(2, i); + abilities[i] = curAbilities & id; + } + } + + } + ImGui::Separator(); +} + void MK11Menu::DrawKeyBind(char* name, int* var) { ImGui::SameLine(); diff --git a/MK11Hook/plugin/Menu.h b/MK11Hook/plugin/Menu.h index c797061..77e6cb7 100644 --- a/MK11Hook/plugin/Menu.h +++ b/MK11Hook/plugin/Menu.h @@ -3,14 +3,16 @@ #include "../mk/CharacterDefinition.h" #include "../mk/MKCharacter.h" #include "../mk/MKCamera.h" +#include "../mk/MKModifier.h" #include "../mk/LadderInfo.h" #include "PluginInterface.h" #include "../helper/eKeyboardMan.h" #include "../utils.h" +#define NUM_MODIFIERS 284 -#define MK11HOOK_VERSION "0.5.8" +#define MK11HOOK_VERSION "0.5.9" enum eCustomCameras { CAMERA_3RDPERSON, @@ -19,6 +21,7 @@ enum eCustomCameras { CAMERA_1STPERSON_MID, CAMERA_INJUSTICE_2, CAMERA_HEAD_TRACKING, + CAMERA_9_16, TOTAL_CUSTOM_CAMERAS }; @@ -44,6 +47,11 @@ enum eScriptExecuteType { SCRIPT_GLOBAL }; +enum eModifierEntryFlag { + ModifierEntryFlag_P1 = 1, + ModifierEntryFlag_P2 = 2, +}; + struct eScriptKeyBind { eScriptExecuteType type; eVKKeyCode key; @@ -51,6 +59,15 @@ struct eScriptKeyBind { unsigned int functionHash; }; +struct ModifierEntry { + std::string name; + int flag; + bool bothPlayers; + Modifier* modifierDefinition; +}; + +extern const char* szModifiers[NUM_MODIFIERS]; + class MK11Menu { public: bool m_bIsActive = false; @@ -111,6 +128,7 @@ class MK11Menu { bool m_bKryptModifier = false; bool m_bTagAssist = false; bool m_bTagAssistP2 = false; + bool m_bAddGlobalModifiers = false; bool m_bDisableGearLoadouts = false; bool m_bDisableComboScaling = false; bool m_bKryptAirbreak = false; @@ -141,15 +159,19 @@ class MK11Menu { int m_nFreeCameraRotationSpeed = 120; int m_nCurrentCustomCamera = CAMERA_3RDPERSON; int m_nCurrentCharModifier = MODIFIER_SCREEN; + + int m_nAIDroneLevelP1 = 0; + int m_nAIDroneLevelP2 = 0; + int m_nP1Abilities = 0; int m_nP2Abilities = 0; int* m_pCurrentVarToChange = nullptr; bool m_bP1CustomAbilities = false; - bool m_P1Abilities[20] = {}; + bool m_P1Abilities[TOTAL_ABILITIES] = {}; bool m_bP2CustomAbilities = false ; - bool m_P2Abilities[20] = {}; + bool m_P2Abilities[TOTAL_ABILITIES] = {}; int m_nScriptExecuteType = 0; unsigned int m_nHash = 0; @@ -181,6 +203,8 @@ class MK11Menu { char szPlayer1AI[128] = {}; char szPlayer2AI[128] = {}; + std::vector m_ModifiersList; + // camera FVector camPos = {}; @@ -227,6 +251,9 @@ class MK11Menu { void DrawScriptReference(); void DrawAnimationTool(); + void DrawModifiers_AbilityTab(); + void DrawModifiers_AbilityTab_List(PLAYER_NUM player); + void DrawKeyBind(char* name, int* var); void KeyBind(int* var, char* bindName, char* name); diff --git a/MK11Hook/plugin/ModifierList.cpp b/MK11Hook/plugin/ModifierList.cpp new file mode 100644 index 0000000..d349185 --- /dev/null +++ b/MK11Hook/plugin/ModifierList.cpp @@ -0,0 +1,288 @@ +#include "Menu.h" + +const char* szModifiers[NUM_MODIFIERS] = { + "AcidRain", + "AirStrike", + "Armor", + "BadLowGround", + "BadSpecial", + "Bleeding", + "BlockingDisabled", + "BrutalityKombat", + "BuffedUp", + "CoordinatesReceived", + "DarkKombat", + "DeadHands", + "DiveKick", + "Earthshaker", + "Earthquake", + "BloodAura", + "ChaosAura", + "DarkAura", + "ElectricAura", + "EnergyAura", + "FireAura", + "IceAura", + "MagicAura", + "PoisonAura", + "BloodFists", + "ChaosFists", + "DarkFists", + "ElectricFists", + "EnergyFists", + "FireFists", + "IceFists", + "MagicFists", + "PoisonFists", + "BloodFloor", + "ChaosFloor", + "DarkFloor", + "ElectricFloor", + "EnergyFloor", + "FireFloor", + "IceFloor", + "MagicFloor", + "PoisonFloor", + "BloodShield", + "HalfResistBlood", + "ChaosShield", + "HalfResistChaos", + "DarkShield", + "HalfResistDark", + "ElectricShield", + "HalfResistElectric", + "EnergyShield", + "HalfResistEnergy", + "FireShield", + "HalfResistFire", + "IceShield", + "HalfResistIce", + "MagicShield", + "HalfResistMagic", + "PoisonShield", + "HalfResistPoison", + "PhysicalShield", + "HalfResistPhysical", + "BloodRockets", + "BloodRockets_FriendlyFire", + "ChaosRockets", + "ChaosRockets_FriendlyFire", + "DarkRockets", + "DarkRockets_FriendlyFire", + "ElectricRockets", + "ElectricRockets_FriendlyFire", + "EnergyRockets", + "EnergyRockets_FriendlyFire", + "FireRockets", + "FireRockets_FriendlyFire", + "IceRockets", + "IceRockets_FriendlyFire", + "MagicRockets", + "MagicRockets_FriendlyFire", + "PoisonRockets", + "PoisonRockets_FriendlyFire", + "BloodStorm", + "ChaosStorm", + "DarkStorm", + "ElectricStorm", + "EnergyStorm", + "FireStorm", + "IceStorm", + "MagicStorm", + "PoisonStorm", + "BloodTotem", + "ChaosTotem", + "DarkTotem", + "ElectricTotem", + "EnergyTotem", + "FireTotem", + "IceTotem", + "MagicTotem", + "PoisonTotem", + "FallingBombs", + "FallingHeads", + "FleetFooted", + "GiftOfBlood", + "CurseOfBlood", + "GiftOfChaos", + "CurseOfChaos", + "GiftOfDark", + "CurseOfDark", + "GiftOfElectric", + "CurseOfElectric", + "GiftOfEnergy", + "CurseOfEnergy", + "GiftOfFire", + "CurseOfFire", + "GiftOfIce", + "CurseOfIce", + "GiftOfMagic", + "CurseOfMagic", + "GiftOfPoison", + "CurseOfPoison", + "GiftOfRandom", + "CurseOfRandom", + "PickupOfRandom", + "GiveSupermove", + "GroundBlade", + "GroundMines", + "GroundSpikes", + "GunAttacksUp", + "JuggleKombat", + "BlueLightningStrikes", + "RedLightningStrikes", + "BlackLightningStrikes", + "MeteorKombat", + "Overpowered", + "DamageBuff", + "PanningLasers", + "PillarsOfFlame", + "Poisoned", + "BadDucking", + "BadJumping", + "PowerOrb", + "PowerStruggle", + "HypoKombat", + "HyperKombat", + "SupermoveBuff", + "WetSpot", + "DamageReflectAll", + "HealBlock", + "BlackDragonAssist", + "BoRaiChoAssist", + "ErmacAssist", + "HsuHaoAssist", + "HydroAssist", + "KungJinAssist", + "MeatAssist", + "MileenaAssist", + "NitaraAssist", + "OnyxAssist", + "QuanChiAssist", + "ReikoAssist", + "ReptileAssist", + "SektorAssist", + "SmokeAssist", + "SpecialForcesAssist", + "StrykerAssist", + "TakedaAssist", + "TanyaAssist", + "TremorAssist", + "CyraxAssist", + "CyraxBombsAssist", + "KenshiAssist", + "RainAssist", + "ShinnokAssist", + "BloodBuff", + "ChaosBuff", + "DarkBuff", + "ElectricBuff", + "EnergyBuff", + "FireBuff", + "IceBuff", + "MagicBuff", + "PoisonBuff", + "PhysicalBuff", + "DisableWeather", + "DisableRockets", + "DisableFloorMods", + "DisableTotemMods", + "FreezeDuration", + "HealthRegen", + "M80Assist", + "PugglesAssist", + "RomanCandleAssist", + "BatsAssist", + "BigBoom", + "BlackCatAssist", + "BottleRockets", + "CannedCranberry", + "DiveBombingTurkey", + "FallingPumpkins", + "Fireworks", + "FlyingWitchAssist", + "Gravestones", + "GravyBubble", + "GroundSpinner", + "HornOfPlenty", + "JackOLantern", + "MashedPotatoes", + "Pentagrams", + "PieAssist", + "SmokeBomb", + "Sparklers", + "RunningTurkeyAssist", + "AIDisabled", + "PhysicalOverride", + "BloodOverride", + "ChaosOverride", + "DarkOverride", + "ElectricOverride", + "EnergyOverride", + "FireOverride", + "IceOverride", + "MagicOverride", + "PoisonOverride", + "FStyleDisabled", + "InvisibleKombat", + "MomentOfOpportunity", + "ProjectilePassThru", + "ReducedDamage", + "ReducedPhysicalDamage", + "ReducedBloodDamage", + "ReducedChaosDamage", + "ReducedDarkDamage", + "ReducedElectricDamage", + "ReducedEnergyDamage", + "ReducedFireDamage", + "ReducedMagicDamage", + "ReducedPoisonDamage", + "SpecialBuff", + "SpecialsDisabled", + "SupermovesDisabled", + "TimerAdjustment", + "Weakened", + "DeflectedGlaive", + "DeflectedGlaiveLow", + "WaveOfGlaives", + "GlaiveBurst", + "GlaiveJuggling", + "HighLowGlaives", + "SavageBleed", + "SavageBleedPhase2", + "SavageBleedPhase3", + "SavageBleedPhase4", + "GreenEnergyBuff", + "SkarletHealingBlood", + "ScytheFall", + "BloodBall", + "SpearFlurry", + "FireResistance", + "DvorahPoisonOvipositors", + "DvorahSpiderFood", + "DvorahOrbspinner", + "DvorahInfest", + "DvorahSwarmCloud", + "RaidenStormhead", + "RaidenLightningPillar", + "RaidenLightningStorm", + "KungLaoRazorHats", + "KungLaoKungFuMaster", + "KungLaoSpiritMaster", + "KungLaoSpiritReinforcement", + "KungLaoSpiritsGifts", + "GreatKungLaosDecimation", + "BouncingHat", + "DragonsBreathZones", + "DragonsBreathJump", + "LiuKangFlowLikeWater", + "KabalGasSaturation", + "KabalSpeedBoost", + "KabalHookBleed", + "KabalGroundBladeRush", + "FightClub", + "BlackDragonSniper", + "ChemicalBurns", + "ErronBlackChainDetonator", + "DoNothing", +}; diff --git a/MK11Hook/plugin/PatternSolver.cpp b/MK11Hook/plugin/PatternSolver.cpp index e749205..bce29f9 100644 --- a/MK11Hook/plugin/PatternSolver.cpp +++ b/MK11Hook/plugin/PatternSolver.cpp @@ -91,8 +91,13 @@ void PatternSolver::Initialize() ms_patterns[PATID_TagAssistModifier_TagAssistModifier] = GetPattern("48 89 4C 24 08 55 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 60 48 C7 45 C0 FE FF FF FF 48 89 9C 24 A8 00 00 00 49 8B D8", 0); ms_patterns[PATID_TagAssistModifier_Activate] = GetPattern("48 85 D2 0F 84 A7 01 00 00 48 8B C4 57 41 56 41 57 48 83 EC 70 48 C7 40 A8 FE FF FF FF", 0); ms_patterns[PATID_TagAssistModifier_CreateObject] = GetPattern("40 57 48 83 EC 30 48 C7 44 24 20 FE FF FF FF 48 89 5C 24 40 48 8B F9 BA 01 00 00 00 B9 20 01 00 00", 0); - ms_patterns[PATID_MKModifier_ActivateModifier] = GetPattern("48 89 5C 24 18 48 89 6C 24 20 56 48 83 EC 20 48 8B 02 48 8B E9 48 8B CA", 0); - ms_patterns[PATID_TagAssistModifierObject_Activate] = GetPattern("48 89 5C 24 08 57 48 83 EC 20 48 8B DA 48 8B F9 48 85 D2 0F 84 89 00 00 00", 0); + ms_patterns[PATID_MKModifier_Constructor] = GetPattern("4C 8B DC 49 89 4B 08 56 57 41 56 48 83 EC 50 49 C7 43 ? ? ? ? ? 49 89 5B 10 49 89 6B 18 48 8B EA 4C 8B F1 48 8B 84 24 ? ? ? ? 49 89 43 B8 E8 ? ? ? ? 90 48 8D 05 ? ? ? ? 49 89 06 4C 8B C5 48 8D 15 ? ? ? ? 48 8D 4C 24 ? E8", 0); + ms_patterns[PATID_MKModifier_Activate] = GetPattern("48 8B C4 41 54 41 56 41 57 48 81 EC ? ? ? ? 48 C7 40 ? ? ? ? ? 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 48 8B F2 48 8B F9 80 B9 ? ? ? ? ? 74 07 32 C0 E9 ? ? ? ? 48 8B 15 ? ? ? ? 4C 8D 25 ? ? ? ? 48 83 BA ? ? ? ? ? 74 1C 8B 82", 0); + ms_patterns[PATID_MKModifier_GetAssetPath] = GetPattern("40 57 48 83 EC 50 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 74 24 ? 48 8B DA 83 79 10 00 74 06 4C 8B 41 08 EB 07 4C 8D 05 ? ? ? ? 48 8D 15 ? ? ? ? 48 8D 4C 24 ? E8", 0); + ms_patterns[PATID_MKModifierObject_Constructor] = GetPattern("48 89 5C 24 ? 57 48 83 EC 20 48 8B 02 48 8B D9 48 8B CA 41 8B F8 FF 50 08 48 89 03 48 8B C3 89 7B 08 48 8B 5C 24 ? 48 83 C4 20 5F C3", 0); + ms_patterns[PATID_MKModifierObject_Activate] = GetPattern("48 89 5C 24 ? 48 89 6C 24 ? 56 48 83 EC 20 49 8B F0 48 8B EA 48 8B D9 E8 ? ? ? ? 48 85 C0 74 56 48 8B C8 48 89 7C 24 ? E8 ? ? ? ? 48 8B F8 48 85 C0 74 3C 8B 53 08 85 D2 74 27 83 EA 01 74 1D", 0); + + ms_patterns[PATID_GetModifierManager] = GetPattern("B9 03 00 00 00 E8 ? ? ? ? E8 ? ? ? ? 48 85 C0 74 11 BA 40 00 00 00", 11); ms_patterns[PATID_LoadModifierAssets] = GetPattern("48 89 5C 24 10 55 48 83 EC 30 48 8D 2D ? ? ? ?", 0); @@ -107,7 +112,10 @@ void PatternSolver::Initialize() ms_patterns[PATID_PlayerInfo_SetMeter] = GetPattern("40 53 48 83 EC 30 0F 29 74 24 20 0F 57 F6 8B DA", 0); ms_patterns[PATID_PlayerInfo_RefreshMeter] = GetPattern("48 89 5C 24 10 56 48 81 EC 80 00 00 00 48 8B D9", 0); ms_patterns[PATID_PlayerInfo_GetDrone] = GetPattern("48 8B 81 50 04 00 00 48 85 C0 74 21", 0); + ms_patterns[PATID_PlayerInfo_MakeDrone] = GetPattern("40 56 57 41 56 48 83 EC 30 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 6C 24 ? 48 8B D9 48 85 C9 75 07 33 C0 E9 ? ? ? ? 48 8B 79 30 48 85 FF 74 F0 48 8B CF E8 ? ? ? ? 33 F6 85 C0 75 3E 44 8B F6 48 8B CF E8 ? ? ? ? 85 C0", 0); ms_patterns[PATID_AIDrone_Set] = GetPattern("48 89 5C 24 10 48 89 6C 24 18 56 57 41 56 48 83 EC 20 48 8B F9 48 8B F2 48 8B 0D ? ? ? ? BA 00 00 00 10", 0); + ms_patterns[PATID_AIDrone_SetLevel] = GetPattern("40 53 48 83 EC 30 0F 29 74 24 ? 48 8B D9 0F 28 F1 0F 2F 35 ? ? ? ? 77 45 48 8B 89 ? ? ? ? 48 85 C9 74 27 8B 83 ? ? ? ? 3D ? ? ? ? 73 1A 8B D0 4C 8D 05 ? ? ? ? 8B 83", 0); + ms_patterns[PATID_SetKryptCharacter] = GetPattern("40 57 48 83 EC 40 48 C7 44 24 20 FE FF FF FF 48 89 5C 24 50 48 89 74 24 60 48 8B DA 48 8B F9 33 F6", 0); ms_patterns[PATID_SetKryptCharacterL] = GetPattern("40 53 48 83 EC 40 48 8B D9 48 85 D2 74 48 80 3A 00", 0); @@ -123,6 +131,9 @@ void PatternSolver::Initialize() ms_patterns[PATID_ProcessDOFSettings] = GetPattern("48 8D 4B 44 E8 ? ? ? ? 48 8D 44 24", 4); + ms_patterns[PATID_FightStartupAddModifiers] = GetPattern("E8 ? ? ? ? E8 ? ? ? ? 85 C0 74 16 0F 1F 44 00 ? 41 8B CC E8", 0); + ms_patterns[PATID_TArray_AddString] = GetPattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 48 63 59 08 48 8B F2 48 8B F9 8D 43 01 89 41 08 3B 41 0C 7E 47 44 8B C0 41 C1 E8 03 42 8D 04 40 83 C0 20 41 03 C0 48 05 ? ? ? ? 48 8B C8 48 C1 F9 3F 23 C1 48 8B 0F 05 ? ? ? ? 89 47 0C 48 85 C9 75 04 85 C0 74 13 C1 E0 04", 0); + ms_patterns[PATID_FightStartupQueueModifiers] = GetPattern("48 8B C4 55 41 54 41 55 41 56 41 57 48 8B EC 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? ? 48 89 58 10 48 89 70 18 48 89 78 20 48 8B FA 4C 8B F9 48 8D 4D C8 E8 ? ? ? ? 48 8B D8 45 33 F6 48 3B F8 0F 84 ? ? ? ? 8B 40 08", 0); auto end = std::chrono::high_resolution_clock::now(); auto time = std::chrono::duration_cast(end - begin); @@ -215,8 +226,11 @@ const char* PatternSolver::GetPatternName(int id) "TagAssistModifier_TagAssistModifier", "TagAssistModifier_Activate", "TagAssistModifier_CreateObject", - "MKModifier_ActivateModifier", - "TagAssistModifierObject_Activate", + "MKModifier_Constructor", + "MKModifier_Activate", + "MKModifier_GetAssetPath", + "MKModifierObject_Constructor", + "MKModifierObject_Activate", "GetModifierManager", "LoadModifierAssets", "MKObject_SetPos", @@ -228,7 +242,9 @@ const char* PatternSolver::GetPatternName(int id) "PlayerInfo_SetMeter", "PlayerInfo_RefreshMeter", "PlayerInfo_GetDrone", + "PlayerInfo_MakeDrone", "AIDrone_Set", + "AIDrone_SetLevel", "SetKryptCharacter", "SetKryptCharacterL", "AnimationToolCode", @@ -237,7 +253,10 @@ const char* PatternSolver::GetPatternName(int id) "USkeletalMeshComponent_GetBoneName", "XInputGetState_Hook", "GetScaleform", - "ProcessDOFSettings" + "ProcessDOFSettings", + "FightStartupAddModifiers", + "TArray_AddString", + "FightStartupQueueModifiers", }; return szPatternNames[id]; diff --git a/MK11Hook/plugin/PatternSolver.h b/MK11Hook/plugin/PatternSolver.h index ce084dc..d374abb 100644 --- a/MK11Hook/plugin/PatternSolver.h +++ b/MK11Hook/plugin/PatternSolver.h @@ -67,8 +67,12 @@ enum EPatternID { PATID_TagAssistModifier_TagAssistModifier, PATID_TagAssistModifier_Activate, PATID_TagAssistModifier_CreateObject, - PATID_MKModifier_ActivateModifier, - PATID_TagAssistModifierObject_Activate, + PATID_MKModifier_Constructor, + PATID_MKModifier_Activate, + PATID_MKModifier_GetAssetPath, + PATID_MKModifierObject_Constructor, + PATID_MKModifierObject_Activate, + PATID_GetModifierManager, PATID_LoadModifierAssets, @@ -83,7 +87,9 @@ enum EPatternID { PATID_PlayerInfo_SetMeter, PATID_PlayerInfo_RefreshMeter, PATID_PlayerInfo_GetDrone, + PATID_PlayerInfo_MakeDrone, PATID_AIDrone_Set, + PATID_AIDrone_SetLevel, PATID_SetKryptCharacter, PATID_SetKryptCharacterL, @@ -96,6 +102,10 @@ enum EPatternID { PATID_XInputGetState_Hook, PATID_GetScaleform, PATID_ProcessDOFSettings, + PATID_FightStartupAddModifiers, + PATID_TArray_AddString, + PATID_FightStartupQueueModifiers, + PATID_Total_Patterns }; diff --git a/MK11Hook/utils/MemoryMgr.h b/MK11Hook/utils/MemoryMgr.h index b53cf48..d52cfda 100644 --- a/MK11Hook/utils/MemoryMgr.h +++ b/MK11Hook/utils/MemoryMgr.h @@ -1,5 +1,4 @@ -#ifndef __MEMORYMGR -#define __MEMORYMGR +#pragma once // Switches: // _MEMORY_NO_CRT - don't include anything "complex" like ScopedUnprotect or memset @@ -7,61 +6,81 @@ #define WRAPPER __declspec(naked) #define DEPRECATED __declspec(deprecated) +#define WRAPARG(a) ((int)a) + +#ifdef _MSC_VER #define EAXJMP(a) { _asm mov eax, a _asm jmp eax } #define VARJMP(a) { _asm jmp a } -#define WRAPARG(a) ((int)a) +#elif defined(__GNUC__) || defined(__clang__) +#define EAXJMP(a) { __asm__ volatile("mov eax, %0\n" "jmp eax" :: "i" (a)); } +#define VARJMP(a) { __asm__ volatile("jmp %0" :: "m" (a)); } +#endif +#ifdef _MSC_VER #define NOVMT __declspec(novtable) +#else +#define NOVMT +#endif + #define SETVMT(a) *((uintptr_t*)this) = (uintptr_t)a #ifndef _MEMORY_DECLS_ONLY #define WIN32_LEAN_AND_MEAN -#include +#include #include #include #ifndef _MEMORY_NO_CRT +#include #include -#include +#include #endif -enum +namespace Memory { - PATCH_CALL, - PATCH_JUMP -}; + enum class HookType + { + Call, + Jump, + }; -template -inline AT DynBaseAddress(AT address) -{ -#ifdef _WIN64 - return (ptrdiff_t)GetModuleHandle(nullptr) - 0x140000000 + address; -#else - return (ptrdiff_t)GetModuleHandle(nullptr) - 0x400000 + address; -#endif -} + template + inline AT DynBaseAddress(AT address) + { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); + #ifdef _WIN64 + return (ptrdiff_t)GetModuleHandle(nullptr) - 0x140000000 + address; + #else + return (ptrdiff_t)GetModuleHandle(nullptr) - 0x400000 + address; + #endif + } -namespace Memory -{ template inline void Patch(AT address, T value) - {*(T*)address = value; } + { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); + *(T*)address = value; + } #ifndef _MEMORY_NO_CRT template inline void Patch(AT address, std::initializer_list list ) { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); uint8_t* addr = reinterpret_cast(address); - std::copy( list.begin(), list.end(), stdext::make_checked_array_iterator(addr, list.size()) ); + std::copy( list.begin(), list.end(), addr ); } #endif template inline void Nop(AT address, size_t count) #ifndef _MEMORY_NO_CRT - { memset((void*)address, 0x90, count); } + { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); + memset((void*)address, 0x90, count); + } #else { do { *(uint8_t*)address++ = 0x90; @@ -71,6 +90,7 @@ namespace Memory template inline void WriteOffsetValue(AT address, Var var) { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); intptr_t dstAddr = (intptr_t)address; intptr_t srcAddr; memcpy( &srcAddr, std::addressof(var), sizeof(srcAddr) ); @@ -80,6 +100,7 @@ namespace Memory template inline void ReadOffsetValue(AT address, Var& var) { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); intptr_t srcAddr = (intptr_t)address; intptr_t dstAddr = srcAddr + (4 + extraBytesAfterOffset) + *(int32_t*)srcAddr; var = {}; @@ -93,9 +114,9 @@ namespace Memory } template - inline void InjectHook(AT address, Func hook, unsigned int nType) + inline void InjectHook(AT address, Func hook, HookType type) { - *(uint8_t*)address = nType == PATCH_JUMP ? 0xE9 : 0xE8; + *(uint8_t*)address = type == HookType::Jump ? 0xE9 : 0xE8; InjectHook(address, hook); } @@ -113,23 +134,38 @@ namespace Memory return reinterpret_cast( addr + offset ); } + constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook) + { + ReadCall(address, func); + InjectHook(address, hook); + }; + #ifndef _MEMORY_NO_CRT inline bool MemEquals(uintptr_t address, std::initializer_list val) { const uint8_t* mem = reinterpret_cast(address); - return std::equal( val.begin(), val.end(), stdext::make_checked_array_iterator(mem, val.size()) ); + return std::equal( val.begin(), val.end(), mem ); } #endif template inline AT Verify(AT address, uintptr_t expected) { + static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized"); assert( uintptr_t(address) == expected ); return address; } namespace DynBase { + enum class HookType + { + Call, + Jump, + }; + + using Memory::DynBaseAddress; + template inline void Patch(AT address, T value) { @@ -162,16 +198,16 @@ namespace Memory Memory::ReadOffsetValue(DynBaseAddress(address), var); } - template - inline void InjectHook(AT address, HT hook) + template + inline void InjectHook(AT address, Func hook) { Memory::InjectHook(DynBaseAddress(address), hook); } - template - inline void InjectHook(AT address, HT hook, unsigned int nType) + template + inline void InjectHook(AT address, Func hook, HookType type) { - Memory::InjectHook(DynBaseAddress(address), hook, nType); + Memory::InjectHook(DynBaseAddress(address), hook, static_cast(type)); } template @@ -186,6 +222,11 @@ namespace Memory return Memory::ReadCallFrom(DynBaseAddress(address), offset); } + constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook) + { + Memory::InterceptCall(DynBaseAddress(address), func, hook); + }; + #ifndef _MEMORY_NO_CRT inline bool MemEquals(uintptr_t address, std::initializer_list val) { @@ -202,6 +243,14 @@ namespace Memory namespace VP { + enum class HookType + { + Call, + Jump, + }; + + using Memory::DynBaseAddress; + template inline void Patch(AT address, T value) { @@ -247,8 +296,8 @@ namespace Memory Memory::ReadOffsetValue(address, var); } - template - inline void InjectHook(AT address, HT hook) + template + inline void InjectHook(AT address, Func hook) { DWORD dwProtect; @@ -257,13 +306,13 @@ namespace Memory VirtualProtect((void*)((DWORD_PTR)address + 1), 4, dwProtect, &dwProtect); } - template - inline void InjectHook(AT address, HT hook, unsigned int nType) + template + inline void InjectHook(AT address, Func hook, HookType type) { DWORD dwProtect; VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect); - Memory::InjectHook( address, hook, nType ); + Memory::InjectHook( address, hook, static_cast(type) ); VirtualProtect((void*)address, 5, dwProtect, &dwProtect); } @@ -279,6 +328,15 @@ namespace Memory return Memory::ReadCallFrom(address, offset); } + constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook) + { + DWORD dwProtect; + + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect); + Memory::InterceptCall(address, func, hook); + VirtualProtect((void*)address, 5, dwProtect, &dwProtect); + }; + #ifndef _MEMORY_NO_CRT inline bool MemEquals(uintptr_t address, std::initializer_list val) { @@ -294,6 +352,14 @@ namespace Memory namespace DynBase { + enum class HookType + { + Call, + Jump, + }; + + using Memory::DynBaseAddress; + template inline void Patch(AT address, T value) { @@ -326,16 +392,16 @@ namespace Memory VP::ReadOffsetValue(DynBaseAddress(address), var); } - template - inline void InjectHook(AT address, HT hook) + template + inline void InjectHook(AT address, Func hook) { VP::InjectHook(DynBaseAddress(address), hook); } - template - inline void InjectHook(AT address, HT hook, unsigned int nType) + template + inline void InjectHook(AT address, Func hook, HookType type) { - VP::InjectHook(DynBaseAddress(address), hook, nType); + VP::InjectHook(DynBaseAddress(address), hook, static_cast(type)); } template @@ -347,9 +413,14 @@ namespace Memory template inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0) { - Memory::ReadCallFrom(DynBaseAddress(address), offset); + return Memory::ReadCallFrom(DynBaseAddress(address), offset); } + constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook) + { + VP::InterceptCall(DynBaseAddress(address), func, hook); + }; + #ifndef _MEMORY_NO_CRT inline bool MemEquals(uintptr_t address, std::initializer_list val) { @@ -367,104 +438,4 @@ namespace Memory }; }; -#ifndef _MEMORY_NO_CRT - -#include -#include -#include - -namespace ScopedUnprotect -{ - class Unprotect - { - public: - ~Unprotect() - { - for ( auto& it : m_queriedProtects ) - { - DWORD dwOldProtect; - VirtualProtect( std::get<0>(it), std::get<1>(it), std::get<2>(it), &dwOldProtect ); - } - } - - protected: - Unprotect() = default; - - void UnprotectRange( DWORD_PTR BaseAddress, SIZE_T Size ) - { - SIZE_T QueriedSize = 0; - while ( QueriedSize < Size ) - { - MEMORY_BASIC_INFORMATION MemoryInf; - DWORD dwOldProtect; - - VirtualQuery( (LPCVOID)(BaseAddress + QueriedSize), &MemoryInf, sizeof(MemoryInf) ); - if ( MemoryInf.State == MEM_COMMIT && (MemoryInf.Type & MEM_IMAGE) != 0 && - (MemoryInf.Protect & (PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_READWRITE|PAGE_WRITECOPY)) == 0 ) - { - const bool wasExecutable = (MemoryInf.Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ)) != 0; - VirtualProtect( MemoryInf.BaseAddress, MemoryInf.RegionSize, wasExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &dwOldProtect ); - m_queriedProtects.emplace_front( MemoryInf.BaseAddress, MemoryInf.RegionSize, MemoryInf.Protect ); - } - QueriedSize += MemoryInf.RegionSize; - } - } - - private: - std::forward_list< std::tuple< LPVOID, SIZE_T, DWORD > > m_queriedProtects; - }; - - class Section : public Unprotect - { - public: - Section( HINSTANCE hInstance, const char* name ) - { - PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew); - PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(ntHeader); - - for ( SIZE_T i = 0, j = ntHeader->FileHeader.NumberOfSections; i < j; ++i, ++pSection ) - { - if ( strncmp( (const char*)pSection->Name, name, IMAGE_SIZEOF_SHORT_NAME ) == 0 ) - { - const DWORD_PTR VirtualAddress = (DWORD_PTR)hInstance + pSection->VirtualAddress; - const SIZE_T VirtualSize = pSection->Misc.VirtualSize; - UnprotectRange( VirtualAddress, VirtualSize ); - - m_locatedSection = true; - break; - } - } - }; - - bool SectionLocated() const { return m_locatedSection; } - - private: - bool m_locatedSection = false; - }; - - class FullModule : public Unprotect - { - public: - FullModule( HINSTANCE hInstance ) - { - PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew); - UnprotectRange( (DWORD_PTR)hInstance, ntHeader->OptionalHeader.SizeOfImage ); - } - }; - - inline std::unique_ptr UnprotectSectionOrFullModule( HINSTANCE hInstance, const char* name ) - { - std::unique_ptr
section = std::make_unique
( hInstance, name ); - if ( !section->SectionLocated() ) - { - return std::make_unique( hInstance ); - } - return section; - } -}; - #endif - -#endif - -#endif \ No newline at end of file diff --git a/MK11Hook/utils/Patterns.cpp b/MK11Hook/utils/Patterns.cpp index e8c36bd..13bceda 100644 --- a/MK11Hook/utils/Patterns.cpp +++ b/MK11Hook/utils/Patterns.cpp @@ -8,7 +8,11 @@ #include "Patterns.h" #define WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX #define NOMINMAX +#endif + #include #include @@ -19,7 +23,7 @@ #if PATTERNS_USE_HINTS - // from boost someplace +// from boost someplace template struct basic_fnv_1 { @@ -46,235 +50,243 @@ typedef basic_fnv_1 fnv_1; namespace hook { - ptrdiff_t details::get_process_base() - { - return ptrdiff_t(GetModuleHandle(nullptr)); - } +ptrdiff_t details::get_process_base() +{ + return ptrdiff_t(GetModuleHandle(nullptr)); +} #if PATTERNS_USE_HINTS - static auto& getHints() - { - static std::multimap hints; - return hints; - } +static auto& getHints() +{ + static std::multimap hints; + return hints; +} #endif - static void TransformPattern(std::string_view pattern, std::basic_string& data, std::basic_string& mask) +static void TransformPattern(std::string_view pattern, std::basic_string& data, std::basic_string& mask) +{ + uint8_t tempDigit = 0; + bool tempFlag = false; + + auto tol = [] (char ch) -> uint8_t { - uint8_t tempDigit = 0; - bool tempFlag = false; + if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10); + if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10); + return uint8_t(ch - '0'); + }; - auto tol = [](char ch) -> uint8_t + for (auto ch : pattern) + { + if (ch == ' ') { - if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10); - if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10); - return uint8_t(ch - '0'); - }; - - for (auto ch : pattern) + continue; + } + else if (ch == '?') { - if (ch == ' ') - { - continue; - } - else if (ch == '?') + data.push_back(0); + mask.push_back(0); + } + else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) + { + uint8_t thisDigit = tol(ch); + + if (!tempFlag) { - data.push_back(0); - mask.push_back(0); + tempDigit = thisDigit << 4; + tempFlag = true; } - else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) + else { - uint8_t thisDigit = tol(ch); - - if (!tempFlag) - { - tempDigit = thisDigit << 4; - tempFlag = true; - } - else - { - tempDigit |= thisDigit; - tempFlag = false; - - data.push_back(tempDigit); - mask.push_back(0xFF); - } + tempDigit |= thisDigit; + tempFlag = false; + + data.push_back(tempDigit); + mask.push_back(0xFF); } } } +} - class executable_meta - { - private: - uintptr_t m_begin; - uintptr_t m_end; - - template - TReturn* getRVA(TOffset rva) - { - return (TReturn*)(m_begin + rva); - } +class executable_meta +{ +private: + uintptr_t m_begin; + uintptr_t m_end; - public: - explicit executable_meta(uintptr_t module) - : m_begin(module) - { - PIMAGE_DOS_HEADER dosHeader = getRVA(0); - PIMAGE_NT_HEADERS ntHeader = getRVA(dosHeader->e_lfanew); +public: + explicit executable_meta(uintptr_t module) + { + PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(module); + PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(module + dosHeader->e_lfanew); - m_end = m_begin + ntHeader->OptionalHeader.SizeOfImage; - } + m_begin = module + ntHeader->OptionalHeader.BaseOfCode; + m_end = m_begin + ntHeader->OptionalHeader.SizeOfCode; - executable_meta(uintptr_t begin, uintptr_t end) - : m_begin(begin), m_end(end) + // Executables with DRM bypassed may lie in their SizeOfCode and underreport severely + // We can somewhat detect this by checking if the code entry point is past + // these boundaries. It's not perfect, but it's safe. + const uintptr_t entryPoint = module + ntHeader->OptionalHeader.AddressOfEntryPoint; + if (entryPoint >= m_begin && entryPoint < m_end) { + return; } - inline uintptr_t begin() const { return m_begin; } - inline uintptr_t end() const { return m_end; } - }; + // Alternate heuristics - scan the entire executable, minus headers + const uintptr_t sizeOfHeaders = ntHeader->OptionalHeader.SizeOfHeaders; + m_begin = module + sizeOfHeaders; + m_end = module + (ntHeader->OptionalHeader.SizeOfImage - sizeOfHeaders); + } - namespace details + executable_meta(uintptr_t begin, uintptr_t end) + : m_begin(begin), m_end(end) { + } - void basic_pattern_impl::Initialize(std::string_view pattern) - { - // get the hash for the base pattern + inline uintptr_t begin() const { return m_begin; } + inline uintptr_t end() const { return m_end; } +}; + +namespace details +{ + +void basic_pattern_impl::Initialize(std::string_view pattern) +{ + // get the hash for the base pattern #if PATTERNS_USE_HINTS - m_hash = fnv_1()(pattern); + m_hash = fnv_1()(pattern); #endif - // transform the base pattern from IDA format to canonical format - TransformPattern(pattern, m_bytes, m_mask); + // transform the base pattern from IDA format to canonical format + TransformPattern(pattern, m_bytes, m_mask); #if PATTERNS_USE_HINTS - // if there's hints, try those first + // if there's hints, try those first #if PATTERNS_CAN_SERIALIZE_HINTS - if (m_rangeStart == reinterpret_cast(GetModuleHandle(nullptr))) + if (m_rangeStart == reinterpret_cast(GetModuleHandle(nullptr))) #endif - { - auto range = getHints().equal_range(m_hash); - - if (range.first != range.second) - { - std::for_each(range.first, range.second, [&](const auto& hint) - { - ConsiderHint(hint.second); - }); - - // if the hints succeeded, we don't need to do anything more - if (!m_matches.empty()) - { - m_matched = true; - return; - } - } - } -#endif - } + { + auto range = getHints().equal_range(m_hash); - void basic_pattern_impl::EnsureMatches(uint32_t maxCount) + if (range.first != range.second) { - if (m_matched) + std::for_each(range.first, range.second, [&] (const auto& hint) + { + ConsiderHint(hint.second); + }); + + // if the hints succeeded, we don't need to do anything more + if (!m_matches.empty()) { + m_matched = true; return; } + } + } +#endif +} + +void basic_pattern_impl::EnsureMatches(uint32_t maxCount) +{ + if (m_matched) + { + return; + } - // scan the executable for code - executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_rangeStart); + // scan the executable for code + executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_rangeStart); - auto matchSuccess = [&](uintptr_t address) - { + auto matchSuccess = [&] (uintptr_t address) + { #if PATTERNS_USE_HINTS - getHints().emplace(m_hash, address); + getHints().emplace(m_hash, address); #else - (void)address; + (void)address; #endif - return (m_matches.size() == maxCount); - }; + return (m_matches.size() == maxCount); + }; - const uint8_t* pattern = m_bytes.data(); - const uint8_t* mask = m_mask.data(); - const size_t maskSize = m_mask.size(); - const size_t lastWild = m_mask.find_last_not_of(uint8_t(0xFF)); + const uint8_t* pattern = m_bytes.data(); + const uint8_t* mask = m_mask.data(); + const size_t maskSize = m_mask.size(); + const size_t lastWild = m_mask.find_last_not_of(uint8_t(0xFF)); - ptrdiff_t Last[256]; + ptrdiff_t Last[256]; - std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast(lastWild)); + std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast(lastWild) ); - for (ptrdiff_t i = 0; i < static_cast(maskSize); ++i) - { - if (Last[pattern[i]] < i) - { - Last[pattern[i]] = i; - } - } + for ( ptrdiff_t i = 0; i < static_cast(maskSize); ++i ) + { + if ( Last[ pattern[i] ] < i ) + { + Last[ pattern[i] ] = i; + } + } + + for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;) + { + uint8_t* ptr = reinterpret_cast(i); + ptrdiff_t j = maskSize - 1; - for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;) + while((j >= 0) && pattern[j] == (ptr[j] & mask[j])) j--; + + if(j < 0) + { + m_matches.emplace_back(ptr); + + if (matchSuccess(i)) { - uint8_t* ptr = reinterpret_cast(i); - ptrdiff_t j = maskSize - 1; - - while ((j >= 0) && pattern[j] == (ptr[j] & mask[j])) j--; - - if (j < 0) - { - m_matches.emplace_back(ptr); - - if (matchSuccess(i)) - { - break; - } - i++; - } - else i += std::max(ptrdiff_t(1), j - Last[ptr[j]]); + break; } - - m_matched = true; + i++; } + else i += std::max(ptrdiff_t(1), j - Last[ ptr[j] ]); + } - bool basic_pattern_impl::ConsiderHint(uintptr_t offset) - { - uint8_t* ptr = reinterpret_cast(offset); + m_matched = true; +} + +bool basic_pattern_impl::ConsiderHint(uintptr_t offset) +{ + uint8_t* ptr = reinterpret_cast(offset); #if PATTERNS_CAN_SERIALIZE_HINTS - const uint8_t* pattern = m_bytes.data(); - const uint8_t* mask = m_mask.data(); + const uint8_t* pattern = m_bytes.data(); + const uint8_t* mask = m_mask.data(); - for (size_t i = 0, j = m_mask.size(); i < j; i++) - { - if (pattern[i] != (ptr[i] & mask[i])) - { - return false; - } - } + for (size_t i = 0, j = m_mask.size(); i < j; i++) + { + if (pattern[i] != (ptr[i] & mask[i])) + { + return false; + } + } #endif - m_matches.emplace_back(ptr); + m_matches.emplace_back(ptr); - return true; - } + return true; +} #if PATTERNS_USE_HINTS && PATTERNS_CAN_SERIALIZE_HINTS - void basic_pattern_impl::hint(uint64_t hash, uintptr_t address) - { - auto& hints = getHints(); - - auto range = hints.equal_range(hash); +void basic_pattern_impl::hint(uint64_t hash, uintptr_t address) +{ + auto& hints = getHints(); - for (auto it = range.first; it != range.second; ++it) - { - if (it->second == address) - { - return; - } - } + auto range = hints.equal_range(hash); - hints.emplace(hash, address); + for (auto it = range.first; it != range.second; ++it) + { + if (it->second == address) + { + return; } + } + + hints.emplace(hash, address); +} #endif - } -} \ No newline at end of file +} +} diff --git a/MK11Hook/utils/Patterns.h b/MK11Hook/utils/Patterns.h index 8c115d6..fe5d6c6 100644 --- a/MK11Hook/utils/Patterns.h +++ b/MK11Hook/utils/Patterns.h @@ -8,10 +8,12 @@ #pragma once #include +#include #include +#include #include -#if defined(_CPPUNWIND) && !defined(PATTERNS_SUPPRESS_EXCEPTIONS) +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(PATTERNS_SUPPRESS_EXCEPTIONS) #define PATTERNS_ENABLE_EXCEPTIONS #endif @@ -35,7 +37,7 @@ namespace hook static void count(bool countMatches) { if (!countMatches) { throw txn_exception{}; } } }; #else - struct exception_err_policy + struct exception_err_policy : public assert_err_policy { }; #endif @@ -57,6 +59,11 @@ namespace hook char* ptr = reinterpret_cast(m_pointer); return reinterpret_cast(ptr + offset); } + + uintptr_t get_uintptr(ptrdiff_t offset = 0) const + { + return reinterpret_cast(get(offset)); + } }; namespace details @@ -121,7 +128,23 @@ namespace hook inline basic_pattern_impl(std::basic_string_view bytes, std::basic_string_view mask) : basic_pattern_impl(get_process_base()) { - assert(bytes.length() == mask.length()); + assert( bytes.length() == mask.length() ); + m_bytes = std::move(bytes); + m_mask = std::move(mask); + } + + inline basic_pattern_impl(void* module, std::basic_string_view bytes, std::basic_string_view mask) + : basic_pattern_impl(reinterpret_cast(module)) + { + assert( bytes.length() == mask.length() ); + m_bytes = std::move(bytes); + m_mask = std::move(mask); + } + + inline basic_pattern_impl(uintptr_t begin, uintptr_t end, std::basic_string_view bytes, std::basic_string_view mask) + : basic_pattern_impl(begin, end) + { + assert( bytes.length() == mask.length() ); m_bytes = std::move(bytes); m_mask = std::move(mask); } @@ -185,18 +208,18 @@ namespace hook template inline auto get_first(ptrdiff_t offset = 0) { - return get_one().get(offset); + return get_one().template get(offset); } template - inline Pred for_each_result(Pred&& pred) + inline Pred for_each_result(Pred pred) { EnsureMatches(UINT32_MAX); - for (auto it : m_matches) + for (auto match : m_matches) { - std::forward(pred)(it); + pred(match); } - return std::forward(pred); + return pred; } public: @@ -227,6 +250,11 @@ namespace hook return pattern(std::move(pattern_string)).get_first(offset); } + inline auto get_pattern_uintptr(std::string_view pattern_string, ptrdiff_t offset = 0) + { + return pattern(std::move(pattern_string)).get_one().get_uintptr(offset); + } + namespace txn { using pattern = hook::basic_pattern; @@ -247,5 +275,10 @@ namespace hook { return pattern(std::move(pattern_string)).get_first(offset); } + + inline auto get_pattern_uintptr(std::string_view pattern_string, ptrdiff_t offset = 0) + { + return pattern(std::move(pattern_string)).get_one().get_uintptr(offset); + } } -} \ No newline at end of file +}