mirror of
https://github.com/EricPlayZ/EGameTools.git
synced 2025-07-18 17:37:53 +08:00
- Added compatibility with v1.19 Tower Raid: Halloween Run update
- Improved CPU performance at game startup when using the mod
This commit is contained in:
@ -35,7 +35,6 @@
|
|||||||
<ClCompile Include="source\game\GamePH\FreeCamera.cpp" />
|
<ClCompile Include="source\game\GamePH\FreeCamera.cpp" />
|
||||||
<ClCompile Include="source\game\GamePH\GameDI_PH.cpp" />
|
<ClCompile Include="source\game\GamePH\GameDI_PH.cpp" />
|
||||||
<ClCompile Include="source\game\GamePH\GameDI_PH2.cpp" />
|
<ClCompile Include="source\game\GamePH\GameDI_PH2.cpp" />
|
||||||
<ClCompile Include="source\game\GamePH\gen_TPPModel.cpp" />
|
|
||||||
<ClCompile Include="source\game\GamePH\game_hooks.cpp" />
|
<ClCompile Include="source\game\GamePH\game_hooks.cpp" />
|
||||||
<ClCompile Include="source\game\GamePH\InventoryContainerDI.cpp" />
|
<ClCompile Include="source\game\GamePH\InventoryContainerDI.cpp" />
|
||||||
<ClCompile Include="source\game\GamePH\InventoryItem.cpp" />
|
<ClCompile Include="source\game\GamePH\InventoryItem.cpp" />
|
||||||
@ -93,6 +92,14 @@
|
|||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\kiero.cpp" />
|
<ClCompile Include="source\kiero.cpp" />
|
||||||
|
<ClCompile Include="source\memscan\memscan.c">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\memscan\util\util.c">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="source\menu\camera.cpp" />
|
<ClCompile Include="source\menu\camera.cpp" />
|
||||||
<ClCompile Include="source\menu\debug.cpp" />
|
<ClCompile Include="source\menu\debug.cpp" />
|
||||||
<ClCompile Include="source\menu\init.cpp" />
|
<ClCompile Include="source\menu\init.cpp" />
|
||||||
@ -140,7 +147,6 @@
|
|||||||
<ClInclude Include="source\game\GamePH\FreeCamera.h" />
|
<ClInclude Include="source\game\GamePH\FreeCamera.h" />
|
||||||
<ClInclude Include="source\game\GamePH\GameDI_PH.h" />
|
<ClInclude Include="source\game\GamePH\GameDI_PH.h" />
|
||||||
<ClInclude Include="source\game\GamePH\GameDI_PH2.h" />
|
<ClInclude Include="source\game\GamePH\GameDI_PH2.h" />
|
||||||
<ClInclude Include="source\game\GamePH\gen_TPPModel.h" />
|
|
||||||
<ClInclude Include="source\game\GamePH\InventoryContainerDI.h" />
|
<ClInclude Include="source\game\GamePH\InventoryContainerDI.h" />
|
||||||
<ClInclude Include="source\game\GamePH\InventoryItem.h" />
|
<ClInclude Include="source\game\GamePH\InventoryItem.h" />
|
||||||
<ClInclude Include="source\game\GamePH\InventoryMoney.h" />
|
<ClInclude Include="source\game\GamePH\InventoryMoney.h" />
|
||||||
@ -179,6 +185,8 @@
|
|||||||
<ClInclude Include="source\ImGui\imstb_truetype.h" />
|
<ClInclude Include="source\ImGui\imstb_truetype.h" />
|
||||||
<ClInclude Include="source\ImGui\misc\freetype\imgui_freetype.h" />
|
<ClInclude Include="source\ImGui\misc\freetype\imgui_freetype.h" />
|
||||||
<ClInclude Include="source\kiero.h" />
|
<ClInclude Include="source\kiero.h" />
|
||||||
|
<ClInclude Include="source\memscan\memscan.h" />
|
||||||
|
<ClInclude Include="source\memscan\util\util.h" />
|
||||||
<ClInclude Include="source\menu\camera.h" />
|
<ClInclude Include="source\menu\camera.h" />
|
||||||
<ClInclude Include="source\menu\debug.h" />
|
<ClInclude Include="source\menu\debug.h" />
|
||||||
<ClInclude Include="source\menu\init.h" />
|
<ClInclude Include="source\menu\init.h" />
|
||||||
@ -271,7 +279,7 @@
|
|||||||
</Optimization>
|
</Optimization>
|
||||||
<IntrinsicFunctions>
|
<IntrinsicFunctions>
|
||||||
</IntrinsicFunctions>
|
</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>pch;source\spdlog\include;source\ImGui\freetype\include;source\ImGui;source\MinHook;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>pch;source\spdlog\include;source\ImGui\freetype\include;source\ImGui;source\MinHook;source\memscan;</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_$(PlatformTarget).pch</PrecompiledHeaderOutputFile>
|
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_$(PlatformTarget).pch</PrecompiledHeaderOutputFile>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -301,7 +309,7 @@
|
|||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
<AdditionalIncludeDirectories>pch;source\spdlog\include;source\ImGui\freetype\include;source\ImGui;source\MinHook;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>pch;source\spdlog\include;source\ImGui\freetype\include;source\ImGui;source\MinHook;source\memscan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<DebugInformationFormat>None</DebugInformationFormat>
|
<DebugInformationFormat>None</DebugInformationFormat>
|
||||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_$(PlatformTarget).pch</PrecompiledHeaderOutputFile>
|
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_$(PlatformTarget).pch</PrecompiledHeaderOutputFile>
|
||||||
|
@ -133,9 +133,6 @@
|
|||||||
<ClCompile Include="source\game\GamePH\GameDI_PH2.cpp">
|
<ClCompile Include="source\game\GamePH\GameDI_PH2.cpp">
|
||||||
<Filter>game\GamePH</Filter>
|
<Filter>game\GamePH</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\game\GamePH\gen_TPPModel.cpp">
|
|
||||||
<Filter>game\GamePH</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\game\GamePH\game_hooks.cpp">
|
<ClCompile Include="source\game\GamePH\game_hooks.cpp">
|
||||||
<Filter>game\GamePH</Filter>
|
<Filter>game\GamePH</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -212,6 +209,12 @@
|
|||||||
<ClCompile Include="source\menu\teleport.cpp">
|
<ClCompile Include="source\menu\teleport.cpp">
|
||||||
<Filter>menu</Filter>
|
<Filter>menu</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\memscan\memscan.c">
|
||||||
|
<Filter>memscan</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\memscan\util\util.c">
|
||||||
|
<Filter>memscan\util</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="source\kiero.h" />
|
<ClInclude Include="source\kiero.h" />
|
||||||
@ -364,9 +367,6 @@
|
|||||||
<ClInclude Include="source\game\GamePH\GameDI_PH2.h">
|
<ClInclude Include="source\game\GamePH\GameDI_PH2.h">
|
||||||
<Filter>game\GamePH</Filter>
|
<Filter>game\GamePH</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\game\GamePH\gen_TPPModel.h">
|
|
||||||
<Filter>game\GamePH</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\game\GamePH\LevelDI.h">
|
<ClInclude Include="source\game\GamePH\LevelDI.h">
|
||||||
<Filter>game\GamePH</Filter>
|
<Filter>game\GamePH</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -453,6 +453,12 @@
|
|||||||
<ClInclude Include="source\menu\teleport.h">
|
<ClInclude Include="source\menu\teleport.h">
|
||||||
<Filter>menu</Filter>
|
<Filter>menu</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\memscan\memscan.h">
|
||||||
|
<Filter>memscan</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\memscan\util\util.h">
|
||||||
|
<Filter>memscan\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="MinHook">
|
<Filter Include="MinHook">
|
||||||
@ -497,5 +503,11 @@
|
|||||||
<Filter Include="ImGui\misc\freetype">
|
<Filter Include="ImGui\misc\freetype">
|
||||||
<UniqueIdentifier>{122420d5-ac60-4778-80bf-1384697fcc44}</UniqueIdentifier>
|
<UniqueIdentifier>{122420d5-ac60-4778-80bf-1384697fcc44}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="memscan">
|
||||||
|
<UniqueIdentifier>{1e82ab1f-550e-4fac-8fac-0888e1e62873}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="memscan\util">
|
||||||
|
<UniqueIdentifier>{7e81ee9f-f74a-4af8-8a10-7530b26c3c86}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -66,6 +66,7 @@
|
|||||||
#include <imstb_textedit.h>
|
#include <imstb_textedit.h>
|
||||||
#include <imstb_truetype.h>
|
#include <imstb_truetype.h>
|
||||||
#include <MinHook.h>
|
#include <MinHook.h>
|
||||||
|
#include <memscan.h>
|
||||||
|
|
||||||
#include "..\source\config\ini.h"
|
#include "..\source\config\ini.h"
|
||||||
#include "..\source\game\Engine\GameSpeedHandler.h"
|
#include "..\source\game\Engine\GameSpeedHandler.h"
|
||||||
|
@ -109,7 +109,7 @@ With all of that said, here is finally what this update brings:
|
|||||||
- Added "Teleport to Waypoint" (Teleport)
|
- Added "Teleport to Waypoint" (Teleport)
|
||||||
- WARNING: if the waypoint is selected to track an object/item on the map, Teleport to Waypoint will not work, if so just set the waypoint nearby instead
|
- WARNING: if the waypoint is selected to track an object/item on the map, Teleport to Waypoint will not work, if so just set the waypoint nearby instead
|
||||||
- WARNING: your player height won't change when teleporting, so make sure you catch yourself if you fall under the map because of the teleportation
|
- WARNING: your player height won't change when teleporting, so make sure you catch yourself if you fall under the map because of the teleportation
|
||||||
- Added "Saved Locations" in Teleport menu, with the ability of saving, deleting and teleporting to said locations; these locations are saved in the config file and will contain a name and a set of coordinates for each location; to reset back to the default list, remove the list from inside the config file and go back into the game
|
- Added "Saved Locations" in Teleport menu, with the ability of saving, deleting and teleporting to said locations; these locations are saved in the config file and will contain a name and a set of coordinates for each location; to reset back to the default list, remove the list from inside the config file and go back into the game; thank you to @Synsteric on Discord for helping me make the default list!
|
||||||
- Added "Increase Data PAKs Limit" (Misc; requires game restart to apply) - you can now add more than 8 data PAKs, e.g. data8.pak, data9.pak, data10.pak, etc, up to 200 PAKs in total
|
- Added "Increase Data PAKs Limit" (Misc; requires game restart to apply) - you can now add more than 8 data PAKs, e.g. data8.pak, data9.pak, data10.pak, etc, up to 200 PAKs in total
|
||||||
- Added "Disable Data PAKs CRC Check" (Misc; requires game restart to apply) - stops the game from scanning data PAKs, which allows you to use data PAK mods in multiplayer as well
|
- Added "Disable Data PAKs CRC Check" (Misc; requires game restart to apply) - stops the game from scanning data PAKs, which allows you to use data PAK mods in multiplayer as well
|
||||||
- Added "Disable Savegame CRC Check" (Misc; requires game restart to apply) - stops the game from falsely saying your savegame is corrupt whenever you modify it
|
- Added "Disable Savegame CRC Check" (Misc; requires game restart to apply) - stops the game from falsely saying your savegame is corrupt whenever you modify it
|
||||||
@ -132,6 +132,12 @@ NOTE: Any mods that are put inside "EGameTools\UserModFiles" as a regular file (
|
|||||||
|
|
||||||
|
|
||||||
I'm soon starting my exams and won't really have the time to update the mod the way I did right now. I had a 2 week leave and so I had plenty of time to further develop this mod.
|
I'm soon starting my exams and won't really have the time to update the mod the way I did right now. I had a 2 week leave and so I had plenty of time to further develop this mod.
|
||||||
If anyone is looking to help with development, I'm all eyes and ears! Thank you!)" }
|
If anyone is looking to help with development, I'm all eyes and ears! Thank you!)" },
|
||||||
|
{ "v1.2.1",
|
||||||
|
R"(- Added compatibility with v1.17.2 Tower Raid update
|
||||||
|
- Added a .PDB file included by default with the mod, for debugging purposes in case the game crashes, now I can more easily detect the cause of a game crash!
|
||||||
|
- Added a crash handler which handles game crashes and generates a "EGameTools-dump.dmp" file in the game's exe directory for debugging purposes; if you encounter a crash and this file gets generated, please send it to me anywhere you can, for example on Discord, so I can try to find out the cause of the game crash!
|
||||||
|
- Fixed "Game Speed" (World) not getting applied with the mod menu opened while having another tab selected other than the World tab
|
||||||
|
I have some things planned for the next updates, but time will decide when I'll be able to work on the updates. I'm almost done with my exams!)" }
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -20,7 +20,7 @@ namespace Core {
|
|||||||
DWORD prev_mode = 0;
|
DWORD prev_mode = 0;
|
||||||
const HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
const HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
GetConsoleMode(hInput, &prev_mode);
|
GetConsoleMode(hInput, &prev_mode);
|
||||||
SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS);
|
SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE* f = nullptr;
|
static FILE* f = nullptr;
|
||||||
@ -43,7 +43,7 @@ namespace Core {
|
|||||||
int rendererAPI = 0;
|
int rendererAPI = 0;
|
||||||
DWORD gameVer = 0;
|
DWORD gameVer = 0;
|
||||||
|
|
||||||
static std::counting_semaphore<4> maxHookThreads(4);
|
std::counting_semaphore<4> maxHookThreads(4);
|
||||||
|
|
||||||
static void LoopHookRenderer() {
|
static void LoopHookRenderer() {
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -173,31 +173,37 @@ namespace Core {
|
|||||||
GamePH::PlayerHealthModule::UpdateClassAddr();
|
GamePH::PlayerHealthModule::UpdateClassAddr();
|
||||||
GamePH::PlayerInfectionModule::UpdateClassAddr();
|
GamePH::PlayerInfectionModule::UpdateClassAddr();
|
||||||
}
|
}
|
||||||
/*static bool WriteMiniDump(PEXCEPTION_POINTERS pExceptionPointers) {
|
#ifndef EXCP_HANDLER_DISABLE_DEBUG
|
||||||
|
static bool WriteMiniDump(PEXCEPTION_POINTERS pExceptionPointers) {
|
||||||
HANDLE hFile = CreateFileA("EGameTools-dump.dmp", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
HANDLE hFile = CreateFileA("EGameTools-dump.dmp", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
if (hFile == INVALID_HANDLE_VALUE)
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION mdei{};
|
MINIDUMP_EXCEPTION_INFORMATION mdei{};
|
||||||
mdei.ThreadId = GetCurrentThreadId();
|
|
||||||
mdei.ExceptionPointers = pExceptionPointers;
|
mdei.ExceptionPointers = pExceptionPointers;
|
||||||
mdei.ClientPointers = false;
|
mdei.ClientPointers = false;
|
||||||
|
|
||||||
int success = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, nullptr, nullptr);
|
int success = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, (pExceptionPointers ? &mdei : nullptr), nullptr, nullptr);
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
static long WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
|
static long WINAPI CrashHandler(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||||
spdlog::error("VEH threw an exception with code {}. Trying to continue execution, writing mini-dump in the mean time.", ExceptionInfo->ExceptionRecord->ExceptionCode);
|
spdlog::error("Crash Handler threw an exception with code {}. Game is exiting, writing mini-dump in the mean time.", ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||||
|
std::string errorMsg = "";
|
||||||
|
|
||||||
if (WriteMiniDump(ExceptionInfo))
|
if (WriteMiniDump(ExceptionInfo)) {
|
||||||
spdlog::info("Mini-dump written to \"EGameTools-dump.dmp\". Please send this to mod author for further help!");
|
spdlog::info("Mini-dump written to \"EGameTools-dump.dmp\". Please send this to mod author for further help!");
|
||||||
else
|
errorMsg = "EGameTools encountered a fatal error that caused the game to crash.\n\nA file \"" + Utils::Files::GetCurrentProcDirectory() + "\\EGameTools-dump.dmp\" has been generated. Please send this file to the author of the mod!\n\nThe game will now close once you press OK.";
|
||||||
|
} else {
|
||||||
spdlog::error("Failed to write mini-dump.");
|
spdlog::error("Failed to write mini-dump.");
|
||||||
|
errorMsg = "EGameTools encountered a fatal error that caused the game to crash.\n\nEGameTools failed to generate a crash dump file unfortunately, which means it is harder to find the cause of the crash.\n\nThe game will now close once you press OK.";
|
||||||
|
}
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
MessageBoxA(nullptr, errorMsg.c_str(), "Fatal game error", MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
|
||||||
}*/
|
exit(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
static void GameVersionCheck() {
|
static void GameVersionCheck() {
|
||||||
try {
|
try {
|
||||||
gameVer = GamePH::GetCurrentGameVersion();
|
gameVer = GamePH::GetCurrentGameVersion();
|
||||||
@ -216,7 +222,9 @@ namespace Core {
|
|||||||
EnableConsole();
|
EnableConsole();
|
||||||
InitLogger();
|
InitLogger();
|
||||||
|
|
||||||
//AddVectoredExceptionHandler(0, &VectoredExceptionHandler);
|
#ifndef EXCP_HANDLER_DISABLE_DEBUG
|
||||||
|
AddVectoredExceptionHandler(0, &VectoredExceptionHandler);
|
||||||
|
#endif
|
||||||
|
|
||||||
spdlog::warn("Getting game version");
|
spdlog::warn("Getting game version");
|
||||||
GameVersionCheck();
|
GameVersionCheck();
|
||||||
@ -227,23 +235,16 @@ namespace Core {
|
|||||||
|
|
||||||
CreateSymlinkForLoadingFiles();
|
CreateSymlinkForLoadingFiles();
|
||||||
|
|
||||||
while (true) {
|
for (auto& hook : *Utils::Hook::HookBase::GetInstances()) {
|
||||||
if (!GetModuleHandle("gamedll_ph_x64_rwdi.dll") || !GetModuleHandle("engine_x64_rwdi.dll"))
|
std::thread([&hook]() {
|
||||||
continue;
|
maxHookThreads.acquire();
|
||||||
|
|
||||||
for (auto& hook : *Utils::Hook::HookBase::GetInstances()) {
|
spdlog::warn("Hooking \"{}\"", hook->name.data());
|
||||||
std::thread([&hook]() {
|
if (hook->HookLoop())
|
||||||
maxHookThreads.acquire();
|
spdlog::info("Hooked \"{}\"!", hook->name.data());
|
||||||
|
|
||||||
spdlog::warn("Hooking \"{}\"", hook->name.data());
|
maxHookThreads.release();
|
||||||
if (hook->HookLoop())
|
}).detach();
|
||||||
spdlog::info("Hooked \"{}\"!", hook->name.data());
|
|
||||||
|
|
||||||
maxHookThreads.release();
|
|
||||||
}).detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::warn("Sorting Player Variables");
|
spdlog::warn("Sorting Player Variables");
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define LLMH_IMPL_DISABLE_DEBUG // this is for disabling low-level mouse hook in case ure trying to debug and u dont want ur pc to die lol
|
#define LLMH_IMPL_DISABLE_DEBUG // this is for disabling low-level mouse hook in case ure trying to debug and u dont want ur pc to die lol
|
||||||
|
#define EXCP_HANDLER_DISABLE_DEBUG // this is for disabling exception handling in case ure trying to debug and u dont want ur debugger to keep crying about errors lol
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VK_NONE -1
|
#define VK_NONE -1
|
||||||
@ -16,9 +17,9 @@
|
|||||||
#define VK_MWHEELUP 0x101
|
#define VK_MWHEELUP 0x101
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr const char* MOD_VERSION_STR = "v1.2.3";
|
constexpr const char* MOD_VERSION_STR = "v1.2.4";
|
||||||
constexpr DWORD MOD_VERSION = 10203;
|
constexpr DWORD MOD_VERSION = 10204;
|
||||||
constexpr DWORD GAME_VER_COMPAT = 11800;
|
constexpr DWORD GAME_VER_COMPAT = 11900;
|
||||||
|
|
||||||
struct Key {
|
struct Key {
|
||||||
constexpr Key(std::string_view name, int code, ImGuiKey imGuiCode) : name(name), code(code), imGuiCode(imGuiCode) {}
|
constexpr Key(std::string_view name, int code, ImGuiKey imGuiCode) : name(name), code(code), imGuiCode(imGuiCode) {}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
extern void DisableConsole();
|
extern void DisableConsole();
|
||||||
|
|
||||||
|
extern std::counting_semaphore<4> maxHookThreads;
|
||||||
|
|
||||||
extern DWORD64 WINAPI MainThread(HMODULE hModule);
|
extern DWORD64 WINAPI MainThread(HMODULE hModule);
|
||||||
extern void Cleanup();
|
extern void Cleanup();
|
||||||
}
|
}
|
||||||
@ -22,10 +24,11 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD64 ul_reason_for_call, LPVOID lpRese
|
|||||||
switch (ul_reason_for_call) {
|
switch (ul_reason_for_call) {
|
||||||
case DLL_PROCESS_ATTACH: {
|
case DLL_PROCESS_ATTACH: {
|
||||||
MH_Initialize();
|
MH_Initialize();
|
||||||
Engine::Hooks::MountDataPaksHook.HookLoop();
|
|
||||||
Engine::Hooks::AuthenticateDataAddNewFileHook.HookLoop();
|
std::thread([]() { Core::maxHookThreads.acquire(); Engine::Hooks::MountDataPaksHook.HookLoop(); Core::maxHookThreads.release(); }).detach();
|
||||||
Engine::Hooks::FsCheckZipCrcHook.HookLoop();
|
std::thread([]() { Core::maxHookThreads.acquire(); Engine::Hooks::AuthenticateDataAddNewFileHook.HookLoop(); Core::maxHookThreads.release(); }).detach();
|
||||||
Engine::Hooks::FsOpenHook.HookLoop();
|
std::thread([]() { Core::maxHookThreads.acquire(); Engine::Hooks::FsCheckZipCrcHook.HookLoop(); Core::maxHookThreads.release(); }).detach();
|
||||||
|
std::thread([]() { Core::maxHookThreads.acquire(); Engine::Hooks::FsOpenHook.HookLoop(); Core::maxHookThreads.release(); }).detach();
|
||||||
|
|
||||||
DisableThreadLibraryCalls(hModule);
|
DisableThreadLibraryCalls(hModule);
|
||||||
hMainThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)Core::MainThread, hModule, 0, nullptr);
|
hMainThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)Core::MainThread, hModule, 0, nullptr);
|
||||||
|
@ -6,9 +6,9 @@ namespace Engine {
|
|||||||
class CBulletPhysicsCharacter {
|
class CBulletPhysicsCharacter {
|
||||||
public:
|
public:
|
||||||
union {
|
union {
|
||||||
buffer<0x8A0, Vector3> playerPos2;
|
buffer<0xA08, Vector3> playerPos2;
|
||||||
buffer<0x8B8, Vector3> playerPos;
|
buffer<0xA20, Vector3> playerPos;
|
||||||
buffer<0xC38, float> playerDownwardVelocity;
|
buffer<0xDA0, float> playerDownwardVelocity;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Vector3 posBeforeFreeze;
|
static Vector3 posBeforeFreeze;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "..\GamePH\GameDI_PH.h"
|
#include "..\GamePH\GameDI_PH.h"
|
||||||
#include "..\GamePH\LevelDI.h"
|
#include "..\GamePH\LevelDI.h"
|
||||||
#include "..\GamePH\gameph_misc.h"
|
#include "..\GamePH\gameph_misc.h"
|
||||||
#include "..\GamePH\gen_TPPModel.h"
|
|
||||||
#include "..\core.h"
|
#include "..\core.h"
|
||||||
#include "..\menu\camera.h"
|
#include "..\menu\camera.h"
|
||||||
#include "..\menu\misc.h"
|
#include "..\menu\misc.h"
|
||||||
|
@ -9,7 +9,7 @@ namespace GamePH {
|
|||||||
public:
|
public:
|
||||||
union {
|
union {
|
||||||
buffer<0x130, SessionCooperativeDI*> pSessionCooperativeDI;
|
buffer<0x130, SessionCooperativeDI*> pSessionCooperativeDI;
|
||||||
buffer<0x880, bool> blockPauseGameOnPlayerAfk;
|
buffer<0x908, bool> blockPauseGameOnPlayerAfk;
|
||||||
};
|
};
|
||||||
|
|
||||||
float GetGameTimeDelta();
|
float GetGameTimeDelta();
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
#include "..\buffer.h"
|
#include "..\buffer.h"
|
||||||
|
|
||||||
namespace GamePH {
|
namespace GamePH {
|
||||||
class gen_TPPModel;
|
class PlayerObjProperties;
|
||||||
|
|
||||||
class LocalClientDI {
|
class LocalClientDI {
|
||||||
public:
|
public:
|
||||||
union {
|
union {
|
||||||
buffer<0x90, gen_TPPModel*> pgen_TPPModel;
|
buffer<0x90, PlayerObjProperties*> pPlayerObjProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
static LocalClientDI* Get();
|
static LocalClientDI* Get();
|
||||||
|
@ -12,6 +12,8 @@ namespace GamePH {
|
|||||||
buffer<0xF0, Engine::CoPhysicsProperty*> pCoPhysicsProperty;
|
buffer<0xF0, Engine::CoPhysicsProperty*> pCoPhysicsProperty;
|
||||||
//buffer<0x2E80, bool> isOutOfBounds;
|
//buffer<0x2E80, bool> isOutOfBounds;
|
||||||
//buffer<0x2E84, float> outOfBoundsTimer;
|
//buffer<0x2E84, float> outOfBoundsTimer;
|
||||||
|
buffer<0x35E9, bool> enableTPPModel1;
|
||||||
|
buffer<0x35EA, bool> enableTPPModel2;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PlayerObjProperties* Get();
|
static PlayerObjProperties* Get();
|
||||||
|
@ -7,7 +7,7 @@ namespace GamePH {
|
|||||||
class PlayerState {
|
class PlayerState {
|
||||||
public:
|
public:
|
||||||
union {
|
union {
|
||||||
buffer<0x2B0, PlayerVariables*> playerVars;
|
buffer<0x300, PlayerVariables*> playerVars;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PlayerState* Get();
|
static PlayerState* Get();
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "LevelDI.h"
|
#include "LevelDI.h"
|
||||||
#include "PlayerHealthModule.h"
|
#include "PlayerHealthModule.h"
|
||||||
#include "PlayerInfectionModule.h"
|
#include "PlayerInfectionModule.h"
|
||||||
#include "gen_TPPModel.h"
|
#include "PlayerObjProperties.h"
|
||||||
|
|
||||||
namespace GamePH {
|
namespace GamePH {
|
||||||
namespace Hooks {
|
namespace Hooks {
|
||||||
@ -161,20 +161,20 @@ namespace GamePH {
|
|||||||
static Utils::Hook::MHook<LPVOID, void(*)(DWORD64, bool)> ShowTPPModelFunc3Hook{ "ShowTPPModelFunc3", &Offsets::Get_ShowTPPModelFunc3, &detourShowTPPModelFunc3 };
|
static Utils::Hook::MHook<LPVOID, void(*)(DWORD64, bool)> ShowTPPModelFunc3Hook{ "ShowTPPModelFunc3", &Offsets::Get_ShowTPPModelFunc3, &detourShowTPPModelFunc3 };
|
||||||
|
|
||||||
static void detourShowTPPModelFunc3(DWORD64 tppFunc2Addr, bool showTPPModel) {
|
static void detourShowTPPModelFunc3(DWORD64 tppFunc2Addr, bool showTPPModel) {
|
||||||
gen_TPPModel* pgen_TPPModel = gen_TPPModel::Get();
|
PlayerObjProperties* playerObjProperties = PlayerObjProperties::Get();
|
||||||
if (!pgen_TPPModel) {
|
if (!playerObjProperties) {
|
||||||
ShowTPPModelFunc3Hook.pOriginal(tppFunc2Addr, showTPPModel);
|
ShowTPPModelFunc3Hook.pOriginal(tppFunc2Addr, showTPPModel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showTPPModel && prevUseTPPModel) {
|
if (!showTPPModel && prevUseTPPModel) {
|
||||||
pgen_TPPModel->enableTPPModel2 = true;
|
playerObjProperties->enableTPPModel2 = true;
|
||||||
pgen_TPPModel->enableTPPModel1 = true;
|
playerObjProperties->enableTPPModel1 = true;
|
||||||
}
|
}
|
||||||
ShowTPPModelFunc3Hook.pOriginal(tppFunc2Addr, showTPPModel);
|
ShowTPPModelFunc3Hook.pOriginal(tppFunc2Addr, showTPPModel);
|
||||||
if (showTPPModel && prevUseTPPModel) {
|
if (showTPPModel && prevUseTPPModel) {
|
||||||
pgen_TPPModel->enableTPPModel2 = false;
|
playerObjProperties->enableTPPModel2 = false;
|
||||||
pgen_TPPModel->enableTPPModel1 = false;
|
playerObjProperties->enableTPPModel1 = false;
|
||||||
} else
|
} else
|
||||||
prevUseTPPModel = showTPPModel;
|
prevUseTPPModel = showTPPModel;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <pch.h>
|
#include <pch.h>
|
||||||
#include "..\offsets.h"
|
#include "..\offsets.h"
|
||||||
#include "GameDI_PH.h"
|
#include "GameDI_PH.h"
|
||||||
#include "gen_TPPModel.h"
|
#include "PlayerObjProperties.h"
|
||||||
|
|
||||||
namespace GamePH {
|
namespace GamePH {
|
||||||
const DWORD GetCurrentGameVersion() {
|
const DWORD GetCurrentGameVersion() {
|
||||||
@ -59,8 +59,8 @@ namespace GamePH {
|
|||||||
void(*pShowTPPModelFunc3)(DWORD64 tppFunc2Addr, bool showTPPModel) = (decltype(pShowTPPModelFunc3))Offsets::Get_ShowTPPModelFunc3();
|
void(*pShowTPPModelFunc3)(DWORD64 tppFunc2Addr, bool showTPPModel) = (decltype(pShowTPPModelFunc3))Offsets::Get_ShowTPPModelFunc3();
|
||||||
if (!pShowTPPModelFunc3)
|
if (!pShowTPPModelFunc3)
|
||||||
return;
|
return;
|
||||||
gen_TPPModel* pgen_TPPModel = gen_TPPModel::Get();
|
PlayerObjProperties* playerObjProperties = PlayerObjProperties::Get();
|
||||||
if (!pgen_TPPModel)
|
if (!playerObjProperties)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pShowTPPModelFunc3(tppFunc2Addr, showTPPModel);
|
pShowTPPModelFunc3(tppFunc2Addr, showTPPModel);
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
#include <pch.h>
|
|
||||||
#include "LocalClientDI.h"
|
|
||||||
#include "gen_TPPModel.h"
|
|
||||||
|
|
||||||
namespace GamePH {
|
|
||||||
gen_TPPModel* gen_TPPModel::Get() {
|
|
||||||
__try {
|
|
||||||
LocalClientDI* pLocalClientDI = LocalClientDI::Get();
|
|
||||||
if (!pLocalClientDI)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
gen_TPPModel* ptr = pLocalClientDI->pgen_TPPModel;
|
|
||||||
if (!Utils::Memory::IsValidPtrMod(ptr, "gamedll_ph_x64_rwdi.dll"))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "..\buffer.h"
|
|
||||||
|
|
||||||
namespace GamePH {
|
|
||||||
class gen_TPPModel {
|
|
||||||
public:
|
|
||||||
union {
|
|
||||||
buffer<0x2DB9, bool> enableTPPModel1;
|
|
||||||
buffer<0x2DBA, bool> enableTPPModel2;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gen_TPPModel* Get();
|
|
||||||
};
|
|
||||||
}
|
|
935
EGameTools/source/memscan/memscan.c
Normal file
935
EGameTools/source/memscan/memscan.c
Normal file
@ -0,0 +1,935 @@
|
|||||||
|
#include "memscan.h"
|
||||||
|
|
||||||
|
#include <memory.h> // memcmp
|
||||||
|
#include <string.h> // strlen
|
||||||
|
|
||||||
|
/* Types */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* example: {0x55, 0x8B, 0xEC} */
|
||||||
|
const ms_ubyte_t* m_data;
|
||||||
|
|
||||||
|
/* the former will result in '3' */
|
||||||
|
ms_usize_t m_size;
|
||||||
|
|
||||||
|
/* the n-th instance of a pattern within range, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
} ms_bytes_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* "55 8B EC" => ms_bytes_t({0x55, 0x8B, 0xEC}, 3, match)
|
||||||
|
* must be null terminated */
|
||||||
|
const char* m_data;
|
||||||
|
|
||||||
|
/* the n-th instance of a pattern within range, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
} ms_bytes_str_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* example: {0x8B, 0x0D} */
|
||||||
|
const ms_ubyte_t* m_data;
|
||||||
|
|
||||||
|
/* the former will result in '3' */
|
||||||
|
ms_usize_t m_size;
|
||||||
|
|
||||||
|
/* the n-th instance of a match within range, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
|
||||||
|
ms_follow_direction_t m_direction;
|
||||||
|
} ms_find_bytes_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* "8B 0C" => ms_find_bytes_t({0x8B, 0x0C}, 2, match, direction)
|
||||||
|
* must be null terminated */
|
||||||
|
const char* m_data;
|
||||||
|
|
||||||
|
/* the n-th instance of a match within range, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
|
||||||
|
ms_follow_direction_t m_direction;
|
||||||
|
} ms_find_str_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* numerical form of pointer to look for */
|
||||||
|
ms_uptr_t m_pointer;
|
||||||
|
|
||||||
|
/* the n-th instance of a match within range, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
|
||||||
|
bool m_swap_endianness;
|
||||||
|
} ms_xref_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* the string to look for */
|
||||||
|
const char* m_data;
|
||||||
|
|
||||||
|
/* string size */
|
||||||
|
ms_usize_t m_size;
|
||||||
|
|
||||||
|
/* the n-th instance of the reversed endianness address to the first
|
||||||
|
* character of the string, 0 - first */
|
||||||
|
ms_usize_t m_match;
|
||||||
|
} ms_string_xref_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* won't be reached if MEMSCAN_UNSAFE_OPTIMIZATIONS are on */
|
||||||
|
|
||||||
|
MS_FOLLOW_STATUS_NO_VALID_FOLLOW_INFO = 0,
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
/* overbounds on start */
|
||||||
|
MS_FOLLOW_STATUS_FAIL_LHS,
|
||||||
|
|
||||||
|
/* overbounds on end */
|
||||||
|
MS_FOLLOW_STATUS_FAIL_RHS,
|
||||||
|
|
||||||
|
/* broke before reaching match */
|
||||||
|
MS_FOLLOW_STATUS_INCOMPLETE,
|
||||||
|
|
||||||
|
/* follow has succeeded, state was set to OK */
|
||||||
|
MS_FOLLOW_STATUS_OK
|
||||||
|
} ms_follow_status_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ms_uptr_t m_address;
|
||||||
|
ms_follow_status_t m_status;
|
||||||
|
} ms_follow_t;
|
||||||
|
|
||||||
|
/* Methods */
|
||||||
|
|
||||||
|
/* Static */
|
||||||
|
|
||||||
|
static ms_follow_t
|
||||||
|
follow_until(const ms_uptr_t copy, const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_find_bytes_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_follow_t result = {0};
|
||||||
|
|
||||||
|
ms_uptr_t address = copy;
|
||||||
|
|
||||||
|
#if !MEMSCAN_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (find_bytes == NULL ||
|
||||||
|
(find_bytes != NULL &&
|
||||||
|
(find_bytes->m_data == NULL || find_bytes->m_size == 0))) {
|
||||||
|
result.m_address = 0;
|
||||||
|
result.m_status = MS_FOLLOW_STATUS_NO_VALID_FOLLOW_INFO;
|
||||||
|
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the following will run at least once, so you can follow regardless of
|
||||||
|
* current address. it will break upon a NULL address, or after the first
|
||||||
|
* overbounds byte, or upon a match in memory. */
|
||||||
|
|
||||||
|
ms_usize_t match = MEMSCAN_FIRST_MATCH;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
|
||||||
|
retry_label:
|
||||||
|
status = memcmp((void*)address, find_bytes->m_data, find_bytes->m_size);
|
||||||
|
|
||||||
|
while ((void*)address != NULL && address >= (start - 1) &&
|
||||||
|
address <= (end + 1) && status != 0) {
|
||||||
|
address +=
|
||||||
|
find_bytes->m_direction == MS_FOLLOW_DIRECTION_BACKWARDS ? -1 : 1;
|
||||||
|
|
||||||
|
status = memcmp((void*)address, find_bytes->m_data, find_bytes->m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.m_address = address;
|
||||||
|
|
||||||
|
/* if the address is smaller than start, then it is overbounds on the lhs,
|
||||||
|
* otherwise, if it is smaller than end, it is overbounds no the rhs,
|
||||||
|
* otherwise, if status is != 0, it is OK, otherwise, it is an incomplete
|
||||||
|
* follow */
|
||||||
|
|
||||||
|
result.m_status = (result.m_address < start
|
||||||
|
? MS_FOLLOW_STATUS_FAIL_LHS
|
||||||
|
: (result.m_address > end
|
||||||
|
? MS_FOLLOW_STATUS_FAIL_RHS
|
||||||
|
: (status != 0 ? MS_FOLLOW_STATUS_INCOMPLETE
|
||||||
|
: MS_FOLLOW_STATUS_OK)));
|
||||||
|
|
||||||
|
/* verify match */
|
||||||
|
|
||||||
|
if (match != find_bytes->m_match &&
|
||||||
|
result.m_status == MS_FOLLOW_STATUS_OK) {
|
||||||
|
++match;
|
||||||
|
address +=
|
||||||
|
find_bytes->m_direction == MS_FOLLOW_DIRECTION_BACKWARDS ? -1 : 1;
|
||||||
|
goto retry_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_label:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_bb_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_t* restrict bytes,
|
||||||
|
const ms_find_bytes_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
#if !MEMSCAN_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (bytes == NULL || (bytes && bytes->m_data == NULL)) {
|
||||||
|
result.m_status = MS_RESULT_NO_VALID_BYTES_INFO;
|
||||||
|
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
/* this value is meant to be used to deduce how many actual bytes were input
|
||||||
|
* to the formation, scaling to every platform's sizeof(unsigned char) */
|
||||||
|
|
||||||
|
const ms_usize_t bytes_len = bytes->m_size / sizeof *bytes->m_data;
|
||||||
|
|
||||||
|
/* here, bytes->m_size is used because we're doing pointer arithmetic */
|
||||||
|
|
||||||
|
const ms_ubyte_t* finish = (ms_ubyte_t*)(end - bytes->m_size);
|
||||||
|
|
||||||
|
ms_usize_t match = MEMSCAN_FIRST_MATCH;
|
||||||
|
|
||||||
|
#if !MEMSCAN_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (start >= (ms_uptr_t)finish) {
|
||||||
|
result.m_status = MS_RESULT_NO_VALID_SPAN;
|
||||||
|
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* loop over every byte from start to end */
|
||||||
|
|
||||||
|
for (ms_ubyte_t* current = (ms_ubyte_t*)start; current < finish;
|
||||||
|
++current) {
|
||||||
|
ms_result_status_t status = MS_RESULT_STATUS_FOUND;
|
||||||
|
|
||||||
|
/* run a scan from current byte to current byte + bytes_len to verify if
|
||||||
|
* we have a match */
|
||||||
|
|
||||||
|
for (ms_usize_t walker = 0; walker < bytes_len; ++walker) {
|
||||||
|
/* if the current byte at walker indice isn't equal to the current
|
||||||
|
* signature byte if it isn't our wildcard */
|
||||||
|
|
||||||
|
if (current[walker] != bytes->m_data[walker] &&
|
||||||
|
bytes->m_data[walker] != k_memscan_wildcard) {
|
||||||
|
/* declare the state as not found for the current iteration
|
||||||
|
* and go to the next one */
|
||||||
|
|
||||||
|
status = MS_RESULT_STATUS_NOT_FOUND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the state wasn't altered (as in, the checks have passed and the
|
||||||
|
* current byte matches our signature) */
|
||||||
|
|
||||||
|
if (status == MS_RESULT_STATUS_FOUND) {
|
||||||
|
/* verify n-th match */
|
||||||
|
|
||||||
|
if (match != bytes->m_match) {
|
||||||
|
++match;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pass our address and status to result */
|
||||||
|
|
||||||
|
result.m_address = (ms_uptr_t)current;
|
||||||
|
result.m_status = status;
|
||||||
|
|
||||||
|
/* attempt a follow */
|
||||||
|
|
||||||
|
const ms_follow_t follow =
|
||||||
|
follow_until(result.m_address, start, end, find_bytes);
|
||||||
|
|
||||||
|
switch (follow.m_status) {
|
||||||
|
case MS_FOLLOW_STATUS_OK: {
|
||||||
|
/* change the result address to the follow result,
|
||||||
|
* started from the original one */
|
||||||
|
|
||||||
|
result.m_address = follow.m_address;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MS_FOLLOW_STATUS_FAIL_LHS:
|
||||||
|
case MS_FOLLOW_STATUS_FAIL_RHS: {
|
||||||
|
/* this is prioritized over MS_FOLLOW_STATUS_INCOMPLETE */
|
||||||
|
|
||||||
|
/* deduce if it was either a left side overbounds
|
||||||
|
* failure or right side overbounds failure for the
|
||||||
|
* possibility of still allowing a result depending on
|
||||||
|
* user response */
|
||||||
|
|
||||||
|
result.m_status =
|
||||||
|
follow.m_status == MS_FOLLOW_STATUS_FAIL_LHS
|
||||||
|
? MS_RESULT_STATUS_FOUND_FOLLOW_FAIL_LHS
|
||||||
|
: MS_RESULT_STATUS_FOUND_FOLLOW_FAIL_RHS;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MS_FOLLOW_STATUS_INCOMPLETE: {
|
||||||
|
/* a condition to break the follow was met before there was
|
||||||
|
* a match in memory between the seeked byte-code and the
|
||||||
|
* byte-code at from it's current address for the seeked
|
||||||
|
* byte-code length */
|
||||||
|
|
||||||
|
result.m_status =
|
||||||
|
MS_RESULT_STATUS_FOUND_FOLLOW_FAIL_INCOMPLETE;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we haven't found an address for our signature, so we will set result
|
||||||
|
* state to NOT FOUND */
|
||||||
|
|
||||||
|
result.m_status = MS_RESULT_STATUS_NOT_FOUND;
|
||||||
|
|
||||||
|
return_label:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_bs_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_t* restrict bytes,
|
||||||
|
const ms_find_str_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
if (find_bytes == NULL)
|
||||||
|
result = memscan_find_pattern_bb_impl(start, end, bytes, NULL);
|
||||||
|
else {
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_pattern_t pattern =
|
||||||
|
util_build_pattern(find_bytes->m_data, strlen(find_bytes->m_data));
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes_from_str = {0};
|
||||||
|
find_bytes_from_str.m_data = pattern.m_data;
|
||||||
|
find_bytes_from_str.m_size = pattern.m_size;
|
||||||
|
find_bytes_from_str.m_match = find_bytes->m_match;
|
||||||
|
find_bytes_from_str.m_direction = find_bytes->m_direction;
|
||||||
|
|
||||||
|
/* pass converted data to base implementation */
|
||||||
|
|
||||||
|
result = memscan_find_pattern_bb_impl(start, end, bytes,
|
||||||
|
&find_bytes_from_str);
|
||||||
|
|
||||||
|
util_free_pattern(&pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_sb_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_str_t* restrict bytes,
|
||||||
|
const ms_find_bytes_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
if (bytes == NULL || (bytes && bytes->m_data == NULL))
|
||||||
|
result = memscan_find_pattern_bb_impl(start, end, NULL, find_bytes);
|
||||||
|
else {
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_pattern_t pattern =
|
||||||
|
util_build_pattern(bytes->m_data, strlen(bytes->m_data));
|
||||||
|
|
||||||
|
ms_bytes_t bytes_from_str = {0};
|
||||||
|
bytes_from_str.m_data = pattern.m_data;
|
||||||
|
bytes_from_str.m_size = pattern.m_size;
|
||||||
|
bytes_from_str.m_match = bytes->m_match;
|
||||||
|
|
||||||
|
/* pass converted data to base implementation */
|
||||||
|
|
||||||
|
result = memscan_find_pattern_bb_impl(start, end, &bytes_from_str,
|
||||||
|
find_bytes);
|
||||||
|
|
||||||
|
util_free_pattern(&pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_ss_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_str_t* restrict bytes,
|
||||||
|
const ms_find_str_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
|
||||||
|
ms_result_t result = {0};
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
if (find_bytes == NULL)
|
||||||
|
result = memscan_find_pattern_sb_impl(start, end, bytes, NULL);
|
||||||
|
else {
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_pattern_t find_pattern =
|
||||||
|
util_build_pattern(find_bytes->m_data, strlen(find_bytes->m_data));
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes_from_str = {0};
|
||||||
|
find_bytes_from_str.m_data = find_pattern.m_data;
|
||||||
|
find_bytes_from_str.m_size = find_pattern.m_size;
|
||||||
|
find_bytes_from_str.m_match = find_bytes->m_match;
|
||||||
|
find_bytes_from_str.m_direction = find_bytes->m_direction;
|
||||||
|
|
||||||
|
/* pass data to our string, bytes wrapper */
|
||||||
|
|
||||||
|
result = memscan_find_pattern_sb_impl(start, end, bytes,
|
||||||
|
&find_bytes_from_str);
|
||||||
|
|
||||||
|
util_free_pattern(&find_pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_nfb_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_t* restrict bytes)
|
||||||
|
{
|
||||||
|
/* pass data to our base implementation. the data being NULL
|
||||||
|
* will prevent a follow from happening */
|
||||||
|
|
||||||
|
return memscan_find_pattern_bb_impl(start, end, bytes, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_pattern_nfs_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_bytes_str_t* restrict bytes)
|
||||||
|
{
|
||||||
|
/* pass data to our string, bytes wrapper. the data being NULL
|
||||||
|
* will prevent a follow from happening */
|
||||||
|
|
||||||
|
return memscan_find_pattern_sb_impl(start, end, bytes, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_xref_b_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_xref_t* restrict xref,
|
||||||
|
const ms_find_bytes_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
#if !MEMSCAN_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (xref == NULL /* data is handled in the pattern finder */) {
|
||||||
|
result.m_status = MS_RESULT_NO_VALID_BYTES_INFO;
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_t from_xref = {0};
|
||||||
|
|
||||||
|
from_xref.m_data =
|
||||||
|
util_ptr_to_byteset(xref->m_pointer, xref->m_swap_endianness);
|
||||||
|
from_xref.m_size = MEMSCAN_BYTESET_SIZE;
|
||||||
|
from_xref.m_match = xref->m_match;
|
||||||
|
|
||||||
|
/* pass data to our no follow, bytes wrapper */
|
||||||
|
|
||||||
|
result = memscan_find_pattern_bb_impl(start, end, &from_xref, find_bytes);
|
||||||
|
|
||||||
|
return_label:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_xref_s_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_xref_t* restrict xref,
|
||||||
|
const ms_find_str_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
if (find_bytes == NULL)
|
||||||
|
result = memscan_find_xref_b_impl(start, end, xref, NULL);
|
||||||
|
else {
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_pattern_t pattern =
|
||||||
|
util_build_pattern(find_bytes->m_data, strlen(find_bytes->m_data));
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes_from_str = {0};
|
||||||
|
find_bytes_from_str.m_data = pattern.m_data;
|
||||||
|
find_bytes_from_str.m_size = pattern.m_size;
|
||||||
|
find_bytes_from_str.m_match = find_bytes->m_match;
|
||||||
|
find_bytes_from_str.m_direction = find_bytes->m_direction;
|
||||||
|
|
||||||
|
result =
|
||||||
|
memscan_find_xref_b_impl(start, end, xref, &find_bytes_from_str);
|
||||||
|
|
||||||
|
util_free_pattern(&pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_xref_nf_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_xref_t* restrict xref)
|
||||||
|
{
|
||||||
|
return memscan_find_xref_b_impl(start, end, xref, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_string_b_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_string_xref_t* restrict string,
|
||||||
|
const ms_find_bytes_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
#if !MEMSCAN_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (string == NULL /* data is handled in the pattern finder */) {
|
||||||
|
result.m_status = MS_RESULT_NO_VALID_BYTES_INFO;
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_t bytes = {0};
|
||||||
|
|
||||||
|
bytes.m_data = (const ms_ubyte_t*)string->m_data;
|
||||||
|
bytes.m_size = string->m_size;
|
||||||
|
bytes.m_match = 0;
|
||||||
|
|
||||||
|
ms_result_t string_find = memscan_find_pattern_nfb_impl(start, end, &bytes);
|
||||||
|
|
||||||
|
if (string_find.m_status != MS_RESULT_STATUS_FOUND) {
|
||||||
|
result.m_status = string_find.m_status;
|
||||||
|
goto return_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
ms_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_pointer = string_find.m_address;
|
||||||
|
xref.m_match = string->m_match;
|
||||||
|
xref.m_swap_endianness = true;
|
||||||
|
|
||||||
|
result = memscan_find_xref_b_impl(start, end, &xref, find_bytes);
|
||||||
|
|
||||||
|
return_label:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_string_s_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_string_xref_t* restrict string,
|
||||||
|
const ms_find_str_t* restrict find_bytes)
|
||||||
|
{
|
||||||
|
ms_result_t result = {0};
|
||||||
|
result.m_address = 0;
|
||||||
|
|
||||||
|
if (find_bytes == NULL)
|
||||||
|
result = memscan_find_string_b_impl(start, end, string, NULL);
|
||||||
|
else {
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_pattern_t pattern =
|
||||||
|
util_build_pattern(find_bytes->m_data, strlen(find_bytes->m_data));
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes_from_str = {0};
|
||||||
|
find_bytes_from_str.m_data = pattern.m_data;
|
||||||
|
find_bytes_from_str.m_size = pattern.m_size;
|
||||||
|
find_bytes_from_str.m_match = find_bytes->m_match;
|
||||||
|
find_bytes_from_str.m_direction = find_bytes->m_direction;
|
||||||
|
|
||||||
|
result = memscan_find_string_b_impl(start, end, string,
|
||||||
|
&find_bytes_from_str);
|
||||||
|
|
||||||
|
util_free_pattern(&pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ms_result_t
|
||||||
|
memscan_find_string_nf_impl(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_string_xref_t* restrict string)
|
||||||
|
{
|
||||||
|
return memscan_find_string_b_impl(start, end, string, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prototype Bodies */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_bb(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_ubyte_t* pattern,
|
||||||
|
const ms_usize_t pattern_size,
|
||||||
|
const ms_usize_t pattern_nth_match,
|
||||||
|
const ms_ubyte_t* follow_pattern,
|
||||||
|
const ms_usize_t follow_pattern_size,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_size = pattern_size;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
ms_find_bytes_t find = {0};
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_size = follow_pattern_size;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_bb_impl(start, end, &bytes, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_bs(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_ubyte_t* pattern,
|
||||||
|
const ms_usize_t pattern_size,
|
||||||
|
const ms_usize_t pattern_nth_match,
|
||||||
|
const char* follow_pattern,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_size = pattern_size;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
ms_find_str_t find = {0};
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_bs_impl(start, end, &bytes, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_sb(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* pattern, const ms_usize_t pattern_nth_match,
|
||||||
|
const ms_ubyte_t* follow_pattern,
|
||||||
|
const ms_usize_t follow_pattern_size,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_str_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
ms_find_bytes_t find = {0};
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_size = follow_pattern_size;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_sb_impl(start, end, &bytes, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_ss(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* pattern, const ms_usize_t pattern_nth_match,
|
||||||
|
const char* follow_pattern,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_str_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
ms_find_str_t find = {0};
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_ss_impl(start, end, &bytes, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_nfb(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_ubyte_t* pattern,
|
||||||
|
const ms_usize_t pattern_size,
|
||||||
|
const ms_usize_t pattern_nth_match)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_size = pattern_size;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_nfb_impl(start, end, &bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_pattern_nfs(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* pattern,
|
||||||
|
const ms_usize_t pattern_nth_match)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_bytes_str_t bytes = {0};
|
||||||
|
bytes.m_data = pattern;
|
||||||
|
bytes.m_match = pattern_nth_match;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_pattern_nfs_impl(start, end, &bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_b(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t content, const ms_usize_t content_nth_match,
|
||||||
|
bool swap_endianness, const ms_ubyte_t* follow_pattern,
|
||||||
|
const ms_usize_t follow_pattern_size,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_pointer = content;
|
||||||
|
xref.m_match = content_nth_match;
|
||||||
|
xref.m_swap_endianness = swap_endianness;
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes = {0};
|
||||||
|
|
||||||
|
find_bytes.m_data = follow_pattern;
|
||||||
|
find_bytes.m_size = follow_pattern_size;
|
||||||
|
find_bytes.m_match = follow_nth_match;
|
||||||
|
find_bytes.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_xref_b_impl(start, end, &xref, &find_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_at_b(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t address, const ms_usize_t nth_match,
|
||||||
|
bool swap_endianness, const ms_ubyte_t* follow_pattern,
|
||||||
|
const ms_usize_t follow_pattern_size,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
return memscan_find_xref_b(start, end, *(ms_uptr_t*)address, nth_match,
|
||||||
|
swap_endianness, follow_pattern,
|
||||||
|
follow_pattern_size, follow_nth_match,
|
||||||
|
follow_direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_s(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t content, const ms_usize_t content_nth_match,
|
||||||
|
bool swap_endianness, const char* follow_pattern,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_pointer = content;
|
||||||
|
xref.m_match = content_nth_match;
|
||||||
|
xref.m_swap_endianness = swap_endianness;
|
||||||
|
|
||||||
|
ms_find_str_t find = {0};
|
||||||
|
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_xref_s_impl(start, end, &xref, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_at_s(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t address, const ms_usize_t nth_match,
|
||||||
|
bool swap_endianness, const char* follow_pattern,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
return memscan_find_xref_s(start, end, *(ms_uptr_t*)address, nth_match,
|
||||||
|
swap_endianness, follow_pattern,
|
||||||
|
follow_nth_match, follow_direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_nf(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t content,
|
||||||
|
const ms_usize_t content_nth_match, bool swap_endianness)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_pointer = content;
|
||||||
|
xref.m_match = content_nth_match;
|
||||||
|
xref.m_swap_endianness = swap_endianness;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_xref_nf_impl(start, end, &xref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_xref_at_nf(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const ms_uptr_t address, const ms_usize_t nth_match,
|
||||||
|
bool swap_endianness)
|
||||||
|
{
|
||||||
|
return memscan_find_xref_nf(start, end, *(ms_uptr_t*)address, nth_match,
|
||||||
|
swap_endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
extern ms_result_t
|
||||||
|
memscan_find_string_b(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* text, const ms_usize_t text_size,
|
||||||
|
const ms_usize_t nth_match,
|
||||||
|
const ms_ubyte_t* follow_pattern,
|
||||||
|
const ms_usize_t follow_pattern_size,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_string_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_data = text;
|
||||||
|
xref.m_size = text_size;
|
||||||
|
xref.m_match = nth_match;
|
||||||
|
|
||||||
|
ms_find_bytes_t find_bytes = {0};
|
||||||
|
|
||||||
|
find_bytes.m_data = follow_pattern;
|
||||||
|
find_bytes.m_size = follow_pattern_size;
|
||||||
|
find_bytes.m_match = follow_nth_match;
|
||||||
|
find_bytes.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_string_b_impl(start, end, &xref, &find_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_string_s(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* text, const ms_usize_t text_size,
|
||||||
|
const ms_usize_t nth_match, const char* follow_pattern,
|
||||||
|
const ms_usize_t follow_nth_match,
|
||||||
|
const ms_follow_direction_t follow_direction)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_string_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_data = text;
|
||||||
|
xref.m_size = text_size;
|
||||||
|
xref.m_match = nth_match;
|
||||||
|
|
||||||
|
ms_find_str_t find = {0};
|
||||||
|
|
||||||
|
find.m_data = follow_pattern;
|
||||||
|
find.m_match = follow_nth_match;
|
||||||
|
find.m_direction = follow_direction;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_string_s_impl(start, end, &xref, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_result_t
|
||||||
|
memscan_find_string_nf(const ms_uptr_t start, const ms_uptr_t end,
|
||||||
|
const char* text, const ms_usize_t text_size,
|
||||||
|
const ms_usize_t nth_match)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
ms_string_xref_t xref = {0};
|
||||||
|
|
||||||
|
xref.m_data = text;
|
||||||
|
xref.m_size = text_size;
|
||||||
|
xref.m_match = nth_match;
|
||||||
|
|
||||||
|
/* pass structured data to manager */
|
||||||
|
|
||||||
|
return memscan_find_string_nf_impl(start, end, &xref);
|
||||||
|
}
|
1037
EGameTools/source/memscan/memscan.h
Normal file
1037
EGameTools/source/memscan/memscan.h
Normal file
File diff suppressed because it is too large
Load Diff
102
EGameTools/source/memscan/util/util.c
Normal file
102
EGameTools/source/memscan/util/util.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "util.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ms_pattern_t
|
||||||
|
util_build_pattern(const char* data, const ms_usize_t data_size)
|
||||||
|
{
|
||||||
|
ms_pattern_t result = {0};
|
||||||
|
|
||||||
|
result.m_data = NULL;
|
||||||
|
result.m_size = 0;
|
||||||
|
|
||||||
|
#if !UTIL_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (data == NULL) {
|
||||||
|
result.m_status = MS_BUILD_STATUS_NO_DATA;
|
||||||
|
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t len = data_size;
|
||||||
|
|
||||||
|
#if !UTIL_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (len == 0) {
|
||||||
|
result.m_status = MS_BUILD_STATUS_SHORT_DATA;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
char* start = (char*)data;
|
||||||
|
char* end = (char*)(data + len);
|
||||||
|
|
||||||
|
/* precompute allocation size */
|
||||||
|
|
||||||
|
ms_usize_t size = 0;
|
||||||
|
|
||||||
|
for (char* current = start; current < end; ++current)
|
||||||
|
++size;
|
||||||
|
|
||||||
|
ms_ubyte_t* bytes = (ms_ubyte_t*)malloc(size * sizeof *bytes);
|
||||||
|
|
||||||
|
/* prefetched */
|
||||||
|
|
||||||
|
ms_usize_t indice = 0;
|
||||||
|
|
||||||
|
for (char* current = start; current < end; ++current) {
|
||||||
|
/* hex substring conversion */
|
||||||
|
|
||||||
|
bytes[indice++] = (ms_ubyte_t)strtoul(current, ¤t, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.m_data = bytes;
|
||||||
|
result.m_size = indice;
|
||||||
|
result.m_status = MS_BUILD_STATUS_OK;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
ms_free_t
|
||||||
|
util_free_pattern(ms_pattern_t* pattern)
|
||||||
|
{
|
||||||
|
#if !UTIL_UNSAFE_OPTIMIZATIONS
|
||||||
|
if (pattern == NULL) {
|
||||||
|
return MS_FREE_NO;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ms_free_t result = MS_FREE_NO;
|
||||||
|
|
||||||
|
if (pattern->m_status == MS_BUILD_STATUS_OK) {
|
||||||
|
free(pattern->m_data);
|
||||||
|
pattern->m_data = NULL;
|
||||||
|
|
||||||
|
result = MS_FREE_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern->m_size = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ms_ubyte_t*
|
||||||
|
util_ptr_to_byteset(const ms_uptr_t num, bool swap_endianness)
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
|
||||||
|
static ms_ubyte_t bytes[MEMSCAN_BYTESET_SIZE] = {0};
|
||||||
|
|
||||||
|
for (ms_usize_t i = 0; i < MEMSCAN_BYTESET_SIZE; ++i) {
|
||||||
|
/* shift formation to get current indice */
|
||||||
|
|
||||||
|
bytes[swap_endianness ? i : MEMSCAN_BYTESET_SIZE - i - 1] =
|
||||||
|
(ms_ubyte_t)(num >> (i * CHAR_BIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
88
EGameTools/source/memscan/util/util.h
Normal file
88
EGameTools/source/memscan/util/util.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Includes */
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Types */
|
||||||
|
|
||||||
|
typedef uint8_t ms_ubyte_t;
|
||||||
|
typedef uintptr_t ms_uptr_t;
|
||||||
|
typedef size_t ms_usize_t;
|
||||||
|
|
||||||
|
/* Extern */
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
#define MEMSCAN_EXTERN extern "C"
|
||||||
|
#else
|
||||||
|
#define MEMSCAN_EXTERN extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* nothing to free, or there's a condition preventing the process */
|
||||||
|
MS_FREE_NO = 0,
|
||||||
|
|
||||||
|
/* the data was found present and then freed */
|
||||||
|
MS_FREE_YES
|
||||||
|
} ms_free_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* won't be reached unless UTIL_UNSAFE_OPTIMIZATIONS is off */
|
||||||
|
|
||||||
|
/* passed data was NULL */
|
||||||
|
MS_BUILD_STATUS_NO_DATA = 0,
|
||||||
|
|
||||||
|
/* data len was 0 */
|
||||||
|
MS_BUILD_STATUS_SHORT_DATA,
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
/* generation has succeeded, status was set to OK */
|
||||||
|
MS_BUILD_STATUS_OK
|
||||||
|
} ms_build_status_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ms_ubyte_t* m_data;
|
||||||
|
ms_usize_t m_size;
|
||||||
|
ms_build_status_t m_status;
|
||||||
|
} ms_pattern_t;
|
||||||
|
|
||||||
|
/* Methods */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate byte code array from byte-code style string
|
||||||
|
*
|
||||||
|
* @param data Example: "AA BB CC DD EE FF", equivalent to
|
||||||
|
* (ms_ubyte_t*)"\xAA\xBB\xCC\xDD\xEE\xFF"
|
||||||
|
* @param data_size Size of 'data'
|
||||||
|
* @return Refer to ms_pattern_t for documentation
|
||||||
|
*/
|
||||||
|
MEMSCAN_EXTERN ms_pattern_t
|
||||||
|
util_build_pattern(const char* data, const ms_usize_t data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deallocate pattern array after usage
|
||||||
|
*
|
||||||
|
* @param pattern Reference to the pattern construct
|
||||||
|
* @return Refer to ms_free_t for documentation
|
||||||
|
*/
|
||||||
|
MEMSCAN_EXTERN ms_free_t
|
||||||
|
util_free_pattern(ms_pattern_t* pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert pointer in numerical form to byteset of MEMSCAN_BYTESET_SIZE
|
||||||
|
* bytes
|
||||||
|
*
|
||||||
|
* @param num Value to convert
|
||||||
|
* @param swap_endianness Whether to swap endianness or not
|
||||||
|
* @return Value as a MEMSCAN_BYTESET_SIZE bytes array
|
||||||
|
*/
|
||||||
|
MEMSCAN_EXTERN ms_ubyte_t*
|
||||||
|
util_ptr_to_byteset(const ms_uptr_t num, bool swap_endianness);
|
||||||
|
|
||||||
|
/* Constants */
|
||||||
|
|
||||||
|
#define MEMSCAN_BYTESET_SIZE (sizeof(ms_uptr_t) / sizeof(ms_ubyte_t))
|
||||||
|
#define MEMSCAN_POINTER_BITS (sizeof(ms_uptr_t) * CHAR_BIT)
|
@ -6,8 +6,8 @@
|
|||||||
#include "..\game\GamePH\GameDI_PH.h"
|
#include "..\game\GamePH\GameDI_PH.h"
|
||||||
#include "..\game\GamePH\LevelDI.h"
|
#include "..\game\GamePH\LevelDI.h"
|
||||||
#include "..\game\GamePH\PlayerVariables.h"
|
#include "..\game\GamePH\PlayerVariables.h"
|
||||||
|
#include "..\game\GamePH\PlayerObjProperties.h"
|
||||||
#include "..\game\GamePH\gameph_misc.h"
|
#include "..\game\GamePH\gameph_misc.h"
|
||||||
#include "..\game\GamePH\gen_TPPModel.h"
|
|
||||||
#include "..\offsets.h"
|
#include "..\offsets.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -149,8 +149,8 @@ namespace Menu {
|
|||||||
if (!iLevel || !iLevel->IsLoaded())
|
if (!iLevel || !iLevel->IsLoaded())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GamePH::gen_TPPModel* pgen_TPPModel = GamePH::gen_TPPModel::Get();
|
GamePH::PlayerObjProperties* playerObjProperties = GamePH::PlayerObjProperties::Get();
|
||||||
if (pgen_TPPModel) {
|
if (playerObjProperties) {
|
||||||
if (Menu::Camera::freeCam.GetValue() && !iLevel->IsTimerFrozen())
|
if (Menu::Camera::freeCam.GetValue() && !iLevel->IsTimerFrozen())
|
||||||
GamePH::ShowTPPModel(true);
|
GamePH::ShowTPPModel(true);
|
||||||
else if (Menu::Camera::freeCam.GetValue() && iLevel->IsTimerFrozen() && !photoMode.GetValue())
|
else if (Menu::Camera::freeCam.GetValue() && iLevel->IsTimerFrozen() && !photoMode.GetValue())
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "..\game\GamePH\SessionCooperativeDI.h"
|
#include "..\game\GamePH\SessionCooperativeDI.h"
|
||||||
#include "..\game\GamePH\TPPCameraDI.h"
|
#include "..\game\GamePH\TPPCameraDI.h"
|
||||||
#include "..\game\GamePH\TimeWeather\CSystem.h"
|
#include "..\game\GamePH\TimeWeather\CSystem.h"
|
||||||
#include "..\game\GamePH\gen_TPPModel.h"
|
|
||||||
|
|
||||||
#include "..\game\Engine\CBulletPhysicsCharacter.h"
|
#include "..\game\Engine\CBulletPhysicsCharacter.h"
|
||||||
#include "..\game\Engine\CGSObject.h"
|
#include "..\game\Engine\CGSObject.h"
|
||||||
@ -37,7 +36,6 @@ namespace Menu {
|
|||||||
{ "FreeCamera", reinterpret_cast<LPVOID(*)()>(&GamePH::FreeCamera::Get) },
|
{ "FreeCamera", reinterpret_cast<LPVOID(*)()>(&GamePH::FreeCamera::Get) },
|
||||||
{ "GameDI_PH", reinterpret_cast<LPVOID(*)()>(&GamePH::GameDI_PH::Get) },
|
{ "GameDI_PH", reinterpret_cast<LPVOID(*)()>(&GamePH::GameDI_PH::Get) },
|
||||||
{ "GameDI_PH2", reinterpret_cast<LPVOID(*)()>(&GamePH::GameDI_PH2::Get) },
|
{ "GameDI_PH2", reinterpret_cast<LPVOID(*)()>(&GamePH::GameDI_PH2::Get) },
|
||||||
{ "gen_TPPModel", reinterpret_cast<LPVOID(*)()>(&GamePH::gen_TPPModel::Get) },
|
|
||||||
{ "LevelDI", reinterpret_cast<LPVOID(*)()>(&GamePH::LevelDI::Get) },
|
{ "LevelDI", reinterpret_cast<LPVOID(*)()>(&GamePH::LevelDI::Get) },
|
||||||
{ "LocalClientDI", reinterpret_cast<LPVOID(*)()>(&GamePH::LocalClientDI::Get) },
|
{ "LocalClientDI", reinterpret_cast<LPVOID(*)()>(&GamePH::LocalClientDI::Get) },
|
||||||
{ "LogicalPlayer", reinterpret_cast<LPVOID(*)()>(&GamePH::LogicalPlayer::Get) },
|
{ "LogicalPlayer", reinterpret_cast<LPVOID(*)()>(&GamePH::LogicalPlayer::Get) },
|
||||||
|
@ -22,6 +22,8 @@ namespace Menu {
|
|||||||
Option firstTimeRunning{};
|
Option firstTimeRunning{};
|
||||||
Option hasSeenChangelog{};
|
Option hasSeenChangelog{};
|
||||||
|
|
||||||
|
int currentTabIndex = 0;
|
||||||
|
|
||||||
void Render() {
|
void Render() {
|
||||||
ImGui::StyleScaleAllSizes(&ImGui::GetStyle(), scale, &defStyle);
|
ImGui::StyleScaleAllSizes(&ImGui::GetStyle(), scale, &defStyle);
|
||||||
ImGui::GetIO().FontGlobalScale = scale;
|
ImGui::GetIO().FontGlobalScale = scale;
|
||||||
@ -47,6 +49,7 @@ namespace Menu {
|
|||||||
ImGui::SetNextWindowBgAlpha(static_cast<float>(opacity) / 100.0f);
|
ImGui::SetNextWindowBgAlpha(static_cast<float>(opacity) / 100.0f);
|
||||||
ImGui::SetNextWindowSizeConstraints(ImVec2(std::fmax(minWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, ImGui::CalcTextSize(Core::gameVer > GAME_VER_COMPAT ? "Please wait for a new mod update." : "Upgrade your game version to one that the mod supports.").x), remainingHeight), ImVec2(maxWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, remainingHeight));
|
ImGui::SetNextWindowSizeConstraints(ImVec2(std::fmax(minWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, ImGui::CalcTextSize(Core::gameVer > GAME_VER_COMPAT ? "Please wait for a new mod update." : "Upgrade your game version to one that the mod supports.").x), remainingHeight), ImVec2(maxWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, remainingHeight));
|
||||||
if (ImGui::BeginChild("##TabChild", ImVec2(0.0f, 0.0f), ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_Border)) {
|
if (ImGui::BeginChild("##TabChild", ImVec2(0.0f, 0.0f), ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_Border)) {
|
||||||
|
currentTabIndex = tab.first;
|
||||||
childWidth = ImGui::GetItemRectSize().x;
|
childWidth = ImGui::GetItemRectSize().x;
|
||||||
tab.second->Render();
|
tab.second->Render();
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -12,7 +12,6 @@ namespace Menu {
|
|||||||
virtual void Update() {};
|
virtual void Update() {};
|
||||||
|
|
||||||
std::string_view tabName{};
|
std::string_view tabName{};
|
||||||
private:
|
|
||||||
int tabIndex{};
|
int tabIndex{};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,5 +26,7 @@ namespace Menu {
|
|||||||
extern Option firstTimeRunning;
|
extern Option firstTimeRunning;
|
||||||
extern Option hasSeenChangelog;
|
extern Option hasSeenChangelog;
|
||||||
|
|
||||||
|
extern int currentTabIndex;
|
||||||
|
|
||||||
extern void Render();
|
extern void Render();
|
||||||
}
|
}
|
@ -89,7 +89,7 @@ namespace Menu {
|
|||||||
if (freezeTime.GetValue() && !Utils::Values::are_samef(time, timeBeforeFreeze, 0.0095f))
|
if (freezeTime.GetValue() && !Utils::Values::are_samef(time, timeBeforeFreeze, 0.0095f))
|
||||||
dayNightCycle->SetDaytime(timeBeforeFreeze);
|
dayNightCycle->SetDaytime(timeBeforeFreeze);
|
||||||
|
|
||||||
if (!menuToggle.GetValue()) {
|
if (!menuToggle.GetValue() || Menu::currentTabIndex != World::Tab::tabIndex) {
|
||||||
if (!slowMotion.GetValue() && !slowMotion.HasChanged() && !Utils::Values::are_samef(gameSpeed, 1.0f))
|
if (!slowMotion.GetValue() && !slowMotion.HasChanged() && !Utils::Values::are_samef(gameSpeed, 1.0f))
|
||||||
iLevel->TimerSetSpeedUp(gameSpeed);
|
iLevel->TimerSetSpeedUp(gameSpeed);
|
||||||
actualGameSpeed = iLevel->TimerGetSpeedUp();
|
actualGameSpeed = iLevel->TimerGetSpeedUp();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
static retType Get_## name () {\
|
static retType Get_## name () {\
|
||||||
static retType name = NULL;\
|
static retType name = NULL;\
|
||||||
static int i = 0;\
|
static int i = 0;\
|
||||||
if (Utils::Memory::IsValidPtr(name) || i >= 10) return name;\
|
if (Utils::Memory::IsValidPtr(name) || !GetModuleHandleA(moduleName) || i >= 10) return name;\
|
||||||
i++;\
|
i++;\
|
||||||
return name=reinterpret_cast<retType>(Utils::SigScan::PatternScanner::FindPattern(moduleName, {pattern, type}));\
|
return name=reinterpret_cast<retType>(Utils::SigScan::PatternScanner::FindPattern(moduleName, {pattern, type}));\
|
||||||
}
|
}
|
||||||
@ -20,14 +20,14 @@ static DWORD64 Get_## name () {\
|
|||||||
static DWORD64 Get_## name () {\
|
static DWORD64 Get_## name () {\
|
||||||
static DWORD64 name = 0;\
|
static DWORD64 name = 0;\
|
||||||
if (Utils::Memory::IsValidPtr(name)) return name;\
|
if (Utils::Memory::IsValidPtr(name)) return name;\
|
||||||
return name=reinterpret_cast<DWORD64>(GetModuleHandle(moduleName)) + static_cast<DWORD64>(off);\
|
return name=reinterpret_cast<DWORD64>(GetModuleHandleA(moduleName)) + static_cast<DWORD64>(off);\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AddVTOffset(name, moduleName, rttiName, retType)\
|
#define AddVTOffset(name, moduleName, rttiName, retType)\
|
||||||
static retType GetVT_## name () {\
|
static retType GetVT_## name () {\
|
||||||
static retType VT_## name = NULL;\
|
static retType VT_## name = NULL;\
|
||||||
static int i = 0;\
|
static int i = 0;\
|
||||||
if (Utils::Memory::IsValidPtr(VT_## name)) return VT_## name;\
|
if (Utils::Memory::IsValidPtr(VT_## name)|| !GetModuleHandleA(moduleName) || i >= 10) return VT_## name;\
|
||||||
i++;\
|
i++;\
|
||||||
return VT_## name=reinterpret_cast<retType>(Utils::RTTI::GetVTablePtr(moduleName, rttiName));\
|
return VT_## name=reinterpret_cast<retType>(Utils::RTTI::GetVTablePtr(moduleName, rttiName));\
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ struct Offsets {
|
|||||||
AddVTOffset(TypedFieldMetaFloatPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VFloatPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", LPVOID)
|
AddVTOffset(TypedFieldMetaFloatPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VFloatPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", LPVOID)
|
||||||
AddVTOffset(TypedFieldMetaBoolPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VBoolPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", LPVOID)
|
AddVTOffset(TypedFieldMetaBoolPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VBoolPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", LPVOID)
|
||||||
AddOffset(LoadPlayerVars, "gamedll_ph_x64_rwdi.dll", "48 89 4C 24 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 8C 24", Utils::SigScan::PatternType::Address, LPVOID)
|
AddOffset(LoadPlayerVars, "gamedll_ph_x64_rwdi.dll", "48 89 4C 24 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 8C 24", Utils::SigScan::PatternType::Address, LPVOID)
|
||||||
AddOffset(PlayerState, "gamedll_ph_x64_rwdi.dll", "4C 8B 35 [?? ?? ?? ?? 4C 8B E2", Utils::SigScan::PatternType::RelativePointer, LPVOID)
|
AddOffset(PlayerState, "gamedll_ph_x64_rwdi.dll", "48 8B 35 [?? ?? ?? ?? 4C 8B F2 48 8B F9", Utils::SigScan::PatternType::RelativePointer, LPVOID)
|
||||||
|
|
||||||
// Game related
|
// Game related
|
||||||
AddVTOffset(CBulletPhysicsCharacter, "engine_x64_rwdi.dll", "CBulletPhysicsCharacter", LPVOID)
|
AddVTOffset(CBulletPhysicsCharacter, "engine_x64_rwdi.dll", "CBulletPhysicsCharacter", LPVOID)
|
||||||
|
@ -40,11 +40,11 @@ namespace Utils {
|
|||||||
bool HookLoop() override {
|
bool HookLoop() override {
|
||||||
if (hooked || (optionRef && !optionRef->GetValue()))
|
if (hooked || (optionRef && !optionRef->GetValue()))
|
||||||
return true;
|
return true;
|
||||||
timeSpentHooking = Utils::Time::Timer(160000);
|
timeSpentHooking = Utils::Time::Timer(120000);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (timeSpentHooking.DidTimePass()) {
|
if (timeSpentHooking.DidTimePass()) {
|
||||||
spdlog::error("Failed hooking \"{}\" after 160 seconds", name);
|
spdlog::error("Failed hooking \"{}\" after 120 seconds", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pGetOffsetFunc || !pGetOffsetFunc())
|
if (!pGetOffsetFunc || !pGetOffsetFunc())
|
||||||
@ -62,6 +62,8 @@ namespace Utils {
|
|||||||
VirtualProtect(pGetOffsetFunc(), bytesAmount, originalProtection, &oldProtection);
|
VirtualProtect(pGetOffsetFunc(), bytesAmount, originalProtection, &oldProtection);
|
||||||
hooked = true;
|
hooked = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ namespace Utils {
|
|||||||
|
|
||||||
bool hooked = false;
|
bool hooked = false;
|
||||||
|
|
||||||
Utils::Time::Timer timeSpentHooking{ 160000 };
|
Utils::Time::Timer timeSpentHooking{ 120000 };
|
||||||
};
|
};
|
||||||
template <typename GetTargetOffsetRetType, typename OrigType>
|
template <typename GetTargetOffsetRetType, typename OrigType>
|
||||||
class MHook : HookBase {
|
class MHook : HookBase {
|
||||||
@ -121,11 +123,11 @@ namespace Utils {
|
|||||||
bool HookLoop() override {
|
bool HookLoop() override {
|
||||||
if (pOriginal)
|
if (pOriginal)
|
||||||
return true;
|
return true;
|
||||||
timeSpentHooking = Utils::Time::Timer(160000);
|
timeSpentHooking = Utils::Time::Timer(120000);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (timeSpentHooking.DidTimePass()) {
|
if (timeSpentHooking.DidTimePass()) {
|
||||||
spdlog::error("Failed hooking function \"{}\" after 160 seconds", name);
|
spdlog::error("Failed hooking function \"{}\" after 120 seconds", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pGetOffsetFunc)
|
if (!pGetOffsetFunc)
|
||||||
@ -137,6 +139,8 @@ namespace Utils {
|
|||||||
MH_EnableHook(pTarget);
|
MH_EnableHook(pTarget);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +150,7 @@ namespace Utils {
|
|||||||
GetTargetOffsetRetType(*pGetOffsetFunc)() = nullptr;
|
GetTargetOffsetRetType(*pGetOffsetFunc)() = nullptr;
|
||||||
OrigType pDetour = nullptr;
|
OrigType pDetour = nullptr;
|
||||||
|
|
||||||
Utils::Time::Timer timeSpentHooking{ 160000 };
|
Utils::Time::Timer timeSpentHooking{ 120000 };
|
||||||
};
|
};
|
||||||
template <typename GetTargetOffsetRetType, typename OrigType>
|
template <typename GetTargetOffsetRetType, typename OrigType>
|
||||||
class VTHook : HookBase {
|
class VTHook : HookBase {
|
||||||
@ -156,11 +160,11 @@ namespace Utils {
|
|||||||
bool HookLoop() override {
|
bool HookLoop() override {
|
||||||
if (pOriginal)
|
if (pOriginal)
|
||||||
return true;
|
return true;
|
||||||
timeSpentHooking = Utils::Time::Timer(160000);
|
timeSpentHooking = Utils::Time::Timer(120000);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (timeSpentHooking.DidTimePass()) {
|
if (timeSpentHooking.DidTimePass()) {
|
||||||
spdlog::error("Failed hooking function \"{}\" after 160 seconds", name);
|
spdlog::error("Failed hooking function \"{}\" after 120 seconds", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pGetOffsetFunc)
|
if (!pGetOffsetFunc)
|
||||||
@ -172,6 +176,8 @@ namespace Utils {
|
|||||||
HookVT(pInstance, pDetour, reinterpret_cast<LPVOID*>(&pOriginal), offset);
|
HookVT(pInstance, pDetour, reinterpret_cast<LPVOID*>(&pOriginal), offset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +187,7 @@ namespace Utils {
|
|||||||
LPVOID pInstance = nullptr;
|
LPVOID pInstance = nullptr;
|
||||||
OrigType pDetour = nullptr;
|
OrigType pDetour = nullptr;
|
||||||
|
|
||||||
Utils::Time::Timer timeSpentHooking{ 160000 };
|
Utils::Time::Timer timeSpentHooking{ 120000 };
|
||||||
|
|
||||||
DWORD offset = 0x0;
|
DWORD offset = 0x0;
|
||||||
};
|
};
|
||||||
|
@ -37,13 +37,13 @@ namespace Utils {
|
|||||||
return ptr && (ptr <= moduleEndPoint && ptr >= moduleEntryPoint);
|
return ptr && (ptr <= moduleEndPoint && ptr >= moduleEntryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string bytesToIDAPattern(BYTE* bytes, size_t size) {
|
std::string BytesToIDAPattern(BYTE* bytes, size_t size) {
|
||||||
std::stringstream idaPattern;
|
std::stringstream idaPattern;
|
||||||
idaPattern << std::hex << std::uppercase << std::setfill('0');
|
idaPattern << std::hex << std::uppercase << std::setfill('0');
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
const int currentByte = bytes[i];
|
const int currentByte = bytes[i];
|
||||||
if (currentByte != 255)
|
if (currentByte != SigScanWildCard)
|
||||||
idaPattern << std::setw(2) << currentByte;
|
idaPattern << std::setw(2) << currentByte;
|
||||||
else
|
else
|
||||||
idaPattern << "??";
|
idaPattern << "??";
|
||||||
@ -54,6 +54,34 @@ namespace Utils {
|
|||||||
|
|
||||||
return idaPattern.str();
|
return idaPattern.str();
|
||||||
}
|
}
|
||||||
|
std::string ConvertSigToScannerSig(const char* pattern, int* offsetToAddrInSig) {
|
||||||
|
size_t len = strlen(pattern);
|
||||||
|
|
||||||
|
std::string patt{};
|
||||||
|
int bytesCounted = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len;) {
|
||||||
|
if (pattern[i] == ' ' || i == len - 1)
|
||||||
|
bytesCounted++;
|
||||||
|
|
||||||
|
if (pattern[i] == '[') {
|
||||||
|
i++;
|
||||||
|
if (offsetToAddrInSig)
|
||||||
|
*offsetToAddrInSig = static_cast<int>(bytesCounted);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pattern[i] == '?') {
|
||||||
|
patt += SigScanWildCardStr;
|
||||||
|
i += (pattern[static_cast<DWORD64>(i) + 1] == '?') ? 2 : 1;
|
||||||
|
} else {
|
||||||
|
patt.push_back(pattern[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return patt;
|
||||||
|
}
|
||||||
DWORD64 CalcTargetAddrOfRelInst(DWORD64 addrOfInst, size_t opSize) {
|
DWORD64 CalcTargetAddrOfRelInst(DWORD64 addrOfInst, size_t opSize) {
|
||||||
int offset = *reinterpret_cast<int*>(addrOfInst + opSize);
|
int offset = *reinterpret_cast<int*>(addrOfInst + opSize);
|
||||||
|
|
||||||
@ -62,7 +90,7 @@ namespace Utils {
|
|||||||
std::vector<DWORD64> GetXrefsTo(DWORD64 address, DWORD64 start, size_t size) {
|
std::vector<DWORD64> GetXrefsTo(DWORD64 address, DWORD64 start, size_t size) {
|
||||||
std::vector<DWORD64> xrefs = {};
|
std::vector<DWORD64> xrefs = {};
|
||||||
|
|
||||||
const std::string idaPattern = bytesToIDAPattern(reinterpret_cast<BYTE*>(&address), 8);
|
const std::string idaPattern = BytesToIDAPattern(reinterpret_cast<BYTE*>(&address), 8);
|
||||||
const DWORD64 end = start + size;
|
const DWORD64 end = start + size;
|
||||||
|
|
||||||
while (start && start < end) {
|
while (start && start < end) {
|
||||||
|
@ -5,11 +5,17 @@
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
static const BYTE SigScanWildCard = 0xAA;
|
||||||
|
static const std::string_view SigScanWildCardStr = "AA";
|
||||||
|
|
||||||
extern const MODULEINFO GetModuleInfo(const char* szModule);
|
extern const MODULEINFO GetModuleInfo(const char* szModule);
|
||||||
extern const FARPROC GetProcAddr(const std::string_view& module, const std::string_view& funcName);
|
extern const FARPROC GetProcAddr(const std::string_view& module, const std::string_view& funcName);
|
||||||
|
|
||||||
extern const bool IsAddressValidMod(const DWORD64 ptr, const char* moduleName);
|
extern const bool IsAddressValidMod(const DWORD64 ptr, const char* moduleName);
|
||||||
|
|
||||||
|
extern std::string BytesToIDAPattern(BYTE* bytes, size_t size);
|
||||||
|
extern std::string ConvertSigToScannerSig(const char* pattern, int* offsetToAddrInSig = nullptr);
|
||||||
|
|
||||||
extern DWORD64 CalcTargetAddrOfRelInst(DWORD64 addrOfInst, size_t opSize);
|
extern DWORD64 CalcTargetAddrOfRelInst(DWORD64 addrOfInst, size_t opSize);
|
||||||
std::vector<DWORD64> GetXrefsTo(DWORD64 address, DWORD64 start, size_t size);
|
std::vector<DWORD64> GetXrefsTo(DWORD64 address, DWORD64 start, size_t size);
|
||||||
|
|
||||||
|
@ -1,45 +1,30 @@
|
|||||||
#include "pch.h"
|
#include <pch.h>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
namespace RTTI {
|
namespace RTTI {
|
||||||
static std::string bytesToIDAPattern(BYTE* bytes, size_t size) {
|
|
||||||
std::stringstream idaPattern;
|
|
||||||
idaPattern << std::hex << std::uppercase << std::setfill('0');
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
const int currentByte = bytes[i];
|
|
||||||
if (currentByte != 255)
|
|
||||||
idaPattern << std::setw(2) << currentByte;
|
|
||||||
else
|
|
||||||
idaPattern << "??";
|
|
||||||
|
|
||||||
if (i != size - 1)
|
|
||||||
idaPattern << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return idaPattern.str();
|
|
||||||
}
|
|
||||||
static std::vector<DWORD64> getXrefsTo(DWORD64 moduleBaseAddr, DWORD64 address, DWORD64 start, size_t size) {
|
static std::vector<DWORD64> getXrefsTo(DWORD64 moduleBaseAddr, DWORD64 address, DWORD64 start, size_t size) {
|
||||||
std::vector<DWORD64> xrefs = {};
|
std::vector<DWORD64> xrefs = {};
|
||||||
|
|
||||||
const DWORD64 finalOffset = address - moduleBaseAddr;
|
const DWORD64 finalOffset = address - moduleBaseAddr;
|
||||||
const std::string idaPattern = bytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<DWORD64*>(&finalOffset)), 4);
|
const std::string idaPattern = Memory::BytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<DWORD64*>(&finalOffset)), 4);
|
||||||
|
std::string patt = Memory::ConvertSigToScannerSig(idaPattern.c_str());
|
||||||
|
|
||||||
// Get the end of the section (in our case the end of the .rdata section)
|
// Get the end of the section (in our case the end of the .rdata section)
|
||||||
const DWORD64 end = start + size;
|
const DWORD64 end = start + size;
|
||||||
|
|
||||||
while (start && start < end) {
|
while (start && start < end) {
|
||||||
DWORD64 xref = reinterpret_cast<DWORD64>(Utils::SigScan::PatternScanner::FindPattern(reinterpret_cast<LPVOID>(start), size, { idaPattern.c_str(), Utils::SigScan::PatternType::Address}));
|
const auto scanner = memscan::mapped_region_t(start, end);
|
||||||
|
auto patternFind = scanner.find_pattern<ms_uptr_t>(patt);
|
||||||
|
|
||||||
// If the xref is 0 it means that there either were no xrefs, or there are no remaining xrefs.
|
// If the xref is 0 it means that there either were no xrefs, or there are no remaining xrefs.
|
||||||
// So we should break out of our loop, otherwise it will keep on trying to look for xrefs.
|
// So we should break out of our loop, otherwise it will keep on trying to look for xrefs.
|
||||||
if (!xref)
|
if (!patternFind.has_value())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We've found an xref, save it in the vector, and add 8 to start, so it wil now search for xrefs
|
// We've found an xref, save it in the vector, and add 8 to start, so it wil now search for xrefs
|
||||||
// from the previously found xref untill we're at the end of the section, or there aren't any xrefs left.
|
// from the previously found xref untill we're at the end of the section, or there aren't any xrefs left.
|
||||||
xrefs.push_back(xref);
|
xrefs.push_back(patternFind.value());
|
||||||
start = xref + 8;
|
start = patternFind.value() + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return xrefs;
|
return xrefs;
|
||||||
@ -83,7 +68,7 @@ namespace Utils {
|
|||||||
const std::string typeDescriptorName = ".?AV" + std::string(tableName) + "@@";
|
const std::string typeDescriptorName = ".?AV" + std::string(tableName) + "@@";
|
||||||
|
|
||||||
// Convert the string to an IDA pattern so that we can pattern scan it
|
// Convert the string to an IDA pattern so that we can pattern scan it
|
||||||
std::string idaPattern = bytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<char*>(typeDescriptorName.data())), typeDescriptorName.size());
|
std::string idaPattern = Memory::BytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<char*>(typeDescriptorName.data())), typeDescriptorName.size());
|
||||||
|
|
||||||
DWORD64 rttiTypeDescriptor = reinterpret_cast<DWORD64>(Utils::SigScan::PatternScanner::FindPattern(moduleName, { idaPattern.c_str(), Utils::SigScan::PatternType::Address }));
|
DWORD64 rttiTypeDescriptor = reinterpret_cast<DWORD64>(Utils::SigScan::PatternScanner::FindPattern(moduleName, { idaPattern.c_str(), Utils::SigScan::PatternType::Address }));
|
||||||
if (!rttiTypeDescriptor)
|
if (!rttiTypeDescriptor)
|
||||||
@ -113,7 +98,7 @@ namespace Utils {
|
|||||||
// Now we need to get an xref to the object locator, as that's where the vtable is located
|
// Now we need to get an xref to the object locator, as that's where the vtable is located
|
||||||
{
|
{
|
||||||
// Convert the object locator address to an IDA pattern
|
// Convert the object locator address to an IDA pattern
|
||||||
idaPattern = bytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<DWORD64*>(&objectLocator)), 8);
|
idaPattern = Memory::BytesToIDAPattern(reinterpret_cast<BYTE*>(const_cast<DWORD64*>(&objectLocator)), 8);
|
||||||
|
|
||||||
const DWORD64 vtableAddr = reinterpret_cast<DWORD64>(Utils::SigScan::PatternScanner::FindPattern(reinterpret_cast<LPVOID>(rdataStart), rdataSize, { idaPattern.c_str(), Utils::SigScan::PatternType::Address })) + 0x8;
|
const DWORD64 vtableAddr = reinterpret_cast<DWORD64>(Utils::SigScan::PatternScanner::FindPattern(reinterpret_cast<LPVOID>(rdataStart), rdataSize, { idaPattern.c_str(), Utils::SigScan::PatternType::Address })) + 0x8;
|
||||||
|
|
||||||
|
@ -38,109 +38,16 @@ namespace Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LPVOID PatternScanner::FindPattern(LPVOID startAddress, DWORD64 searchSize, const Pattern& pattern) {
|
LPVOID PatternScanner::FindPattern(LPVOID startAddress, DWORD64 searchSize, const Pattern& pattern) {
|
||||||
size_t len = strlen(pattern.pattern);
|
|
||||||
if (len == 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
DWORD64 pos = 0;
|
|
||||||
|
|
||||||
size_t byteCount = 1;
|
|
||||||
uint32_t i = 0;
|
|
||||||
while (i < len - 1) {
|
|
||||||
if (pattern.pattern[i] == ' ')
|
|
||||||
byteCount++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE* patt = reinterpret_cast<BYTE*>(malloc(byteCount + 1));
|
|
||||||
if (!patt)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
BYTE* mask = reinterpret_cast<BYTE*>(malloc(byteCount + 1));
|
|
||||||
if (!mask) {
|
|
||||||
free(patt);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int bytesCounted = 0;
|
std::string patt = Memory::ConvertSigToScannerSig(pattern.pattern, &offset);
|
||||||
i = 0;
|
|
||||||
while (i < len - 1) {
|
|
||||||
if (pattern.pattern[i] == '[') {
|
|
||||||
i++;
|
|
||||||
offset = bytesCounted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern.pattern[i] == '\0')
|
const auto scanner = memscan::mapped_region_t(reinterpret_cast<DWORD64>(startAddress), reinterpret_cast<DWORD64>(startAddress) + searchSize);
|
||||||
break;
|
auto patternFind = scanner.find_pattern<ms_uptr_t>(patt);
|
||||||
|
|
||||||
if (pattern.pattern[i] == '?' && pattern.pattern[i + 1] == '?') {
|
|
||||||
mask[bytesCounted] = '?';
|
|
||||||
patt[bytesCounted] = '\0';
|
|
||||||
} else {
|
|
||||||
BYTE hn = pattern.pattern[i] > '9' ? pattern.pattern[i] - 'A' + 10 : pattern.pattern[i] - '0';
|
|
||||||
BYTE ln = pattern.pattern[i + 1] > '9' ? pattern.pattern[i + 1] - 'A' + 10 : pattern.pattern[i + 1] - '0';
|
|
||||||
BYTE n = (hn << 4) | ln;
|
|
||||||
|
|
||||||
mask[bytesCounted] = 'x';
|
|
||||||
patt[bytesCounted] = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesCounted++;
|
|
||||||
|
|
||||||
i += 2;
|
|
||||||
while (i < len && (pattern.pattern[i] == ' ' || pattern.pattern[i] == '\t' || pattern.pattern[i] == '\r' || pattern.pattern[i] == '\n'))
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (bytesCounted <= byteCount)
|
|
||||||
mask[bytesCounted] = '\0';
|
|
||||||
|
|
||||||
LPVOID ret = nullptr;
|
LPVOID ret = nullptr;
|
||||||
const DWORD64 retAddress = reinterpret_cast<DWORD64>(startAddress);
|
|
||||||
const DWORD64 endAddress = retAddress + searchSize;
|
|
||||||
size_t searchLen = bytesCounted;
|
|
||||||
|
|
||||||
BYTE* retAddressPtr = reinterpret_cast<BYTE*>(retAddress);
|
if (patternFind.has_value())
|
||||||
BYTE* endAddressPtr = reinterpret_cast<BYTE*>(endAddress);
|
ret = reinterpret_cast<LPVOID>(patternFind.value() + offset);
|
||||||
|
|
||||||
while (retAddressPtr < endAddressPtr) {
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
if (VirtualQuery(retAddressPtr, &mbi, sizeof(mbi))) {
|
|
||||||
// Check if the memory region is readable
|
|
||||||
if (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READONLY | PAGE_READWRITE)) {
|
|
||||||
// Adjust the end address to the end of this memory region
|
|
||||||
BYTE* regionEnd = reinterpret_cast<BYTE*>(mbi.BaseAddress) + mbi.RegionSize;
|
|
||||||
|
|
||||||
// Only scan within this region
|
|
||||||
while (retAddressPtr < regionEnd && retAddressPtr < endAddressPtr) {
|
|
||||||
bool found = true;
|
|
||||||
|
|
||||||
for (size_t j = 0; j < searchLen; j++) {
|
|
||||||
if (mask[j] == 'x' && retAddressPtr[j] != patt[j]) {
|
|
||||||
found = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
ret = reinterpret_cast<LPVOID>(retAddressPtr + offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
retAddressPtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != nullptr)
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
// Skip the non-readable memory region
|
|
||||||
retAddressPtr = reinterpret_cast<BYTE*>(mbi.BaseAddress) + mbi.RegionSize;
|
|
||||||
} else
|
|
||||||
retAddressPtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(patt);
|
|
||||||
free(mask);
|
|
||||||
|
|
||||||
switch (pattern.type) {
|
switch (pattern.type) {
|
||||||
case PatternType::Pointer:
|
case PatternType::Pointer:
|
||||||
|
Reference in New Issue
Block a user