init commit, hooks ported from spicetools
This commit is contained in:
commit
109501550e
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.vs/
|
||||
x64/
|
||||
depthrush/x64/
|
||||
Release/
|
||||
depthrush/Release/
|
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# depthrush
|
||||
Work in progress Kinect driver for Dancerush Stardom.
|
||||
|
||||
## Installation
|
||||
1. Patch SpiceTools to disable all DRS pad hooks.
|
||||
2. Copy `depthrush.dll` to the same folder as spice64 and use spicecfg to inject depthrush.
|
31
depthrush.sln
Normal file
31
depthrush.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32616.157
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "depthrush", "depthrush\depthrush.vcxproj", "{04B17470-CB82-4724-904B-25445926AB86}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Debug|x64.Build.0 = Debug|x64
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Debug|x86.Build.0 = Debug|Win32
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Release|x64.ActiveCfg = Release|x64
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Release|x64.Build.0 = Release|x64
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Release|x86.ActiveCfg = Release|Win32
|
||||
{04B17470-CB82-4724-904B-25445926AB86}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {A99829DB-1A71-44FC-BA06-638D3412F1BC}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
193
depthrush/depthrush.vcxproj
Normal file
193
depthrush/depthrush.vcxproj
Normal file
@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{04B17470-CB82-4724-904B-25445926AB86}</ProjectGuid>
|
||||
<RootNamespace>ImGuiDirectX11KieroHook</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>depthrush</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x64;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LibraryPath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x64;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="drs.cpp" />
|
||||
<ClCompile Include="kiero\kiero.cpp" />
|
||||
<ClCompile Include="kiero\minhook\src\buffer.c" />
|
||||
<ClCompile Include="kiero\minhook\src\hde\hde32.c" />
|
||||
<ClCompile Include="kiero\minhook\src\hde\hde64.c" />
|
||||
<ClCompile Include="kiero\minhook\src\hook.c" />
|
||||
<ClCompile Include="kiero\minhook\src\trampoline.c" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="kiero\minhook\dll_resources\MinHook.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="kiero\minhook\dll_resources\MinHook.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="drs.h" />
|
||||
<ClInclude Include="includes.h" />
|
||||
<ClInclude Include="kiero\injector\assembly.hpp" />
|
||||
<ClInclude Include="kiero\injector\calling.hpp" />
|
||||
<ClInclude Include="kiero\injector\gvm\gvm.hpp" />
|
||||
<ClInclude Include="kiero\injector\gvm\translator.hpp" />
|
||||
<ClInclude Include="kiero\injector\hooking.hpp" />
|
||||
<ClInclude Include="kiero\injector\injector.hpp" />
|
||||
<ClInclude Include="kiero\injector\utility.hpp" />
|
||||
<ClInclude Include="kiero\kiero.h" />
|
||||
<ClInclude Include="kiero\minhook\include\MinHook.h" />
|
||||
<ClInclude Include="kiero\minhook\src\buffer.h" />
|
||||
<ClInclude Include="kiero\minhook\src\hde\hde32.h" />
|
||||
<ClInclude Include="kiero\minhook\src\hde\hde64.h" />
|
||||
<ClInclude Include="kiero\minhook\src\hde\pstdint.h" />
|
||||
<ClInclude Include="kiero\minhook\src\hde\table32.h" />
|
||||
<ClInclude Include="kiero\minhook\src\hde\table64.h" />
|
||||
<ClInclude Include="kiero\minhook\src\trampoline.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
112
depthrush/depthrush.vcxproj.filters
Normal file
112
depthrush/depthrush.vcxproj.filters
Normal file
@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="kiero">
|
||||
<UniqueIdentifier>{c914abae-6128-4a2a-8821-07a38f656930}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="kiero\minhook\src\buffer.c">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kiero\minhook\src\hde\hde32.c">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kiero\minhook\src\hde\hde64.c">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kiero\minhook\src\hook.c">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kiero\kiero.cpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kiero\minhook\src\trampoline.c">
|
||||
<Filter>kiero</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="drs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="kiero\minhook\dll_resources\MinHook.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="kiero\minhook\src\buffer.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\hde\hde32.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\hde\hde64.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\kiero.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\include\MinHook.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\hde\pstdint.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\hde\table32.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\hde\table64.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\minhook\src\trampoline.h">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="includes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\assembly.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\calling.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\gvm\gvm.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\gvm\translator.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\hooking.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\injector.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="kiero\injector\utility.hpp">
|
||||
<Filter>kiero</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="drs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="kiero\minhook\dll_resources\MinHook.def">
|
||||
<Filter>kiero</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
6
depthrush/depthrush.vcxproj.user
Normal file
6
depthrush/depthrush.vcxproj.user
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>false</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
166
depthrush/drs.cpp
Normal file
166
depthrush/drs.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "drs.h"
|
||||
#include "includes.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <thread>
|
||||
|
||||
#pragma pack(push)
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
WORD unk1;
|
||||
WORD unk2;
|
||||
WORD device_id;
|
||||
WORD vid;
|
||||
WORD pid;
|
||||
WORD pvn;
|
||||
WORD max_point_num;
|
||||
};
|
||||
uint8_t raw[2356];
|
||||
};
|
||||
} dev_info_t;
|
||||
|
||||
typedef struct {
|
||||
DWORD cid;
|
||||
DWORD type;
|
||||
DWORD unused;
|
||||
DWORD y;
|
||||
DWORD x;
|
||||
DWORD height;
|
||||
DWORD width;
|
||||
DWORD unk8;
|
||||
} touch_data_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
enum touch_type {
|
||||
TS_DOWN = 1,
|
||||
TS_MOVE = 2,
|
||||
TS_UP = 3,
|
||||
};
|
||||
|
||||
void *user_data = nullptr;
|
||||
void (*touch_callback)(
|
||||
dev_info_t *dev_info,
|
||||
const touch_data_t *touch_data,
|
||||
int touch_points,
|
||||
int unk1,
|
||||
const void *user_data);
|
||||
|
||||
namespace drs {
|
||||
|
||||
void* TouchSDK_Constructor(void* in) {
|
||||
return in;
|
||||
}
|
||||
|
||||
bool TouchSDK_SendData(dev_info_t*,
|
||||
unsigned char* const, int, unsigned char* const,
|
||||
unsigned char* output, int output_size) {
|
||||
|
||||
// fake success
|
||||
if (output_size >= 4) {
|
||||
output[0] = 0xfc;
|
||||
output[1] = 0xa5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetSignalInit(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TouchSDK_Destructor(void* This) {
|
||||
}
|
||||
|
||||
int TouchSDK_GetYLedTotal(dev_info_t*, int) {
|
||||
return 53;
|
||||
}
|
||||
|
||||
int TouchSDK_GetXLedTotal(dev_info_t*, int) {
|
||||
return 41;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableTouch(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableDrag(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableWheel(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_DisableRightClick(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetMultiTouchMode(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_EnableTouchWidthData(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_EnableRawData(dev_info_t*, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchSDK_SetAllEnable(dev_info_t*, bool, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int TouchSDK_GetTouchDeviceCount(void* This) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int TouchSDK_GetTouchSDKVersion(void) {
|
||||
return 0x01030307;
|
||||
}
|
||||
|
||||
int TouchSDK_InitTouch(void* This, dev_info_t* devices, int max_devices, void* touch_event_cb,
|
||||
void* hotplug_callback, void* userdata) {
|
||||
|
||||
// fake touch device
|
||||
memset(devices, 0, sizeof(devices[0].raw));
|
||||
devices[0].unk1 = 0x1122;
|
||||
devices[0].unk2 = 0x3344;
|
||||
devices[0].device_id = 0;
|
||||
devices[0].vid = 0xDEAD;
|
||||
devices[0].pid = 0xBEEF;
|
||||
devices[0].pvn = 0xC0DE;
|
||||
devices[0].max_point_num = 16;
|
||||
|
||||
// remember provided callback and userdata
|
||||
touch_callback = (decltype(touch_callback))touch_event_cb;
|
||||
user_data = userdata;
|
||||
|
||||
// success
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hookDancepad() {
|
||||
MH_Initialize();
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "??0TouchSDK@@QEAA@XZ", TouchSDK_Constructor, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?SendData@TouchSDK@@QEAA_NU_DeviceInfo@@QEAEH1HH@Z", TouchSDK_SendData, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?SetSignalInit@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_SetSignalInit, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?GetYLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z", TouchSDK_GetYLedTotal, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?GetXLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z", TouchSDK_GetXLedTotal, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?DisableTouch@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_DisableTouch, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?DisableDrag@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_DisableDrag, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?DisableWheel@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_DisableWheel, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?DisableRightClick@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_DisableRightClick, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?SetMultiTouchMode@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_SetMultiTouchMode, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?EnableTouchWidthData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_EnableTouchWidthData, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?EnableRawData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z", TouchSDK_EnableRawData, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?SetAllEnable@TouchSDK@@QEAA_NU_DeviceInfo@@_NH@Z", TouchSDK_SetAllEnable, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?GetTouchDeviceCount@TouchSDK@@QEAAHXZ", TouchSDK_GetTouchDeviceCount, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?GetTouchSDKVersion@TouchSDK@@QEAAIXZ", TouchSDK_GetTouchSDKVersion, NULL);
|
||||
MH_CreateHookApi(L"TouchSDKDll.dll", "?InitTouch@TouchSDK@@QEAAHPEAU_DeviceInfo@@HP6AXU2@PEBU_TouchPointData@@HHPEBX@ZP6AX1_N3@ZPEAX@Z", TouchSDK_InitTouch, NULL);
|
||||
|
||||
MH_EnableHook(MH_ALL_HOOKS);
|
||||
}
|
||||
}
|
43
depthrush/drs.h
Normal file
43
depthrush/drs.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
namespace drs {
|
||||
|
||||
enum DRS_TOUCH_TYPE {
|
||||
DRS_DOWN = 0,
|
||||
DRS_UP = 1,
|
||||
DRS_MOVE = 2,
|
||||
};
|
||||
|
||||
typedef struct drs_touch_t {
|
||||
int type = DRS_UP;
|
||||
int id = 0;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
double width = 1;
|
||||
double height = 1;
|
||||
};
|
||||
|
||||
struct VRFoot {
|
||||
unsigned int id;
|
||||
unsigned int index = 2;
|
||||
float length = 3.1;
|
||||
float size_base = 0.05;
|
||||
float size_scale = 0.1;
|
||||
float height = 3;
|
||||
//linalg::aliases::float4 rotation {0, 0, 0, 1};
|
||||
drs_touch_t event{};
|
||||
//unsigned int get_index();
|
||||
//linalg::aliases::float3 to_world(linalg::aliases::float3 pos);
|
||||
};
|
||||
|
||||
extern char DRS_TAPELED[38 * 49][3];
|
||||
//extern linalg::aliases::float3 VR_SCALE;
|
||||
//extern linalg::aliases::float3 VR_OFFSET;
|
||||
extern float VR_ROTATION;
|
||||
extern VRFoot VR_FOOTS[2];
|
||||
|
||||
//void fire_touches(drs_touch_t* events, size_t event_count);
|
||||
//void start_vr();
|
||||
|
||||
void hookDancepad();
|
||||
}
|
13
depthrush/includes.h
Normal file
13
depthrush/includes.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <libloaderapi.h>
|
||||
#include <winnt.h>
|
||||
#include <iostream>
|
||||
#include "kiero/kiero.h"
|
||||
#include "kiero/minhook/include/MinHook.h"
|
||||
#include "kiero/injector/injector.hpp"
|
||||
#include "d3d9.h"
|
||||
|
||||
|
||||
typedef LRESULT(CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
|
||||
typedef uintptr_t PTR;
|
178
depthrush/kiero/injector/assembly.hpp
Normal file
178
depthrush/kiero/injector/assembly.hpp
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Injectors - Useful Assembly Stuff
|
||||
*
|
||||
* Copyright (C) 2012-2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// This header is very restrict about compiler and architecture
|
||||
#ifndef _MSC_VER // MSVC is much more flexible when we're talking about inline assembly
|
||||
#error Cannot use this header in another compiler other than MSVC
|
||||
#endif
|
||||
#ifndef _M_IX86
|
||||
#error Supported only in x86
|
||||
#endif
|
||||
|
||||
//
|
||||
#include "injector.hpp"
|
||||
|
||||
namespace injector
|
||||
{
|
||||
struct reg_pack
|
||||
{
|
||||
// The ordering is very important, don't change
|
||||
// The first field is the last to be pushed and first to be poped
|
||||
|
||||
// PUSHFD / POPFD
|
||||
uint32_t ef;
|
||||
|
||||
// PUSHAD/POPAD -- must be the lastest fields (because of esp)
|
||||
union
|
||||
{
|
||||
uint32_t arr[8];
|
||||
struct { uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; };
|
||||
};
|
||||
|
||||
enum reg_name {
|
||||
reg_edi, reg_esi, reg_ebp, reg_esp, reg_ebx, reg_edx, reg_ecx, reg_eax
|
||||
};
|
||||
|
||||
enum ef_flag {
|
||||
carry_flag = 0, parity_flag = 2, adjust_flag = 4, zero_flag = 6, sign_flag = 7,
|
||||
direction_flag = 10, overflow_flag = 11
|
||||
};
|
||||
|
||||
uint32_t& operator[](size_t i)
|
||||
{ return this->arr[i]; }
|
||||
const uint32_t& operator[](size_t i) const
|
||||
{ return this->arr[i]; }
|
||||
|
||||
template<uint32_t bit> // bit starts from 0, use ef_flag enum
|
||||
bool flag()
|
||||
{
|
||||
return (this->ef & (1 << bit)) != 0;
|
||||
}
|
||||
|
||||
bool jnb()
|
||||
{
|
||||
return flag<carry_flag>() == false;
|
||||
}
|
||||
};
|
||||
|
||||
// Lowest level stuff (actual assembly) goes on the following namespace
|
||||
// PRIVATE! Skip this, not interesting for you.
|
||||
namespace injector_asm
|
||||
{
|
||||
// Wrapper functor, so the assembly can use some templating
|
||||
template<class T>
|
||||
struct wrapper
|
||||
{
|
||||
static void call(reg_pack* regs)
|
||||
{
|
||||
T fun; fun(*regs);
|
||||
}
|
||||
};
|
||||
|
||||
// Constructs a reg_pack and calls the wrapper functor
|
||||
template<class W> // where W is of type wrapper
|
||||
inline void __declspec(naked) make_reg_pack_and_call()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// Construct the reg_pack structure on the stack
|
||||
pushad // Pushes general purposes registers to reg_pack
|
||||
add [esp+12], 4 // Add 4 to reg_pack::esp 'cuz of our return pointer, let it be as before this func is called
|
||||
pushfd // Pushes EFLAGS to reg_pack
|
||||
|
||||
// Call wrapper sending reg_pack as parameter
|
||||
push esp
|
||||
call W::call
|
||||
add esp, 4
|
||||
|
||||
// Destructs the reg_pack from the stack
|
||||
sub [esp+12+4], 4 // Fix reg_pack::esp before popping it (doesn't make a difference though) (+4 because eflags)
|
||||
popfd // Warning: Do not use any instruction that changes EFLAGS after this (-> sub affects EF!! <-)
|
||||
popad
|
||||
|
||||
// Back to normal flow
|
||||
ret
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* MakeInline
|
||||
* Makes inline assembly (but not assembly, an actual functor of type FuncT) at address
|
||||
*/
|
||||
template<class FuncT>
|
||||
void MakeInline(memory_pointer_tr at)
|
||||
{
|
||||
typedef injector_asm::wrapper<FuncT> functor;
|
||||
if(false) functor::call(nullptr); // To instantiate the template, if not done _asm will fail
|
||||
MakeCALL(at, injector_asm::make_reg_pack_and_call<functor>);
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeInline
|
||||
* Same as above, but it NOPs everything between at and end (exclusive), then performs MakeInline
|
||||
*/
|
||||
template<class FuncT>
|
||||
void MakeInline(memory_pointer_tr at, memory_pointer_tr end)
|
||||
{
|
||||
MakeRangedNOP(at, end);
|
||||
MakeInline<FuncT>(at);
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeInline
|
||||
* Same as above, but (at,end) are template parameters.
|
||||
* On this case the functor can be passed as argument since there will be one func instance for each at,end not just for each FuncT
|
||||
*/
|
||||
template<uintptr_t at, uintptr_t end, class FuncT>
|
||||
void MakeInline(FuncT func)
|
||||
{
|
||||
static FuncT static_func = func; // Stores the func object
|
||||
static_func = func; //
|
||||
|
||||
// Encapsulates the call to static_func
|
||||
struct Caps
|
||||
{
|
||||
void operator()(reg_pack& regs)
|
||||
{ static_func(regs); }
|
||||
};
|
||||
|
||||
// Does the actual MakeInline
|
||||
return MakeInline<Caps>(lazy_pointer<at>::get(), lazy_pointer<end>::get());
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeInline
|
||||
* Same as above, but (end) is calculated by the length of a call instruction
|
||||
*/
|
||||
template<uintptr_t at, class FuncT>
|
||||
void MakeInline(FuncT func)
|
||||
{
|
||||
return MakeInline<at, at+5, FuncT>(func);
|
||||
}
|
||||
};
|
127
depthrush/kiero/injector/calling.hpp
Normal file
127
depthrush/kiero/injector/calling.hpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Injectors - Function Calls Using Variadic Templates
|
||||
*
|
||||
* Copyright (C) 2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "injector.hpp"
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
#if __cplusplus >= 201103L || _MSC_VER >= 1800 // MSVC 2013
|
||||
#else
|
||||
#error "This feature is not supported on this compiler"
|
||||
#endif
|
||||
|
||||
namespace injector
|
||||
{
|
||||
template<class Prototype>
|
||||
struct cstd;
|
||||
|
||||
template<class Ret, class ...Args>
|
||||
struct cstd<Ret(Args...)>
|
||||
{
|
||||
// Call function at @p returning @Ret with args @Args
|
||||
static Ret call(memory_pointer_tr p, Args... a)
|
||||
{
|
||||
auto fn = (Ret(*)(Args...)) p.get<void>();
|
||||
return fn(std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
template<uintptr_t addr> // Uses lazy pointer
|
||||
static Ret call(Args... a)
|
||||
{
|
||||
return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Prototype>
|
||||
struct stdcall;
|
||||
|
||||
template<class Ret, class ...Args>
|
||||
struct stdcall<Ret(Args...)>
|
||||
{
|
||||
// Call function at @p returning @Ret with args @Args
|
||||
static Ret call(memory_pointer_tr p, Args... a)
|
||||
{
|
||||
auto fn = (Ret(__stdcall *)(Args...)) p.get<void>();
|
||||
return fn(std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
template<uintptr_t addr> // Uses lazy pointer
|
||||
static Ret call(Args... a)
|
||||
{
|
||||
return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Prototype>
|
||||
struct fastcall;
|
||||
|
||||
template<class Ret, class ...Args>
|
||||
struct fastcall<Ret(Args...)>
|
||||
{
|
||||
// Call function at @p returning @Ret with args @Args
|
||||
static Ret call(memory_pointer_tr p, Args... a)
|
||||
{
|
||||
auto fn = (Ret(__fastcall *)(Args...)) p.get<void>();;
|
||||
return fn(std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
template<uintptr_t addr> // Uses lazy pointer
|
||||
static Ret call(Args... a)
|
||||
{
|
||||
return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Prototype>
|
||||
struct thiscall;
|
||||
|
||||
template<class Ret, class ...Args>
|
||||
struct thiscall<Ret(Args...)>
|
||||
{
|
||||
// Call function at @p returning @Ret with args @Args
|
||||
static Ret call(memory_pointer_tr p, Args... a)
|
||||
{
|
||||
auto fn = (Ret(__thiscall *)(Args...)) p.get<void>();
|
||||
return fn(std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
// Call function at the index @i from the vtable of the object @a[0]
|
||||
template<size_t i>
|
||||
static Ret vtbl(Args... a)
|
||||
{
|
||||
auto obj = raw_ptr(std::get<0>(std::forward_as_tuple(a...)));
|
||||
auto p = raw_ptr( (*obj.template get<void**>()) [i] );
|
||||
return call(p, std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
template<uintptr_t addr> // Uses lazy pointer
|
||||
static Ret call(Args... a)
|
||||
{
|
||||
return call(lazy_pointer<addr>::get(), std::forward<Args>(a)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
125
depthrush/kiero/injector/gvm/gvm.hpp
Normal file
125
depthrush/kiero/injector/gvm/gvm.hpp
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Injectors - Base Header
|
||||
*
|
||||
* Copyright (C) 2012-2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
namespace injector
|
||||
{
|
||||
|
||||
#if 1 // GVM and Address Translator, Not very interesting for the users, so skip reading those...
|
||||
|
||||
/*
|
||||
* game_version_manager
|
||||
* Detects the game, the game version and the game region
|
||||
* This assumes the executable is decrypted, so, Silent's ASI Loader is recommended.
|
||||
*/
|
||||
#ifndef INJECTOR_OWN_GVM
|
||||
class game_version_manager
|
||||
{
|
||||
public:
|
||||
bool Detect() { return true; }
|
||||
};
|
||||
#endif // INJECTOR_OWN_GVM
|
||||
|
||||
|
||||
/*
|
||||
* address_manager
|
||||
* Address translator from 1.0 executables to other executables offsets
|
||||
* Inherits from game_version_manager ;)
|
||||
*/
|
||||
class address_manager : public game_version_manager
|
||||
{
|
||||
private:
|
||||
address_manager()
|
||||
{
|
||||
this->Detect();
|
||||
}
|
||||
|
||||
// You could implement your translator for the address your plugin uses
|
||||
// If not implemented, the translator won't translate anything, just return the samething as before
|
||||
#ifdef INJECTOR_GVM_HAS_TRANSLATOR
|
||||
void* translator(void* p);
|
||||
#else
|
||||
void* translator(void* p) { return p; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Translates address p to the running executable pointer
|
||||
void* translate(void* p)
|
||||
{
|
||||
return translator(p);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// Address manager singleton
|
||||
static address_manager& singleton()
|
||||
{
|
||||
static address_manager m;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Static version of translate()
|
||||
static void* translate_address(void* p)
|
||||
{
|
||||
return singleton().translate(p);
|
||||
}
|
||||
|
||||
public:
|
||||
// Functors for memory translation:
|
||||
|
||||
// Translates aslr translator
|
||||
struct fn_mem_translator_aslr
|
||||
{
|
||||
void* operator()(void* p) const
|
||||
{
|
||||
static uintptr_t module = (uintptr_t)GetModuleHandle(NULL);
|
||||
return (void*)((uintptr_t)(p)-(0x400000 - module));
|
||||
}
|
||||
};
|
||||
|
||||
// Translates nothing translator
|
||||
struct fn_mem_translator_nop
|
||||
{
|
||||
void* operator()(void* p) const
|
||||
{ return p; }
|
||||
};
|
||||
|
||||
// Real translator
|
||||
struct fn_mem_translator
|
||||
{
|
||||
void* operator()(void* p) const
|
||||
{ return translate_address(p); }
|
||||
};
|
||||
};
|
||||
|
||||
#endif // #if 1
|
||||
|
||||
|
||||
}
|
203
depthrush/kiero/injector/gvm/translator.hpp
Normal file
203
depthrush/kiero/injector/gvm/translator.hpp
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Injectors - Address Translation Management
|
||||
*
|
||||
* Copyright (C) 2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(INJECTOR_GVM_HAS_TRANSLATOR)
|
||||
#error Missing INJECTOR_GVM_HAS_TRANSLATOR on compiler definitions
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is a quick solution for address translations if you're too lazy to implement a proper address_manager::translator by yourself
|
||||
* So, just call address_translator_manager::singleton().translate(p) from your address_manager::translator and that's it.
|
||||
* It'll translate addresses based on 'address_translator' objects, when one gets constructed it turns into a possible translator.
|
||||
* At the constructor of your derived 'address_translator' make the map object to have [addr_to_translate] = translated_addr;
|
||||
* There's also the virtual method 'fallback' that will get called when the translation wasn't possible, you can do some fallback stuff here
|
||||
* (such as return the pointer as is or output a error message)
|
||||
*/
|
||||
|
||||
#include "../injector.hpp"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
namespace injector
|
||||
{
|
||||
/*
|
||||
* address_translator
|
||||
* Base for an address translator
|
||||
*/
|
||||
class address_translator
|
||||
{
|
||||
private:
|
||||
bool enabled;
|
||||
void add();
|
||||
void remove();
|
||||
|
||||
protected:
|
||||
friend class address_translator_manager;
|
||||
std::map<memory_pointer_raw, memory_pointer_raw> map;
|
||||
|
||||
public:
|
||||
address_translator() : enabled(true)
|
||||
{
|
||||
// Must have bounds filled with min ptr and max ptr to have search working properly
|
||||
map.insert(std::make_pair(raw_ptr(0x00000000u), raw_ptr(0x00000000u)));
|
||||
map.insert(std::make_pair(raw_ptr(0xffffffffu), raw_ptr(0xffffffffu)));
|
||||
add();
|
||||
}
|
||||
|
||||
~address_translator()
|
||||
{
|
||||
remove();
|
||||
}
|
||||
|
||||
virtual void* fallback(void*) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Enables or disables this translator
|
||||
void enable(bool enable_it)
|
||||
{
|
||||
if(enable_it) this->enable();
|
||||
else this->disable();
|
||||
}
|
||||
|
||||
// Enables this translator
|
||||
void enable()
|
||||
{
|
||||
this->enabled = true;
|
||||
}
|
||||
|
||||
// Disables this translator
|
||||
void disable()
|
||||
{
|
||||
this->enabled = false;
|
||||
}
|
||||
|
||||
// Checks if this translator is enabled
|
||||
bool is_enabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* address_translator_manager
|
||||
* Manages the address_translator objects
|
||||
*/
|
||||
class address_translator_manager
|
||||
{
|
||||
protected:
|
||||
friend class address_manager;
|
||||
friend class address_translator;
|
||||
|
||||
std::list<const address_translator*> translators;
|
||||
|
||||
void add(const address_translator& t)
|
||||
{
|
||||
translators.push_front(&t);
|
||||
}
|
||||
|
||||
void remove(const address_translator& t)
|
||||
{
|
||||
translators.remove(&t);
|
||||
}
|
||||
|
||||
public:
|
||||
// Translates the address p
|
||||
void* translator(void* p);
|
||||
|
||||
// Singleton object
|
||||
static address_translator_manager& singleton()
|
||||
{
|
||||
static address_translator_manager mgr;
|
||||
return mgr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void* address_translator_manager::translator(void* p_)
|
||||
{
|
||||
static const size_t max_ptr_dist = 7;
|
||||
|
||||
// Tries to find an address in a translator map
|
||||
auto try_map = [](const std::map<memory_pointer_raw, memory_pointer_raw>& map, memory_pointer_raw p) -> memory_pointer_raw
|
||||
{
|
||||
memory_pointer_raw result = nullptr;
|
||||
|
||||
// Find first element in the map that is greater than or equal to p
|
||||
auto it = map.lower_bound(p);
|
||||
if(it != map.end())
|
||||
{
|
||||
// If it's not exactly the address, get back one position on the table
|
||||
if(it->first != p) --it;
|
||||
|
||||
auto diff = (p - it->first).as_int(); // What's the difference between p and that address?
|
||||
if(diff <= max_ptr_dist) // Could we live with this difference in hands?
|
||||
result = it->second + raw_ptr(diff); // Yes, we can!
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
memory_pointer_raw result = nullptr;
|
||||
|
||||
// Try to find translation for this pointer
|
||||
auto& mgr = address_translator_manager::singleton().translators;
|
||||
for(auto it = mgr.begin(); result == nullptr && it != mgr.end(); ++it)
|
||||
{
|
||||
auto& t = **it;
|
||||
if(t.is_enabled()) result = try_map(t.map, p_);
|
||||
}
|
||||
|
||||
// If we couldn't translate the address, notify and try to fallback
|
||||
if(result.is_null())
|
||||
{
|
||||
for(auto it = mgr.begin(); result == nullptr && it != mgr.end(); ++it)
|
||||
{
|
||||
auto& t = **it;
|
||||
if(t.is_enabled()) result = t.fallback(p_);
|
||||
}
|
||||
}
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
inline void address_translator::add()
|
||||
{
|
||||
address_translator_manager::singleton().add(*this);
|
||||
}
|
||||
|
||||
inline void address_translator::remove()
|
||||
{
|
||||
address_translator_manager::singleton().remove(*this);
|
||||
}
|
||||
}
|
687
depthrush/kiero/injector/hooking.hpp
Normal file
687
depthrush/kiero/injector/hooking.hpp
Normal file
@ -0,0 +1,687 @@
|
||||
/*
|
||||
* Injectors - Classes for making your hooking life easy
|
||||
*
|
||||
* Copyright (C) 2013-2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "injector.hpp"
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory> // for std::shared_ptr
|
||||
#include <list>
|
||||
|
||||
namespace injector
|
||||
{
|
||||
/*
|
||||
* scoped_base
|
||||
* Base for any scoped hooking type
|
||||
* !!!! NOTICE !!!! --> Any derived which implements/reimplements restore() should implement a destructor calling it
|
||||
*/
|
||||
class scoped_base
|
||||
{
|
||||
public:
|
||||
virtual ~scoped_base() {}
|
||||
virtual void restore() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* scoped_basic
|
||||
* Base for scoped types which will need a buffer to save/restore stuff
|
||||
*/
|
||||
template<size_t bufsize> // TODO specialize bufsize=0 to be dynamic
|
||||
class scoped_basic : public scoped_base
|
||||
{
|
||||
private:
|
||||
uint8_t buf[bufsize];// Saved content
|
||||
memory_pointer_raw addr; // Data saved from this address
|
||||
size_t size; // Size saved
|
||||
bool saved; // Something saved?
|
||||
bool vp; // Virtual protect?
|
||||
|
||||
public:
|
||||
|
||||
static const bool is_dynamic = false;
|
||||
|
||||
// Restore the previosly saved data
|
||||
// Problems may arise if someone else hooked the same place using the same method
|
||||
virtual void restore()
|
||||
{
|
||||
#ifndef INJECTOR_SCOPED_NOSAVE_NORESTORE
|
||||
if(this->saved)
|
||||
{
|
||||
WriteMemoryRaw(this->addr, this->buf, this->size, this->vp);
|
||||
this->saved = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Save buffer at @addr with @size and virtual protect @vp
|
||||
virtual void save(memory_pointer_tr addr, size_t size, bool vp)
|
||||
{
|
||||
#ifndef INJECTOR_SCOPED_NOSAVE_NORESTORE
|
||||
assert(size <= bufsize); // Debug Safeness
|
||||
this->restore(); // Restore anything we have saved
|
||||
this->saved = true; // Mark that we have data save
|
||||
this->addr = addr.get<void>(); // Save address
|
||||
this->size = size; // Save size
|
||||
this->vp = vp; // Save virtual protect
|
||||
ReadMemoryRaw(addr, buf, size, vp); // Save buffer
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructor, initialises
|
||||
scoped_basic() : saved(false)
|
||||
{}
|
||||
|
||||
~scoped_basic()
|
||||
{
|
||||
this->restore();
|
||||
}
|
||||
|
||||
// No copy construction, we can't do this! Sure we can move construct :)
|
||||
scoped_basic(const scoped_basic&) = delete;
|
||||
scoped_basic(scoped_basic&& rhs)
|
||||
{
|
||||
*this = std::move(rhs);
|
||||
}
|
||||
|
||||
scoped_basic& operator=(const scoped_basic& rhs) = delete;
|
||||
scoped_basic& operator=(scoped_basic&& rhs)
|
||||
{
|
||||
if(this->saved = rhs.saved)
|
||||
{
|
||||
assert(bufsize >= rhs.size);
|
||||
|
||||
this->addr = rhs.addr;
|
||||
this->size = rhs.size;
|
||||
this->vp = rhs.vp;
|
||||
memcpy(buf, rhs.buf, rhs.size);
|
||||
|
||||
rhs.saved = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* RAII wrapper for memory writes
|
||||
* Can save only basic and POD types
|
||||
*/
|
||||
template<size_t bufsize_ = 10>
|
||||
class scoped_write : public scoped_basic<bufsize_>
|
||||
{
|
||||
public:
|
||||
// Save buffer at @addr with @size and virtual protect @vp and then overwrite it with @value
|
||||
void write(memory_pointer_tr addr, void* value, size_t size, bool vp)
|
||||
{
|
||||
this->save(addr, size, vp);
|
||||
return WriteMemoryRaw(addr, value, size, vp);
|
||||
}
|
||||
|
||||
// Save buffer at @addr with size sizeof(@value) and virtual protect @vp and then overwrite it with @value
|
||||
template<class T>
|
||||
void write(memory_pointer_tr addr, T value, bool vp = false)
|
||||
{
|
||||
this->save(addr, sizeof(T), vp);
|
||||
return WriteMemory<T>(addr, value, vp);
|
||||
}
|
||||
|
||||
// Constructors, move constructors, assigment operators........
|
||||
scoped_write() = default;
|
||||
scoped_write(const scoped_write&) = delete;
|
||||
scoped_write(scoped_write&& rhs) : scoped_basic<bufsize_>(std::move(rhs)) {}
|
||||
scoped_write& operator=(const scoped_write& rhs) = delete;
|
||||
scoped_write& operator=(scoped_write&& rhs)
|
||||
{ scoped_basic<bufsize_>::operator=(std::move(rhs)); return *this; }
|
||||
};
|
||||
|
||||
/*
|
||||
* RAII wrapper for filling
|
||||
*/
|
||||
template<size_t bufsize_ = 5>
|
||||
class scoped_fill : public scoped_basic<bufsize_>
|
||||
{
|
||||
public:
|
||||
// Fills memory at @addr with value @value and size @size and virtual protect @vp
|
||||
void fill(memory_pointer_tr addr, uint8_t value, size_t size, bool vp)
|
||||
{
|
||||
this->save(addr, size, vp);
|
||||
return MemoryFill(addr, value, size, vp);
|
||||
}
|
||||
|
||||
// Constructors, move constructors, assigment operators........
|
||||
scoped_fill() = default;
|
||||
scoped_fill(const scoped_fill&) = delete;
|
||||
scoped_fill(scoped_fill&& rhs) : scoped_basic<bufsize_>(std::move(rhs)) {}
|
||||
scoped_fill& operator=(const scoped_fill& rhs) = delete;
|
||||
scoped_fill& operator=(scoped_fill&& rhs)
|
||||
{ scoped_basic<bufsize_>::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
scoped_fill(memory_pointer_tr addr, uint8_t value, size_t size, bool vp)
|
||||
{ fill(addr, value, vp); }
|
||||
};
|
||||
|
||||
/*
|
||||
* RAII wrapper for nopping
|
||||
*/
|
||||
template<size_t bufsize_>
|
||||
class scoped_nop : public scoped_basic<bufsize_>
|
||||
{
|
||||
public:
|
||||
// Makes NOP at @addr with value @value and size @size and virtual protect @vp
|
||||
void make_nop(memory_pointer_tr addr, size_t size = 1, bool vp = true)
|
||||
{
|
||||
this->save(addr, size, vp);
|
||||
return MakeNOP(addr, size, vp);
|
||||
}
|
||||
|
||||
// Constructors, move constructors, assigment operators........
|
||||
scoped_nop() = default;
|
||||
scoped_nop(const scoped_nop&) = delete;
|
||||
scoped_nop(scoped_nop&& rhs) : scoped_basic<bufsize_>(std::move(rhs)) {}
|
||||
scoped_nop& operator=(const scoped_nop& rhs) = delete;
|
||||
scoped_nop& operator=(scoped_nop&& rhs)
|
||||
{ scoped_basic<bufsize_>::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
scoped_nop(memory_pointer_tr addr, size_t size = 1, bool vp = true)
|
||||
{ make_nop(addr, size, vp); }
|
||||
};
|
||||
|
||||
/*
|
||||
* RAII wrapper for MakeJMP
|
||||
*/
|
||||
class scoped_jmp : public scoped_basic<5>
|
||||
{
|
||||
public:
|
||||
// Makes NOP at @addr with value @value and size @size and virtual protect @vp
|
||||
memory_pointer_raw make_jmp(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
this->save(at, 5, vp);
|
||||
return MakeJMP(at, dest, vp);
|
||||
}
|
||||
|
||||
// Constructors, move constructors, assigment operators........
|
||||
scoped_jmp() = default;
|
||||
scoped_jmp(const scoped_jmp&) = delete;
|
||||
scoped_jmp(scoped_jmp&& rhs) : scoped_basic<5>(std::move(rhs)) {}
|
||||
scoped_jmp& operator=(const scoped_jmp& rhs) = delete;
|
||||
scoped_jmp& operator=(scoped_jmp&& rhs)
|
||||
{ scoped_basic<5>::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
scoped_jmp(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{ make_jmp(at, dest, vp); }
|
||||
};
|
||||
|
||||
/*
|
||||
* RAII wrapper for MakeCALL
|
||||
*/
|
||||
class scoped_call : public scoped_basic<5>
|
||||
{
|
||||
public:
|
||||
// Makes NOP at @addr with value @value and size @size and virtual protect @vp
|
||||
memory_pointer_raw make_call(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
this->save(at, 5, vp);
|
||||
return MakeCALL(at, dest, vp);
|
||||
}
|
||||
|
||||
// Constructors, move constructors, assigment operators........
|
||||
scoped_call() = default;
|
||||
scoped_call(const scoped_call&) = delete;
|
||||
scoped_call(scoped_call&& rhs) : scoped_basic<5>(std::move(rhs)) {}
|
||||
scoped_call& operator=(const scoped_call& rhs) = delete;
|
||||
scoped_call& operator=(scoped_call&& rhs)
|
||||
{ scoped_basic<5>::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
scoped_call(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{ make_call(at, dest, vp); }
|
||||
};
|
||||
|
||||
|
||||
#if __cplusplus >= 201103L || _MSC_VER >= 1800 // C++11 or MSVC 2013 required for variadic templates
|
||||
|
||||
/*
|
||||
* function_hooker_manager
|
||||
* Manages many function_hookers that points to the same address
|
||||
* The need for this function arises because otherwise we would only be able to allow one hook per address using function_hookers
|
||||
* This manager takes care of the amount of hooks placed in a particular address, calls the hooks and unhooks when necessary.
|
||||
*/
|
||||
template<class ToManage, class Ret, class ...Args>
|
||||
class function_hooker_manager : protected scoped_call
|
||||
{
|
||||
private:
|
||||
using func_type_raw = typename ToManage::func_type_raw;
|
||||
using func_type = typename ToManage::func_type;
|
||||
using functor_type = typename ToManage::functor_type;
|
||||
using assoc_type = std::list<std::pair<const ToManage*, functor_type>>;
|
||||
|
||||
// Only construction is allowed... by myself ofcourse...
|
||||
function_hooker_manager() = default;
|
||||
function_hooker_manager(const function_hooker_manager&) = delete;
|
||||
function_hooker_manager(function_hooker_manager&&) = delete;
|
||||
|
||||
//
|
||||
func_type_raw original; // Pointer to the original function we've replaced
|
||||
assoc_type assoc; // Association between owners of a hook and the hook (map)
|
||||
bool has_hooked = false; // Is the hook already in place?
|
||||
|
||||
// Find assoc iterator for the content owned by 'owned'
|
||||
typename assoc_type::iterator find_assoc(const ToManage& owner)
|
||||
{
|
||||
for(auto it = assoc.begin(); it != assoc.end(); ++it)
|
||||
if(it->first == &owner) return it;
|
||||
return assoc.end();
|
||||
}
|
||||
|
||||
// Adds a new item to the association map (or override if already in the map)
|
||||
void add(const ToManage& hooker, functor_type functor)
|
||||
{
|
||||
auto it = find_assoc(hooker);
|
||||
if(it != assoc.end())
|
||||
it->second = std::move(functor);
|
||||
else
|
||||
assoc.emplace_back(&hooker, std::move(functor));
|
||||
}
|
||||
|
||||
public:
|
||||
// Forwards the call to all the installed hooks
|
||||
static Ret call_hooks(Args&... args)
|
||||
{
|
||||
auto& manager = *instance();
|
||||
|
||||
if(manager.assoc.size() == 0) // This may be uncommon but may happen (?), no hook installed
|
||||
return manager.original(args...);
|
||||
|
||||
// Functor for the original call
|
||||
func_type original = [&manager](Args... args) -> Ret {
|
||||
return manager.original(args...);
|
||||
};
|
||||
|
||||
if(manager.assoc.size() == 1)
|
||||
{
|
||||
// We have only one hook, just use it directly no need to go further in complexity
|
||||
auto& functor = manager.assoc.begin()->second;
|
||||
return functor(std::move(original), args...);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Build a serie of functors which captures the previous functor sending it to the next functor,
|
||||
// that's what would happen if the hooks took place independent of the template staticness (AAAAAAA)
|
||||
func_type next = std::move(original);
|
||||
for(auto it = manager.assoc.begin(); it != manager.assoc.end(); ++it)
|
||||
{
|
||||
auto& functor = it->second;
|
||||
next = [functor, next](Args... args) -> Ret
|
||||
{
|
||||
return functor(next, args...);
|
||||
};
|
||||
}
|
||||
return next(args...);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Installs a hook associated with the function_hooker 'hooker' which would call the specified 'functor'
|
||||
// We need an auxiliar function pointer 'ptr' (to abstract calling conventions) which should forward itself to ^call_hooks
|
||||
void make_call(const ToManage& hooker, functor_type functor, memory_pointer_raw ptr)
|
||||
{
|
||||
this->add(hooker, std::move(functor));
|
||||
|
||||
// Make sure we only hook this address for the manager once
|
||||
if(!this->has_hooked)
|
||||
{
|
||||
// (the following cast is needed for __thiscall functions)
|
||||
this->original = (func_type_raw) (void*) scoped_call::make_call(hooker.addr, ptr).get();
|
||||
this->has_hooked = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Restores the state of the call we've replaced in the game code
|
||||
// All installed hooks gets uninstalled after this
|
||||
void restore()
|
||||
{
|
||||
if(this->has_hooked)
|
||||
{
|
||||
this->has_hooked = false;
|
||||
this->assoc.clear();
|
||||
return scoped_call::restore();
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces the hook associated with 'from' to be associated with 'to'
|
||||
// After this call the 'from' object has no association in this manager
|
||||
void replace(const ToManage& from, const ToManage& to)
|
||||
{
|
||||
auto it = find_assoc(from);
|
||||
if(it != assoc.end())
|
||||
{
|
||||
auto functor = std::move(it->second);
|
||||
assoc.erase(it);
|
||||
this->add(to, std::move(functor));
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the hook associated with the specified 'hooker'
|
||||
// If the number of hooks reaches zero after the remotion, a restore will take place
|
||||
void remove(const ToManage& hooker)
|
||||
{
|
||||
auto it = find_assoc(hooker);
|
||||
if(it != assoc.end())
|
||||
{
|
||||
assoc.erase(it);
|
||||
if(assoc.size() == 0) this->restore();
|
||||
}
|
||||
}
|
||||
|
||||
// The instance of this specific manager
|
||||
// This work as a shared pointer to avoid the static destruction of the manager even when a static function_hooker
|
||||
// still wants to use it.
|
||||
static std::shared_ptr<function_hooker_manager> instance()
|
||||
{
|
||||
static auto fm_ptr = std::shared_ptr<function_hooker_manager>(new function_hooker_manager());
|
||||
return fm_ptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* function_hooker_base
|
||||
* Base for any function_hooker, this class manages the relationship with the function hooker manager
|
||||
*/
|
||||
template<uintptr_t addr1, class FuncType, class Ret, class ...Args>
|
||||
class function_hooker_base : public scoped_base
|
||||
{
|
||||
public:
|
||||
static const uintptr_t addr = addr1;
|
||||
|
||||
using func_type_raw = FuncType;
|
||||
using func_type = std::function<Ret(Args...)>;
|
||||
using functor_type = std::function<Ret(func_type, Args&...)>;
|
||||
using manager_type = function_hooker_manager<function_hooker_base, Ret, Args...>;
|
||||
|
||||
public:
|
||||
// Constructors, move constructors, assigment operators........
|
||||
function_hooker_base(const function_hooker_base&) = delete;
|
||||
function_hooker_base& operator=(const function_hooker_base& rhs) = delete;
|
||||
|
||||
function_hooker_base() : manager(manager_type::instance())
|
||||
{}
|
||||
|
||||
//
|
||||
virtual ~function_hooker_base()
|
||||
{
|
||||
this->restore();
|
||||
}
|
||||
|
||||
// The move constructor should do a replace in the manager
|
||||
function_hooker_base(function_hooker_base&& rhs)
|
||||
: scoped_base(std::move(rhs)), has_call(rhs.has_call),
|
||||
manager(rhs.manager) // (don't move the manager!, every function_hooker should own one)
|
||||
{
|
||||
manager->replace(rhs, *this);
|
||||
}
|
||||
|
||||
// The move assignment operator should also do a replace in the manager
|
||||
function_hooker_base& operator=(function_hooker_base&& rhs)
|
||||
{
|
||||
scoped_base::operator=(std::move(rhs));
|
||||
manager->replace(rhs, *this);
|
||||
this->has_call = rhs.has_call;
|
||||
this->manager = rhs.manager; // (don't move the manager! every function_hooker should own one)
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Deriveds should implement a proper make_call (yeah it's virtual so derived-deriveds can do some fest)
|
||||
virtual void make_call(functor_type functor) = 0;
|
||||
|
||||
// Restores the state of the call we've replaced in the game code
|
||||
virtual void restore()
|
||||
{
|
||||
this->has_call = false;
|
||||
manager->remove(*this);
|
||||
}
|
||||
|
||||
// Checkers whether a hook is installed
|
||||
bool has_hooked()
|
||||
{
|
||||
return this->has_call;
|
||||
}
|
||||
|
||||
private:
|
||||
bool has_call = false; // Has a hook installed?
|
||||
std::shared_ptr<manager_type> manager; // **EVERY** function_hooker should have a ownership over it's manager_type
|
||||
// this prevents the static destruction of the manager_type while it may be still needed.
|
||||
|
||||
protected: // Forwarders to the function hooker manager
|
||||
|
||||
void make_call(functor_type functor, memory_pointer_raw ptr)
|
||||
{
|
||||
this->has_call = true;
|
||||
manager->make_call(*this, std::move(functor), ptr);
|
||||
}
|
||||
|
||||
static Ret call_hooks(Args&... a)
|
||||
{
|
||||
return manager_type::call_hooks(a...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* function_hooker
|
||||
* For standard conventions (usually __cdecl)
|
||||
*/
|
||||
template<uintptr_t addr1, class Prototype>
|
||||
struct function_hooker;
|
||||
|
||||
template<uintptr_t addr1, class Ret, class ...Args>
|
||||
class function_hooker<addr1, Ret(Args...)>
|
||||
: public function_hooker_base<addr1, Ret(*)(Args...), Ret, Args...>
|
||||
{
|
||||
private:
|
||||
using base = function_hooker_base<addr1, Ret(*)(Args...), Ret, Args...>;
|
||||
|
||||
// The hook caller
|
||||
static Ret call(Args... a)
|
||||
{
|
||||
return base::call_hooks(a...);
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors, move constructors, assigment operators........
|
||||
function_hooker() = default;
|
||||
function_hooker(const function_hooker&) = delete;
|
||||
function_hooker(function_hooker&& rhs) : base(std::move(rhs)) {}
|
||||
function_hooker& operator=(const function_hooker& rhs) = delete;
|
||||
function_hooker& operator=(function_hooker&& rhs)
|
||||
{ base::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
// Makes the hook
|
||||
void make_call(typename base::functor_type functor)
|
||||
{
|
||||
return base::make_call(std::move(functor), raw_ptr(call));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* function_hooker_stdcall
|
||||
* For stdcall conventions (__stdcall)
|
||||
*/
|
||||
template<uintptr_t addr1, class Prototype>
|
||||
struct function_hooker_stdcall;
|
||||
|
||||
template<uintptr_t addr1, class Ret, class ...Args>
|
||||
struct function_hooker_stdcall<addr1, Ret(Args...)>
|
||||
: public function_hooker_base<addr1, Ret(__stdcall*)(Args...), Ret, Args...>
|
||||
{
|
||||
private:
|
||||
using base = function_hooker_base<addr1, Ret(__stdcall*)(Args...), Ret, Args...>;
|
||||
|
||||
// The hook caller
|
||||
static Ret __stdcall call(Args... a)
|
||||
{
|
||||
return base::call_hooks(a...);
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors, move constructors, assigment operators........
|
||||
function_hooker_stdcall() = default;
|
||||
function_hooker_stdcall(const function_hooker_stdcall&) = delete;
|
||||
function_hooker_stdcall(function_hooker_stdcall&& rhs) : base(std::move(rhs)) {}
|
||||
function_hooker_stdcall& operator=(const function_hooker_stdcall& rhs) = delete;
|
||||
function_hooker_stdcall& operator=(function_hooker_stdcall&& rhs)
|
||||
{ base::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
// Makes the hook
|
||||
void make_call(typename base::functor_type functor)
|
||||
{
|
||||
return base::make_call(std::move(functor), raw_ptr(call));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* function_hooker_fastcall
|
||||
* For fastcall conventions (__fastcall)
|
||||
*/
|
||||
template<uintptr_t addr1, class Prototype>
|
||||
struct function_hooker_fastcall;
|
||||
|
||||
template<uintptr_t addr1, class Ret, class ...Args>
|
||||
struct function_hooker_fastcall<addr1, Ret(Args...)>
|
||||
: public function_hooker_base<addr1, Ret(__fastcall*)(Args...), Ret, Args...>
|
||||
{
|
||||
private:
|
||||
using base = function_hooker_base<addr1, Ret(__fastcall*)(Args...), Ret, Args...>;
|
||||
|
||||
// The hook caller
|
||||
static Ret __fastcall call(Args... a)
|
||||
{
|
||||
return base::call_hooks(a...);
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors, move constructors, assigment operators........
|
||||
function_hooker_fastcall() = default;
|
||||
function_hooker_fastcall(const function_hooker_fastcall&) = delete;
|
||||
function_hooker_fastcall(function_hooker_fastcall&& rhs) : base(std::move(rhs)) {}
|
||||
function_hooker_fastcall& operator=(const function_hooker_fastcall& rhs) = delete;
|
||||
function_hooker_fastcall& operator=(function_hooker_fastcall&& rhs)
|
||||
{ base::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
// Makes the hook
|
||||
void make_call(typename base::functor_type functor)
|
||||
{
|
||||
return base::make_call(std::move(functor), raw_ptr(call));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* function_hooker_thiscall
|
||||
* For thiscall conventions (__thiscall, class methods)
|
||||
*/
|
||||
template<uintptr_t addr1, class Prototype>
|
||||
struct function_hooker_thiscall;
|
||||
|
||||
template<uintptr_t addr1, class Ret, class ...Args>
|
||||
struct function_hooker_thiscall<addr1, Ret(Args...)>
|
||||
: public function_hooker_base<addr1, Ret(__thiscall*)(Args...), Ret, Args...>
|
||||
{
|
||||
private:
|
||||
using base = function_hooker_base<addr1, Ret(__thiscall*)(Args...), Ret, Args...>;
|
||||
|
||||
// The hook caller
|
||||
static Ret __thiscall call(Args... a)
|
||||
{
|
||||
return base::call_hooks(a...);
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors, move constructors, assigment operators........
|
||||
function_hooker_thiscall() = default;
|
||||
function_hooker_thiscall(const function_hooker_thiscall&) = delete;
|
||||
function_hooker_thiscall(function_hooker_thiscall&& rhs) : base(std::move(rhs)) {}
|
||||
function_hooker_thiscall& operator=(const function_hooker_thiscall& rhs) = delete;
|
||||
function_hooker_thiscall& operator=(function_hooker_thiscall&& rhs)
|
||||
{ base::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
// Makes the hook
|
||||
void make_call(typename base::functor_type functor)
|
||||
{
|
||||
return base::make_call(std::move(functor), raw_ptr(call));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************* HELPERS ******************/
|
||||
|
||||
/*
|
||||
* Adds a hook to be alive for the entire program lifetime
|
||||
* That means the hook received will be alive until the program dies.
|
||||
* Note: Parameter must be a rvalue
|
||||
*/
|
||||
template<class T> inline
|
||||
T& add_static_hook(T&& hooker)
|
||||
{
|
||||
static std::list<T> a;
|
||||
return *a.emplace(a.end(), std::move(hooker));
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes a hook which is alive until it gets out of scope
|
||||
* 'T' must be any function_hooker object
|
||||
*/
|
||||
template<class T, class F> inline
|
||||
T make_function_hook(F functor)
|
||||
{
|
||||
T a;
|
||||
a.make_call(std::move(functor));
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes a hook which is alive for the entire lifetime of this program
|
||||
* 'T' must be any function_hooker object
|
||||
*/
|
||||
template<class T, class F> inline
|
||||
T& make_static_hook(F functor)
|
||||
{
|
||||
return add_static_hook(make_function_hook<T>(std::move(functor)));
|
||||
}
|
||||
|
||||
|
||||
// TODO when we have access to C++14 add a make_function_hook, make_stdcall_function_hook, and so on
|
||||
// the problem behind implement it with C++11 is that lambdas cannot be generic and the first param of a hook is a functor pointing
|
||||
// to the previous call pointer
|
||||
|
||||
#endif
|
||||
|
||||
}
|
661
depthrush/kiero/injector/injector.hpp
Normal file
661
depthrush/kiero/injector/injector.hpp
Normal file
@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Injectors - Base Header
|
||||
*
|
||||
* Copyright (C) 2012-2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#define INJECTOR_HAS_INJECTOR_HPP
|
||||
#include <windows.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include "gvm/gvm.hpp"
|
||||
/*
|
||||
The following macros (#define) are relevant on this header:
|
||||
|
||||
INJECTOR_GVM_HAS_TRANSLATOR
|
||||
If defined, the user should provide their own address_manager::translator function.
|
||||
That function is responssible for translating a void pointer (that mayn't be an actual pointer) into an actual address.
|
||||
The meaning of that void pointer will be made by YOU when you send it to the functions that receive pointers on this library.
|
||||
The default translator does nothing but returns that void pointer as the address.
|
||||
|
||||
INJECTOR_GVM_OWN_DETECT
|
||||
If defined, the user should provide it's own game detection function thought game_version_manager::Detect
|
||||
By default it provide an good detection for the Grand Theft Auto series.
|
||||
|
||||
INJECTOR_GVM_PLUGIN_NAME
|
||||
If this is defined, it will be used as the plugin name used at error messages.
|
||||
By default it will use ""Unknown Plugin Name"
|
||||
|
||||
INJECTOR_GVM_DUMMY
|
||||
If defined, the game_version_manager will be a dummy object
|
||||
By default it provides a nice gvm for Grand Theft Auto series
|
||||
|
||||
INJECTOR_OWN_GVM
|
||||
If defined, the game_version_manager should be implemented by the user before including this library.
|
||||
By default it provides a nice gvm for Grand Theft Auto series
|
||||
*/
|
||||
#include "gvm/gvm.hpp"
|
||||
|
||||
|
||||
|
||||
namespace injector
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* auto_pointer
|
||||
* Casts itself to another pointer type in the lhs
|
||||
*/
|
||||
union auto_pointer
|
||||
{
|
||||
protected:
|
||||
friend union memory_pointer_tr;
|
||||
template<class T> friend union basic_memory_pointer;
|
||||
|
||||
void* p;
|
||||
uintptr_t a;
|
||||
|
||||
public:
|
||||
auto_pointer() : p(0) {}
|
||||
auto_pointer(const auto_pointer& x) : p(x.p) {}
|
||||
explicit auto_pointer(void* x) : p(x) {}
|
||||
explicit auto_pointer(uint32_t x) : a(x) {}
|
||||
|
||||
bool is_null() const { return this->p != nullptr; }
|
||||
|
||||
#if __cplusplus >= 201103L || _MSC_VER >= 1800
|
||||
explicit operator bool() const { return is_null(); }
|
||||
#endif
|
||||
|
||||
auto_pointer get() const { return *this; }
|
||||
template<class T> T* get() const { return (T*) this->p; }
|
||||
template<class T> T* get_raw() const { return (T*) this->p; }
|
||||
|
||||
template<class T>
|
||||
operator T*() const { return reinterpret_cast<T*>(p); }
|
||||
};
|
||||
|
||||
/*
|
||||
* basic_memory_pointer
|
||||
* A memory pointer class that is capable of many operations, including address translation
|
||||
* MemTranslator is the translator functor
|
||||
*/
|
||||
template<class MemTranslator>
|
||||
union basic_memory_pointer
|
||||
{
|
||||
protected:
|
||||
void* p;
|
||||
uintptr_t a;
|
||||
|
||||
// Translates address p to the running executable pointer
|
||||
static auto_pointer memory_translate(void* p)
|
||||
{
|
||||
return auto_pointer(MemTranslator()(p));
|
||||
}
|
||||
|
||||
public:
|
||||
basic_memory_pointer() : p(nullptr) {}
|
||||
basic_memory_pointer(std::nullptr_t) : p(nullptr) {}
|
||||
basic_memory_pointer(uintptr_t x) : a(x) {}
|
||||
basic_memory_pointer(const auto_pointer& x) : p(x.p) {}
|
||||
basic_memory_pointer(const basic_memory_pointer& rhs) : p(rhs.p) {}
|
||||
|
||||
template<class T>
|
||||
basic_memory_pointer(T* x) : p((void*)x) {}
|
||||
|
||||
|
||||
|
||||
|
||||
// Gets the translated pointer (plus automatic casting to lhs)
|
||||
auto_pointer get() const { return memory_translate(p); }
|
||||
|
||||
// Gets the translated pointer (casted to T*)
|
||||
template<class T> T* get() const { return get(); }
|
||||
|
||||
// Gets the raw pointer, without translation (casted to T*)
|
||||
template<class T> T* get_raw() const { return auto_pointer(p); }
|
||||
|
||||
// This type can get assigned from void* and uintptr_t
|
||||
basic_memory_pointer& operator=(void* x) { return p = x, *this; }
|
||||
basic_memory_pointer& operator=(uintptr_t x) { return a = x, *this; }
|
||||
|
||||
/* Arithmetic */
|
||||
basic_memory_pointer operator+(const basic_memory_pointer& rhs) const
|
||||
{ return basic_memory_pointer(this->a + rhs.a); }
|
||||
|
||||
basic_memory_pointer operator-(const basic_memory_pointer& rhs) const
|
||||
{ return basic_memory_pointer(this->a - rhs.a); }
|
||||
|
||||
basic_memory_pointer operator*(const basic_memory_pointer& rhs) const
|
||||
{ return basic_memory_pointer(this->a * rhs.a); }
|
||||
|
||||
basic_memory_pointer operator/(const basic_memory_pointer& rhs) const
|
||||
{ return basic_memory_pointer(this->a / rhs.a); }
|
||||
|
||||
|
||||
/* Comparision */
|
||||
bool operator==(const basic_memory_pointer& rhs) const
|
||||
{ return this->a == rhs.a; }
|
||||
|
||||
bool operator!=(const basic_memory_pointer& rhs) const
|
||||
{ return this->a != rhs.a; }
|
||||
|
||||
bool operator<(const basic_memory_pointer& rhs) const
|
||||
{ return this->a < rhs.a; }
|
||||
|
||||
bool operator<=(const basic_memory_pointer& rhs) const
|
||||
{ return this->a <= rhs.a; }
|
||||
|
||||
bool operator>(const basic_memory_pointer& rhs) const
|
||||
{ return this->a > rhs.a; }
|
||||
|
||||
bool operator>=(const basic_memory_pointer& rhs) const
|
||||
{ return this->a >=rhs.a; }
|
||||
|
||||
bool is_null() const { return this->p == nullptr; }
|
||||
uintptr_t as_int() const { return this->a; } // does not perform translation
|
||||
|
||||
|
||||
|
||||
#if __cplusplus >= 201103L || _MSC_VER >= 1800 // MSVC 2013
|
||||
/* Conversion to other types */
|
||||
explicit operator uintptr_t() const
|
||||
{ return this->a; } // does not perform translation
|
||||
explicit operator bool() const
|
||||
{ return this->p != nullptr; }
|
||||
#else
|
||||
//operator bool() -------------- Causes casting problems because of implicitness, use !is_null()
|
||||
//{ return this->p != nullptr; }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
// Typedefs including memory translator for the above type
|
||||
typedef basic_memory_pointer<address_manager::fn_mem_translator> memory_pointer;
|
||||
typedef basic_memory_pointer<address_manager::fn_mem_translator_nop> memory_pointer_raw;
|
||||
typedef basic_memory_pointer<address_manager::fn_mem_translator_aslr> memory_pointer_aslr;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* memory_pointer_tr
|
||||
* Stores a basic_memory_pointer<Tr> as a raw pointer from translated pointer
|
||||
*/
|
||||
union memory_pointer_tr
|
||||
{
|
||||
protected:
|
||||
void* p;
|
||||
uintptr_t a;
|
||||
|
||||
public:
|
||||
template<class Tr>
|
||||
memory_pointer_tr(const basic_memory_pointer<Tr>& ptr)
|
||||
: p(ptr.get())
|
||||
{} // Constructs from a basic_memory_pointer
|
||||
|
||||
memory_pointer_tr(const auto_pointer& ptr)
|
||||
: p(ptr.p)
|
||||
{} // Constructs from a auto_pointer, probably comming from basic_memory_pointer::get
|
||||
|
||||
memory_pointer_tr(const memory_pointer_tr& rhs)
|
||||
: p(rhs.p)
|
||||
{} // Constructs from my own type, copy constructor
|
||||
|
||||
memory_pointer_tr(uintptr_t x)
|
||||
: p(memory_pointer(x).get())
|
||||
{} // Constructs from a integer, translating the address
|
||||
|
||||
memory_pointer_tr(void* x)
|
||||
: p(memory_pointer(x).get())
|
||||
{} // Constructs from a void pointer, translating the address
|
||||
|
||||
// Just to be method-compatible with basic_memory_pointer ...
|
||||
auto_pointer get() { return auto_pointer(p); }
|
||||
template<class T> T* get() { return get(); }
|
||||
template<class T> T* get_raw() { return get(); }
|
||||
|
||||
memory_pointer_tr operator+(const uintptr_t& rhs) const
|
||||
{ return memory_pointer_raw(this->a + rhs); }
|
||||
|
||||
memory_pointer_tr operator-(const uintptr_t& rhs) const
|
||||
{ return memory_pointer_raw(this->a - rhs); }
|
||||
|
||||
memory_pointer_tr operator*(const uintptr_t& rhs) const
|
||||
{ return memory_pointer_raw(this->a * rhs); }
|
||||
|
||||
memory_pointer_tr operator/(const uintptr_t& rhs) const
|
||||
{ return memory_pointer_raw(this->a / rhs); }
|
||||
|
||||
bool is_null() const { return this->p == nullptr; }
|
||||
uintptr_t as_int() const { return this->a; }
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
explicit operator uintptr_t() const
|
||||
{ return this->a; }
|
||||
#else
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ProtectMemory
|
||||
* Makes the address @addr have a protection of @protection
|
||||
*/
|
||||
inline bool ProtectMemory(memory_pointer_tr addr, size_t size, DWORD protection)
|
||||
{
|
||||
return VirtualProtect(addr.get(), size, protection, &protection) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* UnprotectMemory
|
||||
* Unprotect the memory at @addr with size @size so it have all accesses (execute, read and write)
|
||||
* Returns the old protection to out_oldprotect
|
||||
*/
|
||||
inline bool UnprotectMemory(memory_pointer_tr addr, size_t size, DWORD& out_oldprotect)
|
||||
{
|
||||
return VirtualProtect(addr.get(), size, PAGE_EXECUTE_READWRITE, &out_oldprotect) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scoped_unprotect
|
||||
* RAII wrapper for UnprotectMemory
|
||||
* On construction unprotects the memory, on destruction reprotects the memory
|
||||
*/
|
||||
struct scoped_unprotect
|
||||
{
|
||||
memory_pointer_raw addr;
|
||||
size_t size;
|
||||
DWORD dwOldProtect;
|
||||
bool bUnprotected;
|
||||
|
||||
scoped_unprotect(memory_pointer_tr addr, size_t size)
|
||||
{
|
||||
if(size == 0) bUnprotected = false;
|
||||
else bUnprotected = UnprotectMemory(this->addr = addr.get<void>(), this->size = size, dwOldProtect);
|
||||
}
|
||||
|
||||
~scoped_unprotect()
|
||||
{
|
||||
if(bUnprotected) ProtectMemory(this->addr.get(), this->size, this->dwOldProtect);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* WriteMemoryRaw
|
||||
* Writes into memory @addr the content of @value with a sizeof @size
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
inline void WriteMemoryRaw(memory_pointer_tr addr, void* value, size_t size, bool vp)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? size : 0);
|
||||
memcpy(addr.get(), value, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* ReadMemoryRaw
|
||||
* Reads the memory at @addr with a sizeof @size into address @ret
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
inline void ReadMemoryRaw(memory_pointer_tr addr, void* ret, size_t size, bool vp)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? size : 0);
|
||||
memcpy(ret, addr.get(), size);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryFill
|
||||
* Fills the memory at @addr with the byte @value doing it @size times
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
inline void MemoryFill(memory_pointer_tr addr, uint8_t value, size_t size, bool vp)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? size : 0);
|
||||
memset(addr.get(), value, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* WriteObject
|
||||
* Assigns the object @value into the same object type at @addr
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
template<class T>
|
||||
inline T& WriteObject(memory_pointer_tr addr, const T& value, bool vp = false)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? sizeof(value) : 0);
|
||||
return (*addr.get<T>() = value);
|
||||
}
|
||||
|
||||
/*
|
||||
* ReadObject
|
||||
* Assigns the object @value with the value of the same object type at @addr
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
template<class T>
|
||||
inline T& ReadObject(memory_pointer_tr addr, T& value, bool vp = false)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? sizeof(value) : 0);
|
||||
return (value = *addr.get<T>());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* WriteMemory
|
||||
* Writes the object of type T into the address @addr
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
template<class T>
|
||||
inline void WriteMemory(memory_pointer_tr addr, T value, bool vp = false)
|
||||
{
|
||||
WriteObject(addr, value, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* ReadMemory
|
||||
* Reads the object type T at address @addr
|
||||
* Does memory unprotection if @vp is true
|
||||
*/
|
||||
template<class T>
|
||||
inline T ReadMemory(memory_pointer_tr addr, bool vp = false)
|
||||
{
|
||||
T value;
|
||||
return ReadObject(addr, value, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* AdjustPointer
|
||||
* Searches in the range [@addr, @addr + @max_search] for a pointer in the range [@default_base, @default_end] and replaces
|
||||
* it with the proper offset in the pointer @replacement_base.
|
||||
* Does memory unprotection if @vp is true.
|
||||
*/
|
||||
inline memory_pointer_raw AdjustPointer(memory_pointer_tr addr,
|
||||
memory_pointer_raw replacement_base, memory_pointer_tr default_base, memory_pointer_tr default_end,
|
||||
size_t max_search = 8, bool vp = true)
|
||||
{
|
||||
scoped_unprotect xprotect(addr, vp? max_search + sizeof(void*) : 0);
|
||||
for(size_t i = 0; i < max_search; ++i)
|
||||
{
|
||||
memory_pointer_raw ptr = ReadMemory<void*>(addr + i);
|
||||
if(ptr >= default_base.get() && ptr <= default_end.get())
|
||||
{
|
||||
auto result = replacement_base + (ptr - default_base.get());
|
||||
WriteMemory<void*>(addr + i, result.get());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GetAbsoluteOffset
|
||||
* Gets absolute address based on relative offset @rel_value from instruction that ends at @end_of_instruction
|
||||
*/
|
||||
inline memory_pointer_raw GetAbsoluteOffset(int rel_value, memory_pointer_tr end_of_instruction)
|
||||
{
|
||||
return end_of_instruction.get<char>() + rel_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* GetRelativeOffset
|
||||
* Gets relative offset based on absolute address @abs_value for instruction that ends at @end_of_instruction
|
||||
*/
|
||||
inline int GetRelativeOffset(memory_pointer_tr abs_value, memory_pointer_tr end_of_instruction)
|
||||
{
|
||||
return uintptr_t(abs_value.get<char>() - end_of_instruction.get<char>());
|
||||
}
|
||||
|
||||
/*
|
||||
* ReadRelativeOffset
|
||||
* Reads relative offset from address @at
|
||||
*/
|
||||
inline memory_pointer_raw ReadRelativeOffset(memory_pointer_tr at, size_t sizeof_addr = 4, bool vp = true)
|
||||
{
|
||||
switch(sizeof_addr)
|
||||
{
|
||||
case 1: return (GetAbsoluteOffset(ReadMemory<int8_t> (at, vp), at+sizeof_addr));
|
||||
case 2: return (GetAbsoluteOffset(ReadMemory<int16_t>(at, vp), at+sizeof_addr));
|
||||
case 4: return (GetAbsoluteOffset(ReadMemory<int32_t>(at, vp), at+sizeof_addr));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeRelativeOffset
|
||||
* Writes relative offset into @at based on absolute destination @dest
|
||||
*/
|
||||
inline void MakeRelativeOffset(memory_pointer_tr at, memory_pointer_tr dest, size_t sizeof_addr = 4, bool vp = true)
|
||||
{
|
||||
switch(sizeof_addr)
|
||||
{
|
||||
case 1: WriteMemory<int8_t> (at, static_cast<int8_t> (GetRelativeOffset(dest, at+sizeof_addr)), vp);
|
||||
case 2: WriteMemory<int16_t>(at, static_cast<int16_t>(GetRelativeOffset(dest, at+sizeof_addr)), vp);
|
||||
case 4: WriteMemory<int32_t>(at, static_cast<int32_t>(GetRelativeOffset(dest, at+sizeof_addr)), vp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GetBranchDestination
|
||||
* Gets the destination of a branch instruction at address @at
|
||||
* *** Works only with JMP and CALL for now ***
|
||||
*/
|
||||
inline memory_pointer_raw GetBranchDestination(memory_pointer_tr at, bool vp = true)
|
||||
{
|
||||
switch(ReadMemory<uint8_t>(at, vp))
|
||||
{
|
||||
// We need to handle other instructions (and prefixes) later...
|
||||
case 0xE8: // call rel
|
||||
case 0xE9: // jmp rel
|
||||
return ReadRelativeOffset(at + 1, 4, vp);
|
||||
|
||||
case 0xFF:
|
||||
switch(ReadMemory<uint8_t>(at + 1, vp))
|
||||
{
|
||||
case 0x15: // call dword ptr [addr]
|
||||
case 0x25: // jmp dword ptr [addr]
|
||||
return *(ReadMemory<uintptr_t*>(at + 2, vp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeJMP
|
||||
* Creates a JMP instruction at address @at that jumps into address @dest
|
||||
* If there was already a branch instruction there, returns the previosly destination of the branch
|
||||
*/
|
||||
inline memory_pointer_raw MakeJMP(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
auto p = GetBranchDestination(at, vp);
|
||||
WriteMemory<uint8_t>(at, 0xE9, vp);
|
||||
MakeRelativeOffset(at+1, dest, 4, vp);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeCALL
|
||||
* Creates a CALL instruction at address @at that jumps into address @dest
|
||||
* If there was already a branch instruction there, returns the previosly destination of the branch
|
||||
*/
|
||||
inline memory_pointer_raw MakeCALL(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
auto p = GetBranchDestination(at, vp);
|
||||
WriteMemory<uint8_t>(at, 0xE8, vp);
|
||||
MakeRelativeOffset(at+1, dest, 4, vp);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeJA
|
||||
* Creates a JA instruction at address @at that jumps if above into address @dest
|
||||
* If there was already a branch instruction there, returns the previosly destination of the branch
|
||||
*/
|
||||
inline void MakeJA(memory_pointer_tr at, memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
WriteMemory<uint16_t>(at, 0x87F0, vp);
|
||||
MakeRelativeOffset(at+2, dest, 4, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeNOP
|
||||
* Creates a bunch of NOP instructions at address @at
|
||||
*/
|
||||
inline void MakeNOP(memory_pointer_tr at, size_t count = 1, bool vp = true)
|
||||
{
|
||||
MemoryFill(at, 0x90, count, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* MakeRangedNOP
|
||||
* Creates a bunch of NOP instructions at address @at until address @until
|
||||
*/
|
||||
inline void MakeRangedNOP(memory_pointer_tr at, memory_pointer_tr until, bool vp = true)
|
||||
{
|
||||
return MakeNOP(at, size_t(until.get_raw<char>() - at.get_raw<char>()), vp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MakeRET
|
||||
* Creates a RET instruction at address @at popping @pop values from the stack
|
||||
* If @pop is equal to 0 it will use the 1 byte form of the instruction
|
||||
*/
|
||||
inline void MakeRET(memory_pointer_tr at, uint16_t pop = 0, bool vp = true)
|
||||
{
|
||||
WriteMemory(at, pop? 0xC2 : 0xC3, vp);
|
||||
if(pop) WriteMemory(at+1, pop, vp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* lazy_pointer
|
||||
* Lazy pointer, where it's final value will get evaluated only once when finally needed.
|
||||
*/
|
||||
template<uintptr_t addr>
|
||||
struct lazy_pointer
|
||||
{
|
||||
public:
|
||||
// Returns the final raw pointer
|
||||
static auto_pointer get()
|
||||
{
|
||||
return xget().get();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static T* get()
|
||||
{
|
||||
return get().get<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns the final pointer
|
||||
static memory_pointer_raw xget()
|
||||
{
|
||||
static void* ptr = nullptr;
|
||||
if(!ptr) ptr = memory_pointer(addr).get();
|
||||
return memory_pointer_raw(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* lazy_object
|
||||
* Lazy object, where it's final object will get evaluated only once when finally needed.
|
||||
*/
|
||||
template<uintptr_t addr, class T>
|
||||
struct lazy_object
|
||||
{
|
||||
static T& get()
|
||||
{
|
||||
static T data;
|
||||
static bool has_data = false;
|
||||
if(!has_data)
|
||||
{
|
||||
ReadObject<T>(addr, data, true);
|
||||
has_data = true;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Helpers
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
inline memory_pointer mem_ptr(T p)
|
||||
{
|
||||
return memory_pointer(p);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline memory_pointer_raw raw_ptr(T p)
|
||||
{
|
||||
return memory_pointer_raw(p);
|
||||
}
|
||||
|
||||
template<class Tr>
|
||||
inline memory_pointer_raw raw_ptr(basic_memory_pointer<Tr> p)
|
||||
{
|
||||
return raw_ptr(p.get());
|
||||
}
|
||||
|
||||
template<uintptr_t addr>
|
||||
inline memory_pointer_raw lazy_ptr()
|
||||
{
|
||||
return lazy_pointer<addr>::get();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline memory_pointer_aslr aslr_ptr(T p)
|
||||
{
|
||||
return memory_pointer_aslr(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
56
depthrush/kiero/injector/utility.hpp
Normal file
56
depthrush/kiero/injector/utility.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Injectors - Utility / Helpers
|
||||
*
|
||||
* Copyright (C) 2014 LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace injector
|
||||
{
|
||||
template<class T, T value>
|
||||
T return_value()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void* force_ptr(const T& fun)
|
||||
{
|
||||
auto ptr = fun;
|
||||
return *(void**)&ptr;
|
||||
}
|
||||
|
||||
|
||||
// Helper structure to help calling back what was there before a hook
|
||||
// e.g. hb.fun = MakeCALL(0x0, raw_ptr(my_hook));
|
||||
template<class FuncType>
|
||||
struct hook_back
|
||||
{
|
||||
typedef FuncType func_type;
|
||||
|
||||
func_type fun;
|
||||
|
||||
hook_back() : fun(nullptr)
|
||||
{}
|
||||
};
|
||||
};
|
720
depthrush/kiero/kiero.cpp
Normal file
720
depthrush/kiero/kiero.cpp
Normal file
@ -0,0 +1,720 @@
|
||||
#include "kiero.h"
|
||||
#include <Windows.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if KIERO_INCLUDE_D3D9
|
||||
# include <d3d9.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_INCLUDE_D3D10
|
||||
# include <dxgi.h>
|
||||
# include <d3d10_1.h>
|
||||
# include <d3d10.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_INCLUDE_D3D11
|
||||
# include <dxgi.h>
|
||||
# include <d3d11.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_INCLUDE_D3D12
|
||||
# include <dxgi.h>
|
||||
# include <d3d12.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_INCLUDE_OPENGL
|
||||
# include <gl/GL.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_INCLUDE_VULKAN
|
||||
# include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
# include "minhook/include/MinHook.h"
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
# define KIERO_TEXT(text) L##text
|
||||
#else
|
||||
# define KIERO_TEXT(text) text
|
||||
#endif
|
||||
|
||||
#define KIERO_ARRAY_SIZE(arr) ((size_t)(sizeof(arr)/sizeof(arr[0])))
|
||||
|
||||
static kiero::RenderType::Enum g_renderType = kiero::RenderType::None;
|
||||
static uint150_t* g_methodsTable = NULL;
|
||||
|
||||
kiero::Status::Enum kiero::init(RenderType::Enum _renderType)
|
||||
{
|
||||
if (g_renderType != RenderType::None)
|
||||
{
|
||||
return Status::AlreadyInitializedError;
|
||||
}
|
||||
|
||||
if (_renderType != RenderType::None)
|
||||
{
|
||||
if (_renderType >= RenderType::D3D9 && _renderType <= RenderType::D3D12)
|
||||
{
|
||||
WNDCLASSEX windowClass;
|
||||
windowClass.cbSize = sizeof(WNDCLASSEX);
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
windowClass.lpfnWndProc = DefWindowProc;
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hInstance = GetModuleHandle(NULL);
|
||||
windowClass.hIcon = NULL;
|
||||
windowClass.hCursor = NULL;
|
||||
windowClass.hbrBackground = NULL;
|
||||
windowClass.lpszMenuName = NULL;
|
||||
windowClass.lpszClassName = KIERO_TEXT("Kiero");
|
||||
windowClass.hIconSm = NULL;
|
||||
|
||||
::RegisterClassEx(&windowClass);
|
||||
|
||||
HWND window = ::CreateWindow(windowClass.lpszClassName, KIERO_TEXT("Kiero DirectX Window"), WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL);
|
||||
|
||||
if (_renderType == RenderType::D3D9)
|
||||
{
|
||||
#if KIERO_INCLUDE_D3D9
|
||||
HMODULE libD3D9;
|
||||
if ((libD3D9 = ::GetModuleHandle(KIERO_TEXT("d3d9.dll"))) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
void* Direct3DCreate9;
|
||||
if ((Direct3DCreate9 = ::GetProcAddress(libD3D9, "Direct3DCreate9")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
LPDIRECT3D9 direct3D9;
|
||||
if ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
D3DDISPLAYMODE displayMode;
|
||||
if (direct3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
D3DPRESENT_PARAMETERS params;
|
||||
params.BackBufferWidth = 0;
|
||||
params.BackBufferHeight = 0;
|
||||
params.BackBufferFormat = displayMode.Format;
|
||||
params.BackBufferCount = 0;
|
||||
params.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||||
params.MultiSampleQuality = NULL;
|
||||
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
params.hDeviceWindow = window;
|
||||
params.Windowed = 1;
|
||||
params.EnableAutoDepthStencil = 0;
|
||||
params.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
||||
params.Flags = NULL;
|
||||
params.FullScreen_RefreshRateInHz = 0;
|
||||
params.PresentationInterval = 0;
|
||||
|
||||
LPDIRECT3DDEVICE9 device;
|
||||
if (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, ¶ms, &device) < 0)
|
||||
{
|
||||
direct3D9->Release();
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(119, sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable, *(uint150_t**)device, 119 * sizeof(uint150_t));
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
direct3D9->Release();
|
||||
direct3D9 = NULL;
|
||||
|
||||
device->Release();
|
||||
device = NULL;
|
||||
|
||||
g_renderType = RenderType::D3D9;
|
||||
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
else if (_renderType == RenderType::D3D10)
|
||||
{
|
||||
#if KIERO_INCLUDE_D3D10
|
||||
HMODULE libDXGI;
|
||||
HMODULE libD3D10;
|
||||
if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D10 = ::GetModuleHandle(KIERO_TEXT("d3d10.dll"))) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
void* CreateDXGIFactory;
|
||||
if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
IDXGIFactory* factory;
|
||||
if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
IDXGIAdapter* adapter;
|
||||
if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
void* D3D10CreateDeviceAndSwapChain;
|
||||
if ((D3D10CreateDeviceAndSwapChain = ::GetProcAddress(libD3D10, "D3D10CreateDeviceAndSwapChain")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
DXGI_RATIONAL refreshRate;
|
||||
refreshRate.Numerator = 60;
|
||||
refreshRate.Denominator = 1;
|
||||
|
||||
DXGI_MODE_DESC bufferDesc;
|
||||
bufferDesc.Width = 100;
|
||||
bufferDesc.Height = 100;
|
||||
bufferDesc.RefreshRate = refreshRate;
|
||||
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
|
||||
DXGI_SAMPLE_DESC sampleDesc;
|
||||
sampleDesc.Count = 1;
|
||||
sampleDesc.Quality = 0;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapChainDesc;
|
||||
swapChainDesc.BufferDesc = bufferDesc;
|
||||
swapChainDesc.SampleDesc = sampleDesc;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = 1;
|
||||
swapChainDesc.OutputWindow = window;
|
||||
swapChainDesc.Windowed = 1;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
|
||||
IDXGISwapChain* swapChain;
|
||||
ID3D10Device* device;
|
||||
|
||||
if (((long(__stdcall*)(
|
||||
IDXGIAdapter*,
|
||||
D3D10_DRIVER_TYPE,
|
||||
HMODULE,
|
||||
UINT,
|
||||
UINT,
|
||||
DXGI_SWAP_CHAIN_DESC*,
|
||||
IDXGISwapChain**,
|
||||
ID3D10Device**))(D3D10CreateDeviceAndSwapChain))(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &swapChainDesc, &swapChain, &device) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(116, sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 18, *(uint150_t**)device, 98 * sizeof(uint150_t));
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
swapChain->Release();
|
||||
swapChain = NULL;
|
||||
|
||||
device->Release();
|
||||
device = NULL;
|
||||
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
|
||||
g_renderType = RenderType::D3D10;
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
else if (_renderType == RenderType::D3D11)
|
||||
{
|
||||
#if KIERO_INCLUDE_D3D11
|
||||
HMODULE libD3D11;
|
||||
if ((libD3D11 = ::GetModuleHandle(KIERO_TEXT("d3d11.dll"))) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
void* D3D11CreateDeviceAndSwapChain;
|
||||
if ((D3D11CreateDeviceAndSwapChain = ::GetProcAddress(libD3D11, "D3D11CreateDeviceAndSwapChain")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 };
|
||||
|
||||
DXGI_RATIONAL refreshRate;
|
||||
refreshRate.Numerator = 60;
|
||||
refreshRate.Denominator = 1;
|
||||
|
||||
DXGI_MODE_DESC bufferDesc;
|
||||
bufferDesc.Width = 100;
|
||||
bufferDesc.Height = 100;
|
||||
bufferDesc.RefreshRate = refreshRate;
|
||||
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
|
||||
DXGI_SAMPLE_DESC sampleDesc;
|
||||
sampleDesc.Count = 1;
|
||||
sampleDesc.Quality = 0;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapChainDesc;
|
||||
swapChainDesc.BufferDesc = bufferDesc;
|
||||
swapChainDesc.SampleDesc = sampleDesc;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = 1;
|
||||
swapChainDesc.OutputWindow = window;
|
||||
swapChainDesc.Windowed = 1;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
|
||||
IDXGISwapChain* swapChain;
|
||||
ID3D11Device* device;
|
||||
ID3D11DeviceContext* context;
|
||||
|
||||
if (((long(__stdcall*)(
|
||||
IDXGIAdapter*,
|
||||
D3D_DRIVER_TYPE,
|
||||
HMODULE,
|
||||
UINT,
|
||||
const D3D_FEATURE_LEVEL*,
|
||||
UINT,
|
||||
UINT,
|
||||
const DXGI_SWAP_CHAIN_DESC*,
|
||||
IDXGISwapChain**,
|
||||
ID3D11Device**,
|
||||
D3D_FEATURE_LEVEL*,
|
||||
ID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(205, sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 18, *(uint150_t**)device, 43 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 18 + 43, *(uint150_t**)context, 144 * sizeof(uint150_t));
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
swapChain->Release();
|
||||
swapChain = NULL;
|
||||
|
||||
device->Release();
|
||||
device = NULL;
|
||||
|
||||
context->Release();
|
||||
context = NULL;
|
||||
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
|
||||
g_renderType = RenderType::D3D11;
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
else if (_renderType == RenderType::D3D12)
|
||||
{
|
||||
#if KIERO_INCLUDE_D3D12
|
||||
HMODULE libDXGI;
|
||||
HMODULE libD3D12;
|
||||
if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D12 = ::GetModuleHandle(KIERO_TEXT("d3d12.dll"))) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
void* CreateDXGIFactory;
|
||||
if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
IDXGIFactory* factory;
|
||||
if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
IDXGIAdapter* adapter;
|
||||
if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
void* D3D12CreateDevice;
|
||||
if ((D3D12CreateDevice = ::GetProcAddress(libD3D12, "D3D12CreateDevice")) == NULL)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
ID3D12Device* device;
|
||||
if (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&device) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc;
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
queueDesc.Priority = 0;
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.NodeMask = 0;
|
||||
|
||||
ID3D12CommandQueue* commandQueue;
|
||||
if (device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
ID3D12CommandAllocator* commandAllocator;
|
||||
if (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&commandAllocator) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* commandList;
|
||||
if (device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&commandList) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
DXGI_RATIONAL refreshRate;
|
||||
refreshRate.Numerator = 60;
|
||||
refreshRate.Denominator = 1;
|
||||
|
||||
DXGI_MODE_DESC bufferDesc;
|
||||
bufferDesc.Width = 100;
|
||||
bufferDesc.Height = 100;
|
||||
bufferDesc.RefreshRate = refreshRate;
|
||||
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
|
||||
DXGI_SAMPLE_DESC sampleDesc;
|
||||
sampleDesc.Count = 1;
|
||||
sampleDesc.Quality = 0;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
|
||||
swapChainDesc.BufferDesc = bufferDesc;
|
||||
swapChainDesc.SampleDesc = sampleDesc;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = 2;
|
||||
swapChainDesc.OutputWindow = window;
|
||||
swapChainDesc.Windowed = 1;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
|
||||
IDXGISwapChain* swapChain;
|
||||
if (factory->CreateSwapChain(commandQueue, &swapChainDesc, &swapChain) < 0)
|
||||
{
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(150, sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable, *(uint150_t**)device, 44 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 44, *(uint150_t**)commandQueue, 19 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 44 + 19, *(uint150_t**)commandAllocator, 9 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 44 + 19 + 9, *(uint150_t**)commandList, 60 * sizeof(uint150_t));
|
||||
::memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
device->Release();
|
||||
device = NULL;
|
||||
|
||||
commandQueue->Release();
|
||||
commandQueue = NULL;
|
||||
|
||||
commandAllocator->Release();
|
||||
commandAllocator = NULL;
|
||||
|
||||
commandList->Release();
|
||||
commandList = NULL;
|
||||
|
||||
swapChain->Release();
|
||||
swapChain = NULL;
|
||||
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
|
||||
g_renderType = RenderType::D3D12;
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
::DestroyWindow(window);
|
||||
::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);
|
||||
|
||||
return Status::NotSupportedError;
|
||||
}
|
||||
else if (_renderType == RenderType::OpenGL)
|
||||
{
|
||||
#if KIERO_INCLUDE_OPENGL
|
||||
HMODULE libOpenGL32;
|
||||
if ((libOpenGL32 = ::GetModuleHandle(KIERO_TEXT("opengl32.dll"))) == NULL)
|
||||
{
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
const char* const methodsNames[] = {
|
||||
"glAccum", "glAlphaFunc", "glAreTexturesResident", "glArrayElement", "glBegin", "glBindTexture", "glBitmap", "glBlendFunc", "glCallList", "glCallLists", "glClear", "glClearAccum",
|
||||
"glClearColor", "glClearDepth", "glClearIndex", "glClearStencil", "glClipPlane", "glColor3b", "glColor3bv", "glColor3d", "glColor3dv", "glColor3f", "glColor3fv", "glColor3i", "glColor3iv",
|
||||
"glColor3s", "glColor3sv", "glColor3ub", "glColor3ubv", "glColor3ui", "glColor3uiv", "glColor3us", "glColor3usv", "glColor4b", "glColor4bv", "glColor4d", "glColor4dv", "glColor4f",
|
||||
"glColor4fv", "glColor4i", "glColor4iv", "glColor4s", "glColor4sv", "glColor4ub", "glColor4ubv", "glColor4ui", "glColor4uiv", "glColor4us", "glColor4usv", "glColorMask", "glColorMaterial",
|
||||
"glColorPointer", "glCopyPixels", "glCopyTexImage1D", "glCopyTexImage2D", "glCopyTexSubImage1D", "glCopyTexSubImage2D", "glCullFaceglCullFace", "glDeleteLists", "glDeleteTextures",
|
||||
"glDepthFunc", "glDepthMask", "glDepthRange", "glDisable", "glDisableClientState", "glDrawArrays", "glDrawBuffer", "glDrawElements", "glDrawPixels", "glEdgeFlag", "glEdgeFlagPointer",
|
||||
"glEdgeFlagv", "glEnable", "glEnableClientState", "glEnd", "glEndList", "glEvalCoord1d", "glEvalCoord1dv", "glEvalCoord1f", "glEvalCoord1fv", "glEvalCoord2d", "glEvalCoord2dv",
|
||||
"glEvalCoord2f", "glEvalCoord2fv", "glEvalMesh1", "glEvalMesh2", "glEvalPoint1", "glEvalPoint2", "glFeedbackBuffer", "glFinish", "glFlush", "glFogf", "glFogfv", "glFogi", "glFogiv",
|
||||
"glFrontFace", "glFrustum", "glGenLists", "glGenTextures", "glGetBooleanv", "glGetClipPlane", "glGetDoublev", "glGetError", "glGetFloatv", "glGetIntegerv", "glGetLightfv", "glGetLightiv",
|
||||
"glGetMapdv", "glGetMapfv", "glGetMapiv", "glGetMaterialfv", "glGetMaterialiv", "glGetPixelMapfv", "glGetPixelMapuiv", "glGetPixelMapusv", "glGetPointerv", "glGetPolygonStipple",
|
||||
"glGetString", "glGetTexEnvfv", "glGetTexEnviv", "glGetTexGendv", "glGetTexGenfv", "glGetTexGeniv", "glGetTexImage", "glGetTexLevelParameterfv", "glGetTexLevelParameteriv",
|
||||
"glGetTexParameterfv", "glGetTexParameteriv", "glHint", "glIndexMask", "glIndexPointer", "glIndexd", "glIndexdv", "glIndexf", "glIndexfv", "glIndexi", "glIndexiv", "glIndexs", "glIndexsv",
|
||||
"glIndexub", "glIndexubv", "glInitNames", "glInterleavedArrays", "glIsEnabled", "glIsList", "glIsTexture", "glLightModelf", "glLightModelfv", "glLightModeli", "glLightModeliv", "glLightf",
|
||||
"glLightfv", "glLighti", "glLightiv", "glLineStipple", "glLineWidth", "glListBase", "glLoadIdentity", "glLoadMatrixd", "glLoadMatrixf", "glLoadName", "glLogicOp", "glMap1d", "glMap1f",
|
||||
"glMap2d", "glMap2f", "glMapGrid1d", "glMapGrid1f", "glMapGrid2d", "glMapGrid2f", "glMaterialf", "glMaterialfv", "glMateriali", "glMaterialiv", "glMatrixMode", "glMultMatrixd",
|
||||
"glMultMatrixf", "glNewList", "glNormal3b", "glNormal3bv", "glNormal3d", "glNormal3dv", "glNormal3f", "glNormal3fv", "glNormal3i", "glNormal3iv", "glNormal3s", "glNormal3sv",
|
||||
"glNormalPointer", "glOrtho", "glPassThrough", "glPixelMapfv", "glPixelMapuiv", "glPixelMapusv", "glPixelStoref", "glPixelStorei", "glPixelTransferf", "glPixelTransferi", "glPixelZoom",
|
||||
"glPointSize", "glPolygonMode", "glPolygonOffset", "glPolygonStipple", "glPopAttrib", "glPopClientAttrib", "glPopMatrix", "glPopName", "glPrioritizeTextures", "glPushAttrib",
|
||||
"glPushClientAttrib", "glPushMatrix", "glPushName", "glRasterPos2d", "glRasterPos2dv", "glRasterPos2f", "glRasterPos2fv", "glRasterPos2i", "glRasterPos2iv", "glRasterPos2s",
|
||||
"glRasterPos2sv", "glRasterPos3d", "glRasterPos3dv", "glRasterPos3f", "glRasterPos3fv", "glRasterPos3i", "glRasterPos3iv", "glRasterPos3s", "glRasterPos3sv", "glRasterPos4d",
|
||||
"glRasterPos4dv", "glRasterPos4f", "glRasterPos4fv", "glRasterPos4i", "glRasterPos4iv", "glRasterPos4s", "glRasterPos4sv", "glReadBuffer", "glReadPixels", "glRectd", "glRectdv", "glRectf",
|
||||
"glRectfv", "glRecti", "glRectiv", "glRects", "glRectsv", "glRenderMode", "glRotated", "glRotatef", "glScaled", "glScalef", "glScissor", "glSelectBuffer", "glShadeModel", "glStencilFunc",
|
||||
"glStencilMask", "glStencilOp", "glTexCoord1d", "glTexCoord1dv", "glTexCoord1f", "glTexCoord1fv", "glTexCoord1i", "glTexCoord1iv", "glTexCoord1s", "glTexCoord1sv", "glTexCoord2d",
|
||||
"glTexCoord2dv", "glTexCoord2f", "glTexCoord2fv", "glTexCoord2i", "glTexCoord2iv", "glTexCoord2s", "glTexCoord2sv", "glTexCoord3d", "glTexCoord3dv", "glTexCoord3f", "glTexCoord3fv",
|
||||
"glTexCoord3i", "glTexCoord3iv", "glTexCoord3s", "glTexCoord3sv", "glTexCoord4d", "glTexCoord4dv", "glTexCoord4f", "glTexCoord4fv", "glTexCoord4i", "glTexCoord4iv", "glTexCoord4s",
|
||||
"glTexCoord4sv", "glTexCoordPointer", "glTexEnvf", "glTexEnvfv", "glTexEnvi", "glTexEnviv", "glTexGend", "glTexGendv", "glTexGenf", "glTexGenfv", "glTexGeni", "glTexGeniv", "glTexImage1D",
|
||||
"glTexImage2D", "glTexParameterf", "glTexParameterfv", "glTexParameteri", "glTexParameteriv", "glTexSubImage1D", "glTexSubImage2D", "glTranslated", "glTranslatef", "glVertex2d",
|
||||
"glVertex2dv", "glVertex2f", "glVertex2fv", "glVertex2i", "glVertex2iv", "glVertex2s", "glVertex2sv", "glVertex3d", "glVertex3dv", "glVertex3f", "glVertex3fv", "glVertex3i", "glVertex3iv",
|
||||
"glVertex3s", "glVertex3sv", "glVertex4d", "glVertex4dv", "glVertex4f", "glVertex4fv", "glVertex4i", "glVertex4iv", "glVertex4s", "glVertex4sv", "glVertexPointer", "glViewport"
|
||||
};
|
||||
|
||||
size_t size = KIERO_ARRAY_SIZE(methodsNames);
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t));
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
g_methodsTable[i] = (uint150_t)::GetProcAddress(libOpenGL32, methodsNames[i]);
|
||||
}
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
g_renderType = RenderType::OpenGL;
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
else if (_renderType == RenderType::Vulkan)
|
||||
{
|
||||
#if KIERO_INCLUDE_VULKAN
|
||||
HMODULE libVulkan;
|
||||
if ((libVulkan = GetModuleHandle(KIERO_TEXT("vulcan-1.dll"))) == NULL)
|
||||
{
|
||||
return Status::ModuleNotFoundError;
|
||||
}
|
||||
|
||||
const char* const methodsNames[] = {
|
||||
"vkCreateInstance", "vkDestroyInstance", "vkEnumeratePhysicalDevices", "vkGetPhysicalDeviceFeatures", "vkGetPhysicalDeviceFormatProperties", "vkGetPhysicalDeviceImageFormatProperties",
|
||||
"vkGetPhysicalDeviceProperties", "vkGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceMemoryProperties", "vkGetInstanceProcAddr", "vkGetDeviceProcAddr", "vkCreateDevice",
|
||||
"vkDestroyDevice", "vkEnumerateInstanceExtensionProperties", "vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceLayerProperties", "vkGetDeviceQueue", "vkQueueSubmit", "vkQueueWaitIdle",
|
||||
"vkDeviceWaitIdle", "vkAllocateMemory", "vkFreeMemory", "vkMapMemory", "vkUnmapMemory", "vkFlushMappedMemoryRanges", "vkInvalidateMappedMemoryRanges", "vkGetDeviceMemoryCommitment",
|
||||
"vkBindBufferMemory", "vkBindImageMemory", "vkGetBufferMemoryRequirements", "vkGetImageMemoryRequirements", "vkGetImageSparseMemoryRequirements", "vkGetPhysicalDeviceSparseImageFormatProperties",
|
||||
"vkQueueBindSparse", "vkCreateFence", "vkDestroyFence", "vkResetFences", "vkGetFenceStatus", "vkWaitForFences", "vkCreateSemaphore", "vkDestroySemaphore", "vkCreateEvent", "vkDestroyEvent",
|
||||
"vkGetEventStatus", "vkSetEvent", "vkResetEvent", "vkCreateQueryPool", "vkDestroyQueryPool", "vkGetQueryPoolResults", "vkCreateBuffer", "vkDestroyBuffer", "vkCreateBufferView", "vkDestroyBufferView",
|
||||
"vkCreateImage", "vkDestroyImage", "vkGetImageSubresourceLayout", "vkCreateImageView", "vkDestroyImageView", "vkCreateShaderModule", "vkDestroyShaderModule", "vkCreatePipelineCache",
|
||||
"vkDestroyPipelineCache", "vkGetPipelineCacheData", "vkMergePipelineCaches", "vkCreateGraphicsPipelines", "vkCreateComputePipelines", "vkDestroyPipeline", "vkCreatePipelineLayout",
|
||||
"vkDestroyPipelineLayout", "vkCreateSampler", "vkDestroySampler", "vkCreateDescriptorSetLayout", "vkDestroyDescriptorSetLayout", "vkCreateDescriptorPool", "vkDestroyDescriptorPool",
|
||||
"vkResetDescriptorPool", "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkUpdateDescriptorSets", "vkCreateFramebuffer", "vkDestroyFramebuffer", "vkCreateRenderPass", "vkDestroyRenderPass",
|
||||
"vkGetRenderAreaGranularity", "vkCreateCommandPool", "vkDestroyCommandPool", "vkResetCommandPool", "vkAllocateCommandBuffers", "vkFreeCommandBuffers", "vkBeginCommandBuffer", "vkEndCommandBuffer",
|
||||
"vkResetCommandBuffer", "vkCmdBindPipeline", "vkCmdSetViewport", "vkCmdSetScissor", "vkCmdSetLineWidth", "vkCmdSetDepthBias", "vkCmdSetBlendConstants", "vkCmdSetDepthBounds",
|
||||
"vkCmdSetStencilCompareMask", "vkCmdSetStencilWriteMask", "vkCmdSetStencilReference", "vkCmdBindDescriptorSets", "vkCmdBindIndexBuffer", "vkCmdBindVertexBuffers", "vkCmdDraw", "vkCmdDrawIndexed",
|
||||
"vkCmdDrawIndirect", "vkCmdDrawIndexedIndirect", "vkCmdDispatch", "vkCmdDispatchIndirect", "vkCmdCopyBuffer", "vkCmdCopyImage", "vkCmdBlitImage", "vkCmdCopyBufferToImage", "vkCmdCopyImageToBuffer",
|
||||
"vkCmdUpdateBuffer", "vkCmdFillBuffer", "vkCmdClearColorImage", "vkCmdClearDepthStencilImage", "vkCmdClearAttachments", "vkCmdResolveImage", "vkCmdSetEvent", "vkCmdResetEvent", "vkCmdWaitEvents",
|
||||
"vkCmdPipelineBarrier", "vkCmdBeginQuery", "vkCmdEndQuery", "vkCmdResetQueryPool", "vkCmdWriteTimestamp", "vkCmdCopyQueryPoolResults", "vkCmdPushConstants", "vkCmdBeginRenderPass", "vkCmdNextSubpass",
|
||||
"vkCmdEndRenderPass", "vkCmdExecuteCommands"
|
||||
};
|
||||
|
||||
size_t size = KIERO_ARRAY_SIZE(methodsNames);
|
||||
|
||||
g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t));
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
g_methodsTable[i] = (uint150_t)::GetProcAddress(libVulkan, methodsNames[i]);
|
||||
}
|
||||
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_Initialize();
|
||||
#endif
|
||||
|
||||
g_renderType = RenderType::Vulkan;
|
||||
|
||||
return Status::Success;
|
||||
#endif
|
||||
}
|
||||
else if (_renderType == RenderType::Auto)
|
||||
{
|
||||
RenderType::Enum type = RenderType::None;
|
||||
|
||||
if (::GetModuleHandle(KIERO_TEXT("d3d9.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::D3D9;
|
||||
}
|
||||
else if (::GetModuleHandle(KIERO_TEXT("d3d10.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::D3D10;
|
||||
}
|
||||
else if (::GetModuleHandle(KIERO_TEXT("d3d11.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::D3D11;
|
||||
}
|
||||
else if (::GetModuleHandle(KIERO_TEXT("d3d12.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::D3D12;
|
||||
}
|
||||
else if (::GetModuleHandle(KIERO_TEXT("opengl32.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::OpenGL;
|
||||
}
|
||||
else if (::GetModuleHandle(KIERO_TEXT("vulcan-1.dll")) != NULL)
|
||||
{
|
||||
type = RenderType::Vulkan;
|
||||
}
|
||||
|
||||
return init(type);
|
||||
}
|
||||
}
|
||||
|
||||
return Status::Success;
|
||||
}
|
||||
|
||||
void kiero::shutdown()
|
||||
{
|
||||
if (g_renderType != RenderType::None)
|
||||
{
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_DisableHook(MH_ALL_HOOKS);
|
||||
#endif
|
||||
|
||||
::free(g_methodsTable);
|
||||
g_methodsTable = NULL;
|
||||
g_renderType = RenderType::None;
|
||||
}
|
||||
}
|
||||
|
||||
kiero::Status::Enum kiero::bind(uint16_t _index, void** _original, void* _function)
|
||||
{
|
||||
// TODO: Need own detour function
|
||||
|
||||
assert(_index >= 0 && _original != NULL && _function != NULL);
|
||||
|
||||
if (g_renderType != RenderType::None)
|
||||
{
|
||||
#if KIERO_USE_MINHOOK
|
||||
void* target = (void*)g_methodsTable[_index];
|
||||
if (MH_CreateHook(target, _function, _original) != MH_OK || MH_EnableHook(target) != MH_OK)
|
||||
{
|
||||
return Status::UnknownError;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Status::Success;
|
||||
}
|
||||
|
||||
return Status::NotInitializedError;
|
||||
}
|
||||
|
||||
void kiero::unbind(uint16_t _index)
|
||||
{
|
||||
assert(_index >= 0);
|
||||
|
||||
if (g_renderType != RenderType::None)
|
||||
{
|
||||
#if KIERO_USE_MINHOOK
|
||||
MH_DisableHook((void*)g_methodsTable[_index]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
kiero::RenderType::Enum kiero::getRenderType()
|
||||
{
|
||||
return g_renderType;
|
||||
}
|
||||
|
||||
uint150_t* kiero::getMethodsTable()
|
||||
{
|
||||
return g_methodsTable;
|
||||
}
|
78
depthrush/kiero/kiero.h
Normal file
78
depthrush/kiero/kiero.h
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef __KIERO_H__
|
||||
#define __KIERO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define KIERO_VERSION "1.2.6"
|
||||
|
||||
#define KIERO_INCLUDE_D3D9 0 // 1 if you need D3D9 hook
|
||||
#define KIERO_INCLUDE_D3D10 0 // 1 if you need D3D10 hook
|
||||
#define KIERO_INCLUDE_D3D11 1 // 1 if you need D3D11 hook
|
||||
#define KIERO_INCLUDE_D3D12 0 // 1 if you need D3D12 hook
|
||||
#define KIERO_INCLUDE_OPENGL 0 // 1 if you need OpenGL hook
|
||||
#define KIERO_INCLUDE_VULKAN 0 // 1 if you need Vulkan hook
|
||||
#define KIERO_USE_MINHOOK 1 // 1 if you will use kiero::bind function
|
||||
|
||||
#define KIERO_ARCH_X64 0
|
||||
#define KIERO_ARCH_X86 0
|
||||
|
||||
#if defined(_M_X64)
|
||||
# undef KIERO_ARCH_X64
|
||||
# define KIERO_ARCH_X64 1
|
||||
#else
|
||||
# undef KIERO_ARCH_X86
|
||||
# define KIERO_ARCH_X86 1
|
||||
#endif
|
||||
|
||||
#if KIERO_ARCH_X64
|
||||
typedef uint64_t uint150_t;
|
||||
#else
|
||||
typedef uint32_t uint150_t;
|
||||
#endif
|
||||
|
||||
namespace kiero
|
||||
{
|
||||
struct Status
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
UnknownError = -1,
|
||||
NotSupportedError = -2,
|
||||
ModuleNotFoundError = -3,
|
||||
|
||||
AlreadyInitializedError = -4,
|
||||
NotInitializedError = -5,
|
||||
|
||||
Success = 0,
|
||||
};
|
||||
};
|
||||
|
||||
struct RenderType
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
None,
|
||||
|
||||
D3D9,
|
||||
D3D10,
|
||||
D3D11,
|
||||
D3D12,
|
||||
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
|
||||
Auto
|
||||
};
|
||||
};
|
||||
|
||||
Status::Enum init(RenderType::Enum renderType);
|
||||
void shutdown();
|
||||
|
||||
Status::Enum bind(uint16_t index, void** original, void* function);
|
||||
void unbind(uint16_t index);
|
||||
|
||||
RenderType::Enum getRenderType();
|
||||
uint150_t* getMethodsTable();
|
||||
}
|
||||
|
||||
#endif // __KIERO_H__
|
14
depthrush/kiero/minhook/dll_resources/MinHook.def
Normal file
14
depthrush/kiero/minhook/dll_resources/MinHook.def
Normal file
@ -0,0 +1,14 @@
|
||||
EXPORTS
|
||||
MH_Initialize
|
||||
MH_Uninitialize
|
||||
|
||||
MH_CreateHook
|
||||
MH_CreateHookApi
|
||||
MH_CreateHookApiEx
|
||||
MH_RemoveHook
|
||||
MH_EnableHook
|
||||
MH_DisableHook
|
||||
MH_QueueEnableHook
|
||||
MH_QueueDisableHook
|
||||
MH_ApplyQueued
|
||||
MH_StatusToString
|
32
depthrush/kiero/minhook/dll_resources/MinHook.rc
Normal file
32
depthrush/kiero/minhook/dll_resources/MinHook.rc
Normal file
@ -0,0 +1,32 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 1,3,3,0
|
||||
PRODUCTVERSION 1,3,3,0
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Tsuda Kageyu"
|
||||
VALUE "FileDescription", "MinHook - The Minimalistic API Hook Library for x64/x86"
|
||||
VALUE "FileVersion", "1.3.3.0"
|
||||
VALUE "InternalName", "MinHookD"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved."
|
||||
VALUE "LegalTrademarks", "Tsuda Kageyu"
|
||||
VALUE "ProductName", "MinHook DLL"
|
||||
VALUE "ProductVersion", "1.3.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
186
depthrush/kiero/minhook/include/MinHook.h
Normal file
186
depthrush/kiero/minhook/include/MinHook.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a Hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
312
depthrush/kiero/minhook/src/buffer.c
Normal file
312
depthrush/kiero/minhook/src/buffer.c
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "buffer.h"
|
||||
|
||||
// Size of each memory block. (= page size of VirtualAlloc)
|
||||
#define MEMORY_BLOCK_SIZE 0x1000
|
||||
|
||||
// Max range for seeking a memory block. (= 1024MB)
|
||||
#define MAX_MEMORY_RANGE 0x40000000
|
||||
|
||||
// Memory protection flags to check the executable address.
|
||||
#define PAGE_EXECUTE_FLAGS \
|
||||
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
|
||||
|
||||
// Memory slot.
|
||||
typedef struct _MEMORY_SLOT
|
||||
{
|
||||
union
|
||||
{
|
||||
struct _MEMORY_SLOT *pNext;
|
||||
UINT8 buffer[MEMORY_SLOT_SIZE];
|
||||
};
|
||||
} MEMORY_SLOT, *PMEMORY_SLOT;
|
||||
|
||||
// Memory block info. Placed at the head of each block.
|
||||
typedef struct _MEMORY_BLOCK
|
||||
{
|
||||
struct _MEMORY_BLOCK *pNext;
|
||||
PMEMORY_SLOT pFree; // First element of the free slot list.
|
||||
UINT usedCount;
|
||||
} MEMORY_BLOCK, *PMEMORY_BLOCK;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// First element of the memory block list.
|
||||
PMEMORY_BLOCK g_pMemoryBlocks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID InitializeBuffer(VOID)
|
||||
{
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID UninitializeBuffer(VOID)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = NULL;
|
||||
|
||||
while (pBlock)
|
||||
{
|
||||
PMEMORY_BLOCK pNext = pBlock->pNext;
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
pBlock = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the previous allocation granularity multiply.
|
||||
tryAddr -= dwAllocationGranularity;
|
||||
|
||||
while (tryAddr >= (ULONG_PTR)pMinAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
|
||||
break;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the next allocation granularity multiply.
|
||||
tryAddr += dwAllocationGranularity;
|
||||
|
||||
while (tryAddr <= (ULONG_PTR)pMaxAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
|
||||
|
||||
// Round up to the next allocation granularity.
|
||||
tryAddr += dwAllocationGranularity - 1;
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
ULONG_PTR minAddr;
|
||||
ULONG_PTR maxAddr;
|
||||
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
|
||||
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
|
||||
|
||||
// pOrigin ± 512MB
|
||||
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
|
||||
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
|
||||
|
||||
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
|
||||
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
|
||||
|
||||
// Make room for MEMORY_BLOCK_SIZE bytes.
|
||||
maxAddr -= MEMORY_BLOCK_SIZE - 1;
|
||||
#endif
|
||||
|
||||
// Look the registered blocks for a reachable one.
|
||||
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Ignore the blocks too far.
|
||||
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
|
||||
continue;
|
||||
#endif
|
||||
// The block has at least one unused slot.
|
||||
if (pBlock->pFree != NULL)
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Alloc a new block above if not found.
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc >= minAddr)
|
||||
{
|
||||
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Alloc a new block below if not found.
|
||||
if (pBlock == NULL)
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc <= maxAddr)
|
||||
{
|
||||
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// In x86 mode, a memory block can be placed anywhere.
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
#endif
|
||||
|
||||
if (pBlock != NULL)
|
||||
{
|
||||
// Build a linked list of all the slots.
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
|
||||
pBlock->pFree = NULL;
|
||||
pBlock->usedCount = 0;
|
||||
do
|
||||
{
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pSlot++;
|
||||
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
|
||||
|
||||
pBlock->pNext = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = pBlock;
|
||||
}
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_SLOT pSlot;
|
||||
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
|
||||
if (pBlock == NULL)
|
||||
return NULL;
|
||||
|
||||
// Remove an unused slot from the list.
|
||||
pSlot = pBlock->pFree;
|
||||
pBlock->pFree = pSlot->pNext;
|
||||
pBlock->usedCount++;
|
||||
#ifdef _DEBUG
|
||||
// Fill the slot with INT3 for debugging.
|
||||
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
|
||||
#endif
|
||||
return pSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID FreeBuffer(LPVOID pBuffer)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
PMEMORY_BLOCK pPrev = NULL;
|
||||
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
|
||||
|
||||
while (pBlock != NULL)
|
||||
{
|
||||
if ((ULONG_PTR)pBlock == pTargetBlock)
|
||||
{
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
|
||||
#ifdef _DEBUG
|
||||
// Clear the released slot for debugging.
|
||||
memset(pSlot, 0x00, sizeof(*pSlot));
|
||||
#endif
|
||||
// Restore the released slot to the list.
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pBlock->usedCount--;
|
||||
|
||||
// Free if unused.
|
||||
if (pBlock->usedCount == 0)
|
||||
{
|
||||
if (pPrev)
|
||||
pPrev->pNext = pBlock->pNext;
|
||||
else
|
||||
g_pMemoryBlocks = pBlock->pNext;
|
||||
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pPrev = pBlock;
|
||||
pBlock = pBlock->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL IsExecutableAddress(LPVOID pAddress)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mi;
|
||||
VirtualQuery(pAddress, &mi, sizeof(mi));
|
||||
|
||||
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
|
||||
}
|
42
depthrush/kiero/minhook/src/buffer.h
Normal file
42
depthrush/kiero/minhook/src/buffer.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Size of each memory slot.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define MEMORY_SLOT_SIZE 64
|
||||
#else
|
||||
#define MEMORY_SLOT_SIZE 32
|
||||
#endif
|
||||
|
||||
VOID InitializeBuffer(VOID);
|
||||
VOID UninitializeBuffer(VOID);
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin);
|
||||
VOID FreeBuffer(LPVOID pBuffer);
|
||||
BOOL IsExecutableAddress(LPVOID pAddress);
|
326
depthrush/kiero/minhook/src/hde/hde32.c
Normal file
326
depthrush/kiero/minhook/src/hde/hde32.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
|
||||
#include "hde32.h"
|
||||
#include "table32.h"
|
||||
|
||||
unsigned int hde32_disasm(const void *code, hde32s *hs)
|
||||
{
|
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||
|
||||
// Avoid using memset to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memset((LPBYTE)hs, 0, sizeof(hde32s));
|
||||
#else
|
||||
__stosb((LPBYTE)hs, 0, sizeof(hde32s));
|
||||
#endif
|
||||
|
||||
for (x = 16; x; x--)
|
||||
switch (c = *p++) {
|
||||
case 0xf3:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F3;
|
||||
break;
|
||||
case 0xf2:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F2;
|
||||
break;
|
||||
case 0xf0:
|
||||
hs->p_lock = c;
|
||||
pref |= PRE_LOCK;
|
||||
break;
|
||||
case 0x26: case 0x2e: case 0x36:
|
||||
case 0x3e: case 0x64: case 0x65:
|
||||
hs->p_seg = c;
|
||||
pref |= PRE_SEG;
|
||||
break;
|
||||
case 0x66:
|
||||
hs->p_66 = c;
|
||||
pref |= PRE_66;
|
||||
break;
|
||||
case 0x67:
|
||||
hs->p_67 = c;
|
||||
pref |= PRE_67;
|
||||
break;
|
||||
default:
|
||||
goto pref_done;
|
||||
}
|
||||
pref_done:
|
||||
|
||||
hs->flags = (uint32_t)pref << 23;
|
||||
|
||||
if (!pref)
|
||||
pref |= PRE_NONE;
|
||||
|
||||
if ((hs->opcode = c) == 0x0f) {
|
||||
hs->opcode2 = c = *p++;
|
||||
ht += DELTA_OPCODES;
|
||||
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||
if (pref & PRE_67)
|
||||
pref |= PRE_66;
|
||||
else
|
||||
pref &= ~PRE_66;
|
||||
}
|
||||
|
||||
opcode = c;
|
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||
|
||||
if (cflags == C_ERROR) {
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
cflags = 0;
|
||||
if ((opcode & -3) == 0x24)
|
||||
cflags++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (cflags & C_GROUP) {
|
||||
uint16_t t;
|
||||
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||
cflags = (uint8_t)t;
|
||||
x = (uint8_t)(t >> 8);
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_PREFIXES;
|
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (cflags & C_MODRM) {
|
||||
hs->flags |= F_MODRM;
|
||||
hs->modrm = c = *p++;
|
||||
hs->modrm_mod = m_mod = c >> 6;
|
||||
hs->modrm_rm = m_rm = c & 7;
|
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||
|
||||
if (x && ((x << m_reg) & 0x80))
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||
uint8_t t = opcode - 0xd9;
|
||||
if (m_mod == 3) {
|
||||
ht = hde32_table + DELTA_FPU_MODRM + t*8;
|
||||
t = ht[m_reg] << m_rm;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_FPU_REG;
|
||||
t = ht[t] << m_reg;
|
||||
}
|
||||
if (t & 0x80)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (pref & PRE_LOCK) {
|
||||
if (m_mod == 3) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
} else {
|
||||
uint8_t *table_end, op = opcode;
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_OP2_LOCK_OK;
|
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_OP_LOCK_OK;
|
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||
op &= -2;
|
||||
}
|
||||
for (; ht != table_end; ht++)
|
||||
if (*ht++ == op) {
|
||||
if (!((*ht << m_reg) & 0x80))
|
||||
goto no_lock_error;
|
||||
else
|
||||
break;
|
||||
}
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
no_lock_error:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x20: case 0x22:
|
||||
m_mod = 3;
|
||||
if (m_reg > 4 || m_reg == 1)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x21: case 0x23:
|
||||
m_mod = 3;
|
||||
if (m_reg == 4 || m_reg == 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case 0x8c:
|
||||
if (m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x8e:
|
||||
if (m_reg == 1 || m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod == 3) {
|
||||
uint8_t *table_end;
|
||||
if (hs->opcode2) {
|
||||
ht = hde32_table + DELTA_OP2_ONLY_MEM;
|
||||
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
|
||||
} else {
|
||||
ht = hde32_table + DELTA_OP_ONLY_MEM;
|
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||
}
|
||||
for (; ht != table_end; ht += 2)
|
||||
if (*ht++ == opcode) {
|
||||
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
|
||||
goto error_operand;
|
||||
else
|
||||
break;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x50: case 0xd7: case 0xf7:
|
||||
if (pref & (PRE_NONE | PRE_66))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xd6:
|
||||
if (pref & (PRE_F2 | PRE_F3))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xc5:
|
||||
goto error_operand;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else
|
||||
goto no_error_operand;
|
||||
|
||||
error_operand:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||
no_error_operand:
|
||||
|
||||
c = *p++;
|
||||
if (m_reg <= 1) {
|
||||
if (opcode == 0xf6)
|
||||
cflags |= C_IMM8;
|
||||
else if (opcode == 0xf7)
|
||||
cflags |= C_IMM_P66;
|
||||
}
|
||||
|
||||
switch (m_mod) {
|
||||
case 0:
|
||||
if (pref & PRE_67) {
|
||||
if (m_rm == 6)
|
||||
disp_size = 2;
|
||||
} else
|
||||
if (m_rm == 5)
|
||||
disp_size = 4;
|
||||
break;
|
||||
case 1:
|
||||
disp_size = 1;
|
||||
break;
|
||||
case 2:
|
||||
disp_size = 2;
|
||||
if (!(pref & PRE_67))
|
||||
disp_size <<= 1;
|
||||
}
|
||||
|
||||
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
|
||||
hs->flags |= F_SIB;
|
||||
p++;
|
||||
hs->sib = c;
|
||||
hs->sib_scale = c >> 6;
|
||||
hs->sib_index = (c & 0x3f) >> 3;
|
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||
disp_size = 4;
|
||||
}
|
||||
|
||||
p--;
|
||||
switch (disp_size) {
|
||||
case 1:
|
||||
hs->flags |= F_DISP8;
|
||||
hs->disp.disp8 = *p;
|
||||
break;
|
||||
case 2:
|
||||
hs->flags |= F_DISP16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
break;
|
||||
case 4:
|
||||
hs->flags |= F_DISP32;
|
||||
hs->disp.disp32 = *(uint32_t *)p;
|
||||
}
|
||||
p += disp_size;
|
||||
} else if (pref & PRE_LOCK)
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
|
||||
if (cflags & C_IMM_P66) {
|
||||
if (cflags & C_REL32) {
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
goto disasm_done;
|
||||
}
|
||||
goto rel32_ok;
|
||||
}
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
} else {
|
||||
hs->flags |= F_IMM32;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (cflags & C_IMM16) {
|
||||
if (hs->flags & F_IMM32) {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
} else if (hs->flags & F_IMM16) {
|
||||
hs->flags |= F_2IMM16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
} else {
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
}
|
||||
p += 2;
|
||||
}
|
||||
if (cflags & C_IMM8) {
|
||||
hs->flags |= F_IMM8;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
if (cflags & C_REL32) {
|
||||
rel32_ok:
|
||||
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else if (cflags & C_REL8) {
|
||||
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
disasm_done:
|
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||
hs->len = 15;
|
||||
}
|
||||
|
||||
return (unsigned int)hs->len;
|
||||
}
|
||||
|
||||
#endif // defined(_M_IX86) || defined(__i386__)
|
105
depthrush/kiero/minhook/src/hde/hde32.h
Normal file
105
depthrush/kiero/minhook/src/hde/hde32.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32
|
||||
* Copyright (c) 2006-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
* hde32.h: C/C++ header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HDE32_H_
|
||||
#define _HDE32_H_
|
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
*
|
||||
* if your compiler doesn't contain "stdint.h" header (for
|
||||
* example, Microsoft Visual C++), you can download file:
|
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to:
|
||||
* #include "pstdint.h"
|
||||
*/
|
||||
#include "pstdint.h"
|
||||
|
||||
#define F_MODRM 0x00000001
|
||||
#define F_SIB 0x00000002
|
||||
#define F_IMM8 0x00000004
|
||||
#define F_IMM16 0x00000008
|
||||
#define F_IMM32 0x00000010
|
||||
#define F_DISP8 0x00000020
|
||||
#define F_DISP16 0x00000040
|
||||
#define F_DISP32 0x00000080
|
||||
#define F_RELATIVE 0x00000100
|
||||
#define F_2IMM16 0x00000800
|
||||
#define F_ERROR 0x00001000
|
||||
#define F_ERROR_OPCODE 0x00002000
|
||||
#define F_ERROR_LENGTH 0x00004000
|
||||
#define F_ERROR_LOCK 0x00008000
|
||||
#define F_ERROR_OPERAND 0x00010000
|
||||
#define F_PREFIX_REPNZ 0x01000000
|
||||
#define F_PREFIX_REPX 0x02000000
|
||||
#define F_PREFIX_REP 0x03000000
|
||||
#define F_PREFIX_66 0x04000000
|
||||
#define F_PREFIX_67 0x08000000
|
||||
#define F_PREFIX_LOCK 0x10000000
|
||||
#define F_PREFIX_SEG 0x20000000
|
||||
#define F_PREFIX_ANY 0x3f000000
|
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e
|
||||
#define PREFIX_SEGMENT_SS 0x36
|
||||
#define PREFIX_SEGMENT_DS 0x3e
|
||||
#define PREFIX_SEGMENT_ES 0x26
|
||||
#define PREFIX_SEGMENT_FS 0x64
|
||||
#define PREFIX_SEGMENT_GS 0x65
|
||||
#define PREFIX_LOCK 0xf0
|
||||
#define PREFIX_REPNZ 0xf2
|
||||
#define PREFIX_REPX 0xf3
|
||||
#define PREFIX_OPERAND_SIZE 0x66
|
||||
#define PREFIX_ADDRESS_SIZE 0x67
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t p_rep;
|
||||
uint8_t p_lock;
|
||||
uint8_t p_seg;
|
||||
uint8_t p_66;
|
||||
uint8_t p_67;
|
||||
uint8_t opcode;
|
||||
uint8_t opcode2;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_mod;
|
||||
uint8_t modrm_reg;
|
||||
uint8_t modrm_rm;
|
||||
uint8_t sib;
|
||||
uint8_t sib_scale;
|
||||
uint8_t sib_index;
|
||||
uint8_t sib_base;
|
||||
union {
|
||||
uint8_t imm8;
|
||||
uint16_t imm16;
|
||||
uint32_t imm32;
|
||||
} imm;
|
||||
union {
|
||||
uint8_t disp8;
|
||||
uint16_t disp16;
|
||||
uint32_t disp32;
|
||||
} disp;
|
||||
uint32_t flags;
|
||||
} hde32s;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* __cdecl */
|
||||
unsigned int hde32_disasm(const void *code, hde32s *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HDE32_H_ */
|
337
depthrush/kiero/minhook/src/hde/hde64.c
Normal file
337
depthrush/kiero/minhook/src/hde/hde64.c
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
|
||||
#include "hde64.h"
|
||||
#include "table64.h"
|
||||
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs)
|
||||
{
|
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||
uint8_t op64 = 0;
|
||||
|
||||
// Avoid using memset to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memset((LPBYTE)hs, 0, sizeof(hde64s));
|
||||
#else
|
||||
__stosb((LPBYTE)hs, 0, sizeof(hde64s));
|
||||
#endif
|
||||
|
||||
for (x = 16; x; x--)
|
||||
switch (c = *p++) {
|
||||
case 0xf3:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F3;
|
||||
break;
|
||||
case 0xf2:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F2;
|
||||
break;
|
||||
case 0xf0:
|
||||
hs->p_lock = c;
|
||||
pref |= PRE_LOCK;
|
||||
break;
|
||||
case 0x26: case 0x2e: case 0x36:
|
||||
case 0x3e: case 0x64: case 0x65:
|
||||
hs->p_seg = c;
|
||||
pref |= PRE_SEG;
|
||||
break;
|
||||
case 0x66:
|
||||
hs->p_66 = c;
|
||||
pref |= PRE_66;
|
||||
break;
|
||||
case 0x67:
|
||||
hs->p_67 = c;
|
||||
pref |= PRE_67;
|
||||
break;
|
||||
default:
|
||||
goto pref_done;
|
||||
}
|
||||
pref_done:
|
||||
|
||||
hs->flags = (uint32_t)pref << 23;
|
||||
|
||||
if (!pref)
|
||||
pref |= PRE_NONE;
|
||||
|
||||
if ((c & 0xf0) == 0x40) {
|
||||
hs->flags |= F_PREFIX_REX;
|
||||
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
|
||||
op64++;
|
||||
hs->rex_r = (c & 7) >> 2;
|
||||
hs->rex_x = (c & 3) >> 1;
|
||||
hs->rex_b = c & 1;
|
||||
if (((c = *p++) & 0xf0) == 0x40) {
|
||||
opcode = c;
|
||||
goto error_opcode;
|
||||
}
|
||||
}
|
||||
|
||||
if ((hs->opcode = c) == 0x0f) {
|
||||
hs->opcode2 = c = *p++;
|
||||
ht += DELTA_OPCODES;
|
||||
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||
op64++;
|
||||
if (pref & PRE_67)
|
||||
pref |= PRE_66;
|
||||
else
|
||||
pref &= ~PRE_66;
|
||||
}
|
||||
|
||||
opcode = c;
|
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||
|
||||
if (cflags == C_ERROR) {
|
||||
error_opcode:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
cflags = 0;
|
||||
if ((opcode & -3) == 0x24)
|
||||
cflags++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (cflags & C_GROUP) {
|
||||
uint16_t t;
|
||||
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||
cflags = (uint8_t)t;
|
||||
x = (uint8_t)(t >> 8);
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_PREFIXES;
|
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (cflags & C_MODRM) {
|
||||
hs->flags |= F_MODRM;
|
||||
hs->modrm = c = *p++;
|
||||
hs->modrm_mod = m_mod = c >> 6;
|
||||
hs->modrm_rm = m_rm = c & 7;
|
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||
|
||||
if (x && ((x << m_reg) & 0x80))
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||
uint8_t t = opcode - 0xd9;
|
||||
if (m_mod == 3) {
|
||||
ht = hde64_table + DELTA_FPU_MODRM + t*8;
|
||||
t = ht[m_reg] << m_rm;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_FPU_REG;
|
||||
t = ht[t] << m_reg;
|
||||
}
|
||||
if (t & 0x80)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (pref & PRE_LOCK) {
|
||||
if (m_mod == 3) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
} else {
|
||||
uint8_t *table_end, op = opcode;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_LOCK_OK;
|
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_LOCK_OK;
|
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||
op &= -2;
|
||||
}
|
||||
for (; ht != table_end; ht++)
|
||||
if (*ht++ == op) {
|
||||
if (!((*ht << m_reg) & 0x80))
|
||||
goto no_lock_error;
|
||||
else
|
||||
break;
|
||||
}
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
no_lock_error:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x20: case 0x22:
|
||||
m_mod = 3;
|
||||
if (m_reg > 4 || m_reg == 1)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x21: case 0x23:
|
||||
m_mod = 3;
|
||||
if (m_reg == 4 || m_reg == 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case 0x8c:
|
||||
if (m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x8e:
|
||||
if (m_reg == 1 || m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod == 3) {
|
||||
uint8_t *table_end;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_ONLY_MEM;
|
||||
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_ONLY_MEM;
|
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||
}
|
||||
for (; ht != table_end; ht += 2)
|
||||
if (*ht++ == opcode) {
|
||||
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
|
||||
goto error_operand;
|
||||
else
|
||||
break;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x50: case 0xd7: case 0xf7:
|
||||
if (pref & (PRE_NONE | PRE_66))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xd6:
|
||||
if (pref & (PRE_F2 | PRE_F3))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xc5:
|
||||
goto error_operand;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else
|
||||
goto no_error_operand;
|
||||
|
||||
error_operand:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||
no_error_operand:
|
||||
|
||||
c = *p++;
|
||||
if (m_reg <= 1) {
|
||||
if (opcode == 0xf6)
|
||||
cflags |= C_IMM8;
|
||||
else if (opcode == 0xf7)
|
||||
cflags |= C_IMM_P66;
|
||||
}
|
||||
|
||||
switch (m_mod) {
|
||||
case 0:
|
||||
if (pref & PRE_67) {
|
||||
if (m_rm == 6)
|
||||
disp_size = 2;
|
||||
} else
|
||||
if (m_rm == 5)
|
||||
disp_size = 4;
|
||||
break;
|
||||
case 1:
|
||||
disp_size = 1;
|
||||
break;
|
||||
case 2:
|
||||
disp_size = 2;
|
||||
if (!(pref & PRE_67))
|
||||
disp_size <<= 1;
|
||||
}
|
||||
|
||||
if (m_mod != 3 && m_rm == 4) {
|
||||
hs->flags |= F_SIB;
|
||||
p++;
|
||||
hs->sib = c;
|
||||
hs->sib_scale = c >> 6;
|
||||
hs->sib_index = (c & 0x3f) >> 3;
|
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||
disp_size = 4;
|
||||
}
|
||||
|
||||
p--;
|
||||
switch (disp_size) {
|
||||
case 1:
|
||||
hs->flags |= F_DISP8;
|
||||
hs->disp.disp8 = *p;
|
||||
break;
|
||||
case 2:
|
||||
hs->flags |= F_DISP16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
break;
|
||||
case 4:
|
||||
hs->flags |= F_DISP32;
|
||||
hs->disp.disp32 = *(uint32_t *)p;
|
||||
}
|
||||
p += disp_size;
|
||||
} else if (pref & PRE_LOCK)
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
|
||||
if (cflags & C_IMM_P66) {
|
||||
if (cflags & C_REL32) {
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
goto disasm_done;
|
||||
}
|
||||
goto rel32_ok;
|
||||
}
|
||||
if (op64) {
|
||||
hs->flags |= F_IMM64;
|
||||
hs->imm.imm64 = *(uint64_t *)p;
|
||||
p += 8;
|
||||
} else if (!(pref & PRE_66)) {
|
||||
hs->flags |= F_IMM32;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else
|
||||
goto imm16_ok;
|
||||
}
|
||||
|
||||
|
||||
if (cflags & C_IMM16) {
|
||||
imm16_ok:
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
}
|
||||
if (cflags & C_IMM8) {
|
||||
hs->flags |= F_IMM8;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
if (cflags & C_REL32) {
|
||||
rel32_ok:
|
||||
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else if (cflags & C_REL8) {
|
||||
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
disasm_done:
|
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||
hs->len = 15;
|
||||
}
|
||||
|
||||
return (unsigned int)hs->len;
|
||||
}
|
||||
|
||||
#endif // defined(_M_X64) || defined(__x86_64__)
|
112
depthrush/kiero/minhook/src/hde/hde64.h
Normal file
112
depthrush/kiero/minhook/src/hde/hde64.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
* hde64.h: C/C++ header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HDE64_H_
|
||||
#define _HDE64_H_
|
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
*
|
||||
* if your compiler doesn't contain "stdint.h" header (for
|
||||
* example, Microsoft Visual C++), you can download file:
|
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to:
|
||||
* #include "pstdint.h"
|
||||
*/
|
||||
#include "pstdint.h"
|
||||
|
||||
#define F_MODRM 0x00000001
|
||||
#define F_SIB 0x00000002
|
||||
#define F_IMM8 0x00000004
|
||||
#define F_IMM16 0x00000008
|
||||
#define F_IMM32 0x00000010
|
||||
#define F_IMM64 0x00000020
|
||||
#define F_DISP8 0x00000040
|
||||
#define F_DISP16 0x00000080
|
||||
#define F_DISP32 0x00000100
|
||||
#define F_RELATIVE 0x00000200
|
||||
#define F_ERROR 0x00001000
|
||||
#define F_ERROR_OPCODE 0x00002000
|
||||
#define F_ERROR_LENGTH 0x00004000
|
||||
#define F_ERROR_LOCK 0x00008000
|
||||
#define F_ERROR_OPERAND 0x00010000
|
||||
#define F_PREFIX_REPNZ 0x01000000
|
||||
#define F_PREFIX_REPX 0x02000000
|
||||
#define F_PREFIX_REP 0x03000000
|
||||
#define F_PREFIX_66 0x04000000
|
||||
#define F_PREFIX_67 0x08000000
|
||||
#define F_PREFIX_LOCK 0x10000000
|
||||
#define F_PREFIX_SEG 0x20000000
|
||||
#define F_PREFIX_REX 0x40000000
|
||||
#define F_PREFIX_ANY 0x7f000000
|
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e
|
||||
#define PREFIX_SEGMENT_SS 0x36
|
||||
#define PREFIX_SEGMENT_DS 0x3e
|
||||
#define PREFIX_SEGMENT_ES 0x26
|
||||
#define PREFIX_SEGMENT_FS 0x64
|
||||
#define PREFIX_SEGMENT_GS 0x65
|
||||
#define PREFIX_LOCK 0xf0
|
||||
#define PREFIX_REPNZ 0xf2
|
||||
#define PREFIX_REPX 0xf3
|
||||
#define PREFIX_OPERAND_SIZE 0x66
|
||||
#define PREFIX_ADDRESS_SIZE 0x67
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t p_rep;
|
||||
uint8_t p_lock;
|
||||
uint8_t p_seg;
|
||||
uint8_t p_66;
|
||||
uint8_t p_67;
|
||||
uint8_t rex;
|
||||
uint8_t rex_w;
|
||||
uint8_t rex_r;
|
||||
uint8_t rex_x;
|
||||
uint8_t rex_b;
|
||||
uint8_t opcode;
|
||||
uint8_t opcode2;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_mod;
|
||||
uint8_t modrm_reg;
|
||||
uint8_t modrm_rm;
|
||||
uint8_t sib;
|
||||
uint8_t sib_scale;
|
||||
uint8_t sib_index;
|
||||
uint8_t sib_base;
|
||||
union {
|
||||
uint8_t imm8;
|
||||
uint16_t imm16;
|
||||
uint32_t imm32;
|
||||
uint64_t imm64;
|
||||
} imm;
|
||||
union {
|
||||
uint8_t disp8;
|
||||
uint16_t disp16;
|
||||
uint32_t disp32;
|
||||
} disp;
|
||||
uint32_t flags;
|
||||
} hde64s;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* __cdecl */
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HDE64_H_ */
|
39
depthrush/kiero/minhook/src/hde/pstdint.h
Normal file
39
depthrush/kiero/minhook/src/hde/pstdint.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Integer types for HDE.
|
||||
typedef INT8 int8_t;
|
||||
typedef INT16 int16_t;
|
||||
typedef INT32 int32_t;
|
||||
typedef INT64 int64_t;
|
||||
typedef UINT8 uint8_t;
|
||||
typedef UINT16 uint16_t;
|
||||
typedef UINT32 uint32_t;
|
||||
typedef UINT64 uint64_t;
|
73
depthrush/kiero/minhook/src/hde/table32.h
Normal file
73
depthrush/kiero/minhook/src/hde/table32.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 32 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define C_NONE 0x00
|
||||
#define C_MODRM 0x01
|
||||
#define C_IMM8 0x02
|
||||
#define C_IMM16 0x04
|
||||
#define C_IMM_P66 0x10
|
||||
#define C_REL8 0x20
|
||||
#define C_REL32 0x40
|
||||
#define C_GROUP 0x80
|
||||
#define C_ERROR 0xff
|
||||
|
||||
#define PRE_ANY 0x00
|
||||
#define PRE_NONE 0x01
|
||||
#define PRE_F2 0x02
|
||||
#define PRE_F3 0x04
|
||||
#define PRE_66 0x08
|
||||
#define PRE_67 0x10
|
||||
#define PRE_LOCK 0x20
|
||||
#define PRE_SEG 0x40
|
||||
#define PRE_ALL 0xff
|
||||
|
||||
#define DELTA_OPCODES 0x4a
|
||||
#define DELTA_FPU_REG 0xf1
|
||||
#define DELTA_FPU_MODRM 0xf8
|
||||
#define DELTA_PREFIXES 0x130
|
||||
#define DELTA_OP_LOCK_OK 0x1a1
|
||||
#define DELTA_OP2_LOCK_OK 0x1b9
|
||||
#define DELTA_OP_ONLY_MEM 0x1cb
|
||||
#define DELTA_OP2_ONLY_MEM 0x1da
|
||||
|
||||
unsigned char hde32_table[] = {
|
||||
0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
|
||||
0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
|
||||
0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
|
||||
0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
|
||||
0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
|
||||
0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
|
||||
0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
|
||||
0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
|
||||
0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
|
||||
0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
|
||||
0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
|
||||
0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
|
||||
0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
|
||||
0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
|
||||
0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
|
||||
0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
|
||||
0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
|
||||
0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
|
||||
0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
|
||||
0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
|
||||
0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
|
||||
0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
|
||||
0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
|
||||
0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
||||
0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
|
||||
0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
|
||||
0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
|
||||
0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
|
||||
0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
|
||||
0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
|
||||
0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
|
||||
0xe7,0x08,0x00,0xf0,0x02,0x00
|
||||
};
|
74
depthrush/kiero/minhook/src/hde/table64.h
Normal file
74
depthrush/kiero/minhook/src/hde/table64.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define C_NONE 0x00
|
||||
#define C_MODRM 0x01
|
||||
#define C_IMM8 0x02
|
||||
#define C_IMM16 0x04
|
||||
#define C_IMM_P66 0x10
|
||||
#define C_REL8 0x20
|
||||
#define C_REL32 0x40
|
||||
#define C_GROUP 0x80
|
||||
#define C_ERROR 0xff
|
||||
|
||||
#define PRE_ANY 0x00
|
||||
#define PRE_NONE 0x01
|
||||
#define PRE_F2 0x02
|
||||
#define PRE_F3 0x04
|
||||
#define PRE_66 0x08
|
||||
#define PRE_67 0x10
|
||||
#define PRE_LOCK 0x20
|
||||
#define PRE_SEG 0x40
|
||||
#define PRE_ALL 0xff
|
||||
|
||||
#define DELTA_OPCODES 0x4a
|
||||
#define DELTA_FPU_REG 0xfd
|
||||
#define DELTA_FPU_MODRM 0x104
|
||||
#define DELTA_PREFIXES 0x13c
|
||||
#define DELTA_OP_LOCK_OK 0x1ae
|
||||
#define DELTA_OP2_LOCK_OK 0x1c6
|
||||
#define DELTA_OP_ONLY_MEM 0x1d8
|
||||
#define DELTA_OP2_ONLY_MEM 0x1e7
|
||||
|
||||
unsigned char hde64_table[] = {
|
||||
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
|
||||
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
|
||||
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
|
||||
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
|
||||
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
|
||||
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
|
||||
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
|
||||
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
|
||||
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
|
||||
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
|
||||
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
|
||||
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
|
||||
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
|
||||
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
|
||||
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
|
||||
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
|
||||
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
|
||||
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
|
||||
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
|
||||
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
|
||||
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
|
||||
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
|
||||
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
|
||||
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
||||
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
|
||||
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
|
||||
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
|
||||
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
|
||||
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
|
||||
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
|
||||
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
|
||||
0x00,0xf0,0x02,0x00
|
||||
};
|
889
depthrush/kiero/minhook/src/hook.c
Normal file
889
depthrush/kiero/minhook/src/hook.c
Normal file
@ -0,0 +1,889 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../include/MinHook.h"
|
||||
#include "buffer.h"
|
||||
#include "trampoline.h"
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
// Initial capacity of the HOOK_ENTRY buffer.
|
||||
#define INITIAL_HOOK_CAPACITY 32
|
||||
|
||||
// Initial capacity of the thread IDs buffer.
|
||||
#define INITIAL_THREAD_CAPACITY 128
|
||||
|
||||
// Special hook position values.
|
||||
#define INVALID_HOOK_POS UINT_MAX
|
||||
#define ALL_HOOKS_POS UINT_MAX
|
||||
|
||||
// Freeze() action argument defines.
|
||||
#define ACTION_DISABLE 0
|
||||
#define ACTION_ENABLE 1
|
||||
#define ACTION_APPLY_QUEUED 2
|
||||
|
||||
// Thread access rights for suspending/resuming threads.
|
||||
#define THREAD_ACCESS \
|
||||
(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
|
||||
|
||||
// Hook information.
|
||||
typedef struct _HOOK_ENTRY
|
||||
{
|
||||
LPVOID pTarget; // Address of the target function.
|
||||
LPVOID pDetour; // Address of the detour or relay function.
|
||||
LPVOID pTrampoline; // Address of the trampoline function.
|
||||
UINT8 backup[8]; // Original prologue of the target function.
|
||||
|
||||
UINT8 patchAbove : 1; // Uses the hot patch area.
|
||||
UINT8 isEnabled : 1; // Enabled.
|
||||
UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
|
||||
|
||||
UINT nIP : 4; // Count of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
|
||||
} HOOK_ENTRY, *PHOOK_ENTRY;
|
||||
|
||||
// Suspended threads for Freeze()/Unfreeze().
|
||||
typedef struct _FROZEN_THREADS
|
||||
{
|
||||
LPDWORD pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} FROZEN_THREADS, *PFROZEN_THREADS;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
|
||||
volatile LONG g_isLocked = FALSE;
|
||||
|
||||
// Private heap handle. If not NULL, this library is initialized.
|
||||
HANDLE g_hHeap = NULL;
|
||||
|
||||
// Hook entries.
|
||||
struct
|
||||
{
|
||||
PHOOK_ENTRY pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} g_hooks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns INVALID_HOOK_POS if not found.
|
||||
static UINT FindHookEntry(LPVOID pTarget)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
|
||||
return i;
|
||||
}
|
||||
|
||||
return INVALID_HOOK_POS;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PHOOK_ENTRY AddHookEntry()
|
||||
{
|
||||
if (g_hooks.pItems == NULL)
|
||||
{
|
||||
g_hooks.capacity = INITIAL_HOOK_CAPACITY;
|
||||
g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
|
||||
g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
|
||||
if (g_hooks.pItems == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else if (g_hooks.size >= g_hooks.capacity)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
g_hooks.capacity *= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
|
||||
return &g_hooks.pItems[g_hooks.size++];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static void DeleteHookEntry(UINT pos)
|
||||
{
|
||||
if (pos < g_hooks.size - 1)
|
||||
g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
|
||||
|
||||
g_hooks.size--;
|
||||
|
||||
if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
g_hooks.capacity /= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Check relay function.
|
||||
if (ip == (DWORD_PTR)pHook->pDetour)
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
|
||||
{
|
||||
// If the thread suspended in the overwritten area,
|
||||
// move IP to the proper address.
|
||||
|
||||
CONTEXT c;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
DWORD64 *pIP = &c.Rip;
|
||||
#else
|
||||
DWORD *pIP = &c.Eip;
|
||||
#endif
|
||||
UINT count;
|
||||
|
||||
c.ContextFlags = CONTEXT_CONTROL;
|
||||
if (!GetThreadContext(hThread, &c))
|
||||
return;
|
||||
|
||||
if (pos == ALL_HOOKS_POS)
|
||||
{
|
||||
pos = 0;
|
||||
count = g_hooks.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = pos + 1;
|
||||
}
|
||||
|
||||
for (; pos < count; ++pos)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
BOOL enable;
|
||||
DWORD_PTR ip;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_DISABLE:
|
||||
enable = FALSE;
|
||||
break;
|
||||
|
||||
case ACTION_ENABLE:
|
||||
enable = TRUE;
|
||||
break;
|
||||
|
||||
default: // ACTION_APPLY_QUEUED
|
||||
enable = pHook->queueEnable;
|
||||
break;
|
||||
}
|
||||
if (pHook->isEnabled == enable)
|
||||
continue;
|
||||
|
||||
if (enable)
|
||||
ip = FindNewIP(pHook, *pIP);
|
||||
else
|
||||
ip = FindOldIP(pHook, *pIP);
|
||||
|
||||
if (ip != 0)
|
||||
{
|
||||
*pIP = ip;
|
||||
SetThreadContext(hThread, &c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnapshot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
THREADENTRY32 te;
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
if (Thread32First(hSnapshot, &te))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
|
||||
&& te.th32OwnerProcessID == GetCurrentProcessId()
|
||||
&& te.th32ThreadID != GetCurrentThreadId())
|
||||
{
|
||||
if (pThreads->pItems == NULL)
|
||||
{
|
||||
pThreads->capacity = INITIAL_THREAD_CAPACITY;
|
||||
pThreads->pItems
|
||||
= (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
|
||||
if (pThreads->pItems == NULL)
|
||||
break;
|
||||
}
|
||||
else if (pThreads->size >= pThreads->capacity)
|
||||
{
|
||||
LPDWORD p = (LPDWORD)HeapReAlloc(
|
||||
g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
pThreads->capacity *= 2;
|
||||
pThreads->pItems = p;
|
||||
}
|
||||
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
|
||||
}
|
||||
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
} while (Thread32Next(hSnapshot, &te));
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
|
||||
{
|
||||
pThreads->pItems = NULL;
|
||||
pThreads->capacity = 0;
|
||||
pThreads->size = 0;
|
||||
EnumerateThreads(pThreads);
|
||||
|
||||
if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
||||
if (hThread != NULL)
|
||||
{
|
||||
SuspendThread(hThread);
|
||||
ProcessThreadIPs(hThread, pos, action);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID Unfreeze(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
||||
if (hThread != NULL)
|
||||
{
|
||||
ResumeThread(hThread);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(g_hHeap, 0, pThreads->pItems);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
DWORD oldProtect;
|
||||
SIZE_T patchSize = sizeof(JMP_REL);
|
||||
LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
pPatchTarget -= sizeof(JMP_REL);
|
||||
patchSize += sizeof(JMP_REL_SHORT);
|
||||
}
|
||||
|
||||
if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||
return MH_ERROR_MEMORY_PROTECT;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
|
||||
pJmp->opcode = 0xE9;
|
||||
pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
|
||||
pShortJmp->opcode = 0xEB;
|
||||
pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pHook->patchAbove)
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
else
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
|
||||
|
||||
// Just-in-case measure.
|
||||
FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
|
||||
|
||||
pHook->isEnabled = enable;
|
||||
pHook->queueEnable = enable;
|
||||
|
||||
return MH_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableAllHooksLL(BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
|
||||
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
status = EnableHookLL(i, enable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID EnterSpinLock(VOID)
|
||||
{
|
||||
SIZE_T spinCount = 0;
|
||||
|
||||
// Wait until the flag is FALSE.
|
||||
while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedCompareExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
// Prevent the loop from being too busy.
|
||||
if (spinCount < 32)
|
||||
Sleep(0);
|
||||
else
|
||||
Sleep(1);
|
||||
|
||||
spinCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID LeaveSpinLock(VOID)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
InterlockedExchange(&g_isLocked, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Initialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap == NULL)
|
||||
{
|
||||
g_hHeap = HeapCreate(0, 0, 0);
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
// Initialize the internal function buffer.
|
||||
InitializeBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
status = EnableAllHooksLL(FALSE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
// Free the internal function buffer.
|
||||
|
||||
// HeapFree is actually not required, but some tools detect a false
|
||||
// memory leak without HeapFree.
|
||||
|
||||
UninitializeBuffer();
|
||||
|
||||
HeapFree(g_hHeap, 0, g_hooks.pItems);
|
||||
HeapDestroy(g_hHeap);
|
||||
|
||||
g_hHeap = NULL;
|
||||
|
||||
g_hooks.pItems = NULL;
|
||||
g_hooks.capacity = 0;
|
||||
g_hooks.size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos == INVALID_HOOK_POS)
|
||||
{
|
||||
LPVOID pBuffer = AllocateBuffer(pTarget);
|
||||
if (pBuffer != NULL)
|
||||
{
|
||||
TRAMPOLINE ct;
|
||||
|
||||
ct.pTarget = pTarget;
|
||||
ct.pDetour = pDetour;
|
||||
ct.pTrampoline = pBuffer;
|
||||
if (CreateTrampolineFunction(&ct))
|
||||
{
|
||||
PHOOK_ENTRY pHook = AddHookEntry();
|
||||
if (pHook != NULL)
|
||||
{
|
||||
pHook->pTarget = ct.pTarget;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
pHook->pDetour = ct.pRelay;
|
||||
#else
|
||||
pHook->pDetour = ct.pDetour;
|
||||
#endif
|
||||
pHook->pTrampoline = ct.pTrampoline;
|
||||
pHook->patchAbove = ct.patchAbove;
|
||||
pHook->isEnabled = FALSE;
|
||||
pHook->queueEnable = FALSE;
|
||||
pHook->nIP = ct.nIP;
|
||||
memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
|
||||
memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
|
||||
|
||||
// Back up the target function.
|
||||
|
||||
if (ct.patchAbove)
|
||||
{
|
||||
memcpy(
|
||||
pHook->backup,
|
||||
(LPBYTE)pTarget - sizeof(JMP_REL),
|
||||
sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
if (ppOriginal != NULL)
|
||||
*ppOriginal = pHook->pTrampoline;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
if (status != MH_OK)
|
||||
{
|
||||
FreeBuffer(pBuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_EXECUTABLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, pos, ACTION_DISABLE);
|
||||
|
||||
status = EnableHookLL(pos, FALSE);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
|
||||
if (status == MH_OK)
|
||||
{
|
||||
FreeBuffer(g_hooks.pItems[pos].pTrampoline);
|
||||
DeleteHookEntry(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
status = EnableAllHooksLL(enable);
|
||||
}
|
||||
else
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled != enable)
|
||||
{
|
||||
Freeze(&threads, pos, ACTION_ENABLE);
|
||||
|
||||
status = EnableHookLL(pos, enable);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
g_hooks.pItems[i].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
g_hooks.pItems[pos].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
|
||||
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[i];
|
||||
if (pHook->isEnabled != pHook->queueEnable)
|
||||
{
|
||||
status = EnableHookLL(i, pHook->queueEnable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
|
||||
LPVOID *ppOriginal, LPVOID *ppTarget)
|
||||
{
|
||||
HMODULE hModule;
|
||||
LPVOID pTarget;
|
||||
|
||||
hModule = GetModuleHandleW(pszModule);
|
||||
if (hModule == NULL)
|
||||
return MH_ERROR_MODULE_NOT_FOUND;
|
||||
|
||||
pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
|
||||
if (pTarget == NULL)
|
||||
return MH_ERROR_FUNCTION_NOT_FOUND;
|
||||
|
||||
if(ppTarget != NULL)
|
||||
*ppTarget = pTarget;
|
||||
|
||||
return MH_CreateHook(pTarget, pDetour, ppOriginal);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status)
|
||||
{
|
||||
#define MH_ST2STR(x) \
|
||||
case x: \
|
||||
return #x;
|
||||
|
||||
switch (status) {
|
||||
MH_ST2STR(MH_UNKNOWN)
|
||||
MH_ST2STR(MH_OK)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_CREATED)
|
||||
MH_ST2STR(MH_ERROR_NOT_CREATED)
|
||||
MH_ST2STR(MH_ERROR_ENABLED)
|
||||
MH_ST2STR(MH_ERROR_DISABLED)
|
||||
MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
|
||||
MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
|
||||
MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
|
||||
MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
|
||||
}
|
||||
|
||||
#undef MH_ST2STR
|
||||
|
||||
return "(unknown)";
|
||||
}
|
316
depthrush/kiero/minhook/src/trampoline.c
Normal file
316
depthrush/kiero/minhook/src/trampoline.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#include "./hde/hde64.h"
|
||||
typedef hde64s HDE;
|
||||
#define HDE_DISASM(code, hs) hde64_disasm(code, hs)
|
||||
#else
|
||||
#include "./hde/hde32.h"
|
||||
typedef hde32s HDE;
|
||||
#define HDE_DISASM(code, hs) hde32_disasm(code, hs)
|
||||
#endif
|
||||
|
||||
#include "trampoline.h"
|
||||
#include "buffer.h"
|
||||
|
||||
// Maximum size of a trampoline function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
|
||||
#else
|
||||
#define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
|
||||
return FALSE;
|
||||
|
||||
for (i = 1; i < size; ++i)
|
||||
{
|
||||
if (pInst[i] != pInst[0])
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
CALL_ABS call = {
|
||||
0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
|
||||
0xEB, 0x08, // EB 08: JMP +10
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JMP_ABS jmp = {
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JCC_ABS jcc = {
|
||||
0x70, 0x0E, // 7* 0E: J** +16
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
#else
|
||||
CALL_REL call = {
|
||||
0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JMP_REL jmp = {
|
||||
0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JCC_REL jcc = {
|
||||
0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
#endif
|
||||
|
||||
UINT8 oldPos = 0;
|
||||
UINT8 newPos = 0;
|
||||
ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
|
||||
BOOL finished = FALSE; // Is the function completed?
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
UINT8 instBuf[16];
|
||||
#endif
|
||||
|
||||
ct->patchAbove = FALSE;
|
||||
ct->nIP = 0;
|
||||
|
||||
do
|
||||
{
|
||||
HDE hs;
|
||||
UINT copySize;
|
||||
LPVOID pCopySrc;
|
||||
ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
|
||||
ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
|
||||
|
||||
copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
|
||||
if (hs.flags & F_ERROR)
|
||||
return FALSE;
|
||||
|
||||
pCopySrc = (LPVOID)pOldInst;
|
||||
if (oldPos >= sizeof(JMP_REL))
|
||||
{
|
||||
// The trampoline function is long enough.
|
||||
// Complete the function with the jump to the target function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = pOldInst;
|
||||
#else
|
||||
jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
finished = TRUE;
|
||||
}
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
else if ((hs.modrm & 0xC7) == 0x05)
|
||||
{
|
||||
// Instructions using RIP relative addressing. (ModR/M = 00???101B)
|
||||
|
||||
// Modify the RIP relative address.
|
||||
PUINT32 pRelAddr;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memcpy(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#else
|
||||
__movsb(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#endif
|
||||
pCopySrc = instBuf;
|
||||
|
||||
// Relative address is stored at (instruction length - immediate value length - 4).
|
||||
pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
|
||||
*pRelAddr
|
||||
= (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
|
||||
|
||||
// Complete the function if JMP (FF /4).
|
||||
if (hs.opcode == 0xFF && hs.modrm_reg == 4)
|
||||
finished = TRUE;
|
||||
}
|
||||
#endif
|
||||
else if (hs.opcode == 0xE8)
|
||||
{
|
||||
// Direct relative CALL
|
||||
ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
call.address = dest;
|
||||
#else
|
||||
call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
|
||||
#endif
|
||||
pCopySrc = &call;
|
||||
copySize = sizeof(call);
|
||||
}
|
||||
else if ((hs.opcode & 0xFD) == 0xE9)
|
||||
{
|
||||
// Direct relative JMP (EB or E9)
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if (hs.opcode == 0xEB) // isShort jmp
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = dest;
|
||||
#else
|
||||
jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
// Exit the function If it is not in the branch
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xF0) == 0x70
|
||||
|| (hs.opcode & 0xFC) == 0xE0
|
||||
|| (hs.opcode2 & 0xF0) == 0x80)
|
||||
{
|
||||
// Direct relative Jcc
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if ((hs.opcode & 0xF0) == 0x70 // Jcc
|
||||
|| (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else if ((hs.opcode & 0xFC) == 0xE0)
|
||||
{
|
||||
// LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Invert the condition in x64 mode to simplify the conditional jump logic.
|
||||
jcc.opcode = 0x71 ^ cond;
|
||||
jcc.address = dest;
|
||||
#else
|
||||
jcc.opcode1 = 0x80 | cond;
|
||||
jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
|
||||
#endif
|
||||
pCopySrc = &jcc;
|
||||
copySize = sizeof(jcc);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xFE) == 0xC2)
|
||||
{
|
||||
// RET (C2 or C3)
|
||||
|
||||
// Complete the function if not in a branch.
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
|
||||
// Can't alter the instruction length in a branch.
|
||||
if (pOldInst < jmpDest && copySize != hs.len)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function is too large.
|
||||
if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function has too many instructions.
|
||||
if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
|
||||
return FALSE;
|
||||
|
||||
ct->oldIPs[ct->nIP] = oldPos;
|
||||
ct->newIPs[ct->nIP] = newPos;
|
||||
ct->nIP++;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef _MSC_VER
|
||||
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
||||
#else
|
||||
__movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
||||
#endif
|
||||
newPos += copySize;
|
||||
oldPos += hs.len;
|
||||
}
|
||||
while (!finished);
|
||||
|
||||
// Is there enough place for a long jump?
|
||||
if (oldPos < sizeof(JMP_REL)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
|
||||
{
|
||||
// Is there enough place for a short jump?
|
||||
if (oldPos < sizeof(JMP_REL_SHORT)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Can we place the long jump above the function?
|
||||
if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
ct->patchAbove = TRUE;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Create a relay function.
|
||||
jmp.address = (ULONG_PTR)ct->pDetour;
|
||||
|
||||
ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
|
||||
memcpy(ct->pRelay, &jmp, sizeof(jmp));
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
105
depthrush/kiero/minhook/src/trampoline.h
Normal file
105
depthrush/kiero/minhook/src/trampoline.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Structs for writing x86/x64 instructions.
|
||||
|
||||
// 8-bit relative jump.
|
||||
typedef struct _JMP_REL_SHORT
|
||||
{
|
||||
UINT8 opcode; // EB xx: JMP +2+xx
|
||||
UINT8 operand;
|
||||
} JMP_REL_SHORT, *PJMP_REL_SHORT;
|
||||
|
||||
// 32-bit direct relative jump/call.
|
||||
typedef struct _JMP_REL
|
||||
{
|
||||
UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
|
||||
UINT32 operand; // Relative destination address
|
||||
} JMP_REL, *PJMP_REL, CALL_REL;
|
||||
|
||||
// 64-bit indirect absolute jump.
|
||||
typedef struct _JMP_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF25 00000000: JMP [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JMP_ABS, *PJMP_ABS;
|
||||
|
||||
// 64-bit indirect absolute call.
|
||||
typedef struct _CALL_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF15 00000002: CALL [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy0;
|
||||
UINT8 dummy1; // EB 08: JMP +10
|
||||
UINT8 dummy2;
|
||||
UINT64 address; // Absolute destination address
|
||||
} CALL_ABS;
|
||||
|
||||
// 32-bit direct relative conditional jumps.
|
||||
typedef struct _JCC_REL
|
||||
{
|
||||
UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
UINT8 opcode1;
|
||||
UINT32 operand; // Relative destination address
|
||||
} JCC_REL;
|
||||
|
||||
// 64bit indirect absolute conditional jumps that x64 lacks.
|
||||
typedef struct _JCC_ABS
|
||||
{
|
||||
UINT8 opcode; // 7* 0E: J** +16
|
||||
UINT8 dummy0;
|
||||
UINT8 dummy1; // FF25 00000000: JMP [+6]
|
||||
UINT8 dummy2;
|
||||
UINT32 dummy3;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JCC_ABS;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _TRAMPOLINE
|
||||
{
|
||||
LPVOID pTarget; // [In] Address of the target function.
|
||||
LPVOID pDetour; // [In] Address of the detour function.
|
||||
LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
LPVOID pRelay; // [Out] Address of the relay function.
|
||||
#endif
|
||||
BOOL patchAbove; // [Out] Should use the hot patch area?
|
||||
UINT nIP; // [Out] Number of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
|
||||
} TRAMPOLINE, *PTRAMPOLINE;
|
||||
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
|
53
depthrush/main.cpp
Normal file
53
depthrush/main.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "includes.h"
|
||||
#include "drs.h"
|
||||
|
||||
static uintptr_t imageBase;
|
||||
|
||||
inline void safeJMP(injector::memory_pointer_tr at, injector::memory_pointer_raw dest, bool vp = true)
|
||||
{
|
||||
MH_Initialize();
|
||||
MH_CreateHook((void*)at.as_int(), (void*)dest.as_int(), nullptr);
|
||||
MH_EnableHook((void*)at.as_int());
|
||||
}
|
||||
|
||||
inline void safeUNJMP(injector::memory_pointer_tr pTarget) {
|
||||
MH_DisableHook((void*)pTarget.as_int());
|
||||
MH_RemoveHook((void*)pTarget.as_int());
|
||||
}
|
||||
|
||||
static int returnTrue() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int returnFalse() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool init = false;
|
||||
|
||||
/*
|
||||
DWORD WINAPI MainThread(LPVOID lpReserved)
|
||||
{
|
||||
bool init_hook = false;
|
||||
do
|
||||
{
|
||||
|
||||
} while (!init_hook);
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE hMod, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hMod);
|
||||
imageBase = (uintptr_t)GetModuleHandleA(0);
|
||||
drs::hookDancepad();
|
||||
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
Loading…
Reference in New Issue
Block a user