Full Code of MiroKaku/DetoursX for AI

main b2466f0ee27f cached
36 files
572.4 KB
161.2k tokens
519 symbols
1 requests
Download .txt
Showing preview only (593K chars total). Download the full file or copy to clipboard to get everything.
Repository: MiroKaku/DetoursX
Branch: main
Commit: b2466f0ee27f
Files: 36
Total size: 572.4 KB

Directory structure:
gitextract_reyt6s3d/

├── .gitignore
├── BuildAllTargets.cmd
├── BuildAllTargets.proj
├── Detours/
│   ├── api_thunks.cpp
│   ├── api_thunks.h
│   ├── creatwth.cpp
│   ├── detours.cpp
│   ├── detours.h
│   ├── detoursx.cpp
│   ├── detver.h
│   ├── disasm.cpp
│   ├── disolarm.cpp
│   ├── disolarm64.cpp
│   ├── disolia64.cpp
│   ├── disolx64.cpp
│   ├── disolx86.cpp
│   ├── image.cpp
│   ├── modules.cpp
│   └── uimports.cpp
├── Detours.StaticLibrary/
│   └── Detours.StaticLibrary.vcxproj
├── Detours.StaticLibraryForDriver/
│   └── Detours.StaticLibraryForDriver.vcxproj
├── Detours.Test/
│   ├── Detours.Test.vcxproj
│   ├── Main.cpp
│   └── Module.def
├── Detours.TestForDriver/
│   ├── Detours.TestForDriver.inf
│   ├── Detours.TestForDriver.vcxproj
│   └── Main.cpp
├── DetoursX.slnx
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.Cpp.props
├── InitializeVisualStudioEnvironment.cmd
├── LICENSE
├── README.md
├── README.zh-CN.md
└── global.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
.xmake/
vsxmake*/
vs20*/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/


================================================
FILE: BuildAllTargets.cmd
================================================
@setlocal
@echo off

rem Change to the current folder.
cd "%~dp0"

rem Remove the output folder for a fresh compile.
rd /s /q Output

rem Initialize Visual Studio environment
call "%~dp0InitializeVisualStudioEnvironment.cmd"

rem Build all targets
MSBuild -binaryLogger:Output\BuildAllTargets.binlog -m BuildAllTargets.proj

@endlocal

================================================
FILE: BuildAllTargets.proj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project 
  DefaultTargets="Restore;Build"
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <SolutionPath>$(MSBuildThisFileDirectory)*.slnx</SolutionPath>
  </PropertyGroup>
  <ItemGroup>
    <!--
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Debug;Platform=x86</AdditionalProperties>   
    </ProjectReference>
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Release;Platform=x86</AdditionalProperties>   
    </ProjectReference>
    -->
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Debug;Platform=x64</AdditionalProperties>   
    </ProjectReference>
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Release;Platform=x64</AdditionalProperties>   
    </ProjectReference>
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Debug;Platform=ARM64</AdditionalProperties>   
    </ProjectReference>
    <ProjectReference Include="$(SolutionPath)">
      <AdditionalProperties>Configuration=Release;Platform=ARM64</AdditionalProperties>   
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <!-- <PackagingProjectReference Include="$(MSBuildThisFileDirectory)Mile.Project.Windows\Mile.Project.NuGetPackaging.proj">
      <AdditionalProperties>NuspecFile=$(MSBuildThisFileDirectory)SampleProject\SampleProject.nuspec</AdditionalProperties>   
    </PackagingProjectReference> -->
  </ItemGroup>
  <Target Name="Restore" >
    <MSBuild
      Projects="@(ProjectReference)"
      Targets="Restore"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
    <MSBuild
      Projects="@(PackagingProjectReference)"
      Targets="Restore"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
  </Target>
  <Target Name="Build" >
    <MSBuild
      Projects="@(ProjectReference)"
      Targets="Build"
      BuildInParallel="True"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
    <MSBuild
      Projects="@(PackagingProjectReference)"
      Targets="Build"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
  </Target>
  <Target Name="Rebuild" >
    <MSBuild
      Projects="@(ProjectReference)"
      Targets="Rebuild"
      BuildInParallel="True"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
    <MSBuild
      Projects="@(PackagingProjectReference)"
      Targets="Rebuild"
      StopOnFirstFailure="True"
      Properties="PreferredToolArchitecture=x64" />
  </Target>
</Project>

================================================
FILE: Detours/api_thunks.cpp
================================================
//////////////////////////////////////////////////////////////////////////////
//
//  Detours Disassembler (disasm.cpp of detours.lib)
//
//  Microsoft Research Detours Package, Version 4.0.1
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//

//////////////////////////////////////////////////////////////////////////////
//

#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable:4091) // empty typedef
#endif

#if defined(_KERNEL_MODE)
#define DETOURS_KERNEL
#endif

#include <Veil.h>

#ifdef DETOURS_KERNEL

namespace Detours::Thunks
{

//////////////////////////////////////////////////////////////////////////////
//

// Zw

NTSTATUS NTAPI ZwReadVirtualMemory(
    _In_ HANDLE ProcessHandle,
    _In_opt_ PVOID BaseAddress,
    _Out_writes_bytes_(BufferSize) PVOID Buffer,
    _In_ SIZE_T BufferSize,
    _Out_opt_ PSIZE_T NumberOfBytesRead
)
{
    SIZE_T BytesCopied = 0u;
    KPROCESSOR_MODE PreviousMode = KernelMode;
    PEPROCESS Process = NULL;
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PETHREAD CurrentThread = NULL;

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread();

    //
    // If the buffer size is not zero, then attempt to read data from the
    // specified process address space into the current process address
    // space.
    //

    BytesCopied = 0;
    Status = STATUS_SUCCESS;
    if (BufferSize != 0) {

        //
        // Reference the target process.
        //

        Status = ObReferenceObjectByHandle(
            ProcessHandle,
            PROCESS_VM_READ,
            *PsProcessType,
            PreviousMode,
            (PVOID*)&Process,
            NULL);

        //
        // If the process was successfully referenced, then attempt to
        // read the specified memory either by direct mapping or copying
        // through nonpaged pool.
        //

        if (Status == STATUS_SUCCESS) {

            Status = MmCopyVirtualMemory(
                Process,
                BaseAddress,
                PsGetThreadProcess(CurrentThread),
                Buffer,
                BufferSize,
                PreviousMode,
                &BytesCopied);

            //
            // Dereference the target process.
            //

            ObDereferenceObject(Process);
        }
    }

    //
    // If requested, return the number of bytes read.
    //

    if (ARGUMENT_PRESENT(NumberOfBytesRead)) {
        __try {
            *NumberOfBytesRead = BytesCopied;

        } __except(EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }
    }

    return Status;
}

NTSTATUS NTAPI ZwWriteVirtualMemory(
    _In_ HANDLE ProcessHandle,
    _In_opt_ PVOID BaseAddress,
    _In_reads_bytes_(BufferSize) PVOID Buffer,
    _In_ SIZE_T BufferSize,
    _Out_opt_ PSIZE_T NumberOfBytesWritten
)
{
    SIZE_T BytesCopied = 0u;
    KPROCESSOR_MODE PreviousMode = KernelMode;
    PEPROCESS Process = NULL;
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PETHREAD CurrentThread = NULL;

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread();

    //
    // If the buffer size is not zero, then attempt to write data from the
    // current process address space into the target process address space.
    //

    BytesCopied = 0;
    Status = STATUS_SUCCESS;
    if (BufferSize != 0) {

        //
        // Reference the target process.
        //

        Status = ObReferenceObjectByHandle(
            ProcessHandle,
            PROCESS_VM_WRITE,
            *PsProcessType,
            PreviousMode,
            (PVOID*)&Process,
            NULL);

        //
        // If the process was successfully referenced, then attempt to
        // write the specified memory either by direct mapping or copying
        // through nonpaged pool.
        //

        if (Status == STATUS_SUCCESS) {

            Status = MmCopyVirtualMemory(
                PsGetThreadProcess(CurrentThread),
                Buffer,
                Process,
                BaseAddress,
                BufferSize,
                PreviousMode,
                &BytesCopied);

            //
            // Dereference the target process.
            //

            ObDereferenceObject(Process);
        }
    }

    //
    // If requested, return the number of bytes read.
    //

    if (ARGUMENT_PRESENT(NumberOfBytesWritten)) {
        __try {
            *NumberOfBytesWritten = BytesCopied;

        } __except(EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }
    }

    return Status;
}

//////////////////////////////////////////////////////////////////////////////
//

// Set/Get Last Error

static DWORD __Win32Error = NO_ERROR;

VOID WINAPI SetLastError(_In_ DWORD Win32Error)
{
    __Win32Error = Win32Error;
}

DWORD WINAPI GetLastError(VOID)
{
    return __Win32Error;
}


//////////////////////////////////////////////////////////////////////////////
//

// Process & Thread

HANDLE WINAPI GetCurrentProcess(VOID)
{
    return ZwCurrentProcess();
}

HANDLE WINAPI GetCurrentThread(VOID)
{
    return ZwCurrentThread();
}

DWORD WINAPI GetCurrentProcessId(VOID)
{
    return (DWORD)(ULONG_PTR)PsGetCurrentProcessId();
}

DWORD WINAPI GetCurrentThreadId(VOID)
{
    return (DWORD)(ULONG_PTR)PsGetCurrentThreadId();
}

BOOL WINAPI IsWow64Process(
    _In_ HANDLE hProcess,
    _Out_ PBOOL Wow64Process
)
{
    NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
    ULONG_PTR Peb32 = 0u;

    NtStatus = ZwQueryInformationProcess(
        hProcess,
        ProcessWow64Information,
        &Peb32,
        sizeof(Peb32),
        NULL
    );

    *Wow64Process = FALSE;

    if (!NT_SUCCESS(NtStatus)) {

        SetLastError(NtStatus);
    }
    else {

        if (Peb32 == 0) {
            *Wow64Process = FALSE;
        }
        else {
            *Wow64Process = TRUE;
        }
    }

    return (NT_SUCCESS(NtStatus));
}

_Success_(return != FALSE)
BOOL WINAPI ReadProcessMemory(
    _In_ HANDLE hProcess,
    _In_ LPCVOID lpBaseAddress,
    _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer,
    _In_ SIZE_T nSize,
    _Out_opt_ SIZE_T * lpNumberOfBytesRead
)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    SIZE_T NtNumberOfBytesRead = 0u;

    Status = ZwReadVirtualMemory(
        hProcess,
        (PVOID)lpBaseAddress,
        lpBuffer,
        nSize,
        &NtNumberOfBytesRead
    );

    if (lpNumberOfBytesRead != NULL) {
        *lpNumberOfBytesRead = NtNumberOfBytesRead;
    }

    if (!NT_SUCCESS(Status)) {
        SetLastError(Status);
        return FALSE;
    }
    else {
        return TRUE;
    }
}

_Success_(return != FALSE)
BOOL WINAPI WriteProcessMemory(
    _In_ HANDLE hProcess,
    _In_ LPVOID lpBaseAddress,
    _In_reads_bytes_(nSize) LPCVOID lpBuffer,
    _In_ SIZE_T nSize,
    _Out_opt_ SIZE_T * lpNumberOfBytesWritten
)
{
    NTSTATUS Status;
    ULONG OldProtect = PAGE_READWRITE;
    SIZE_T RegionSize;
    PVOID Base;
    SIZE_T NtNumberOfBytesWritten = 0u;

    //
    // Set the protection to allow writes
    //

    RegionSize = nSize;
    Base = lpBaseAddress;
    Status = ZwProtectVirtualMemory(
        hProcess,
        &Base,
        &RegionSize,
        PAGE_READWRITE,
        &OldProtect
    );
    if (NT_SUCCESS(Status)) {

        //
        // See if previous protection was writable. If so,
        // then reset protection and do the write.
        // Otherwise, see if previous protection was read-only or
        // no access. In this case, don't do the write, just fail
        //

        if ((OldProtect & PAGE_READWRITE) == PAGE_READWRITE ||
            (OldProtect & PAGE_WRITECOPY) == PAGE_WRITECOPY ||
            (OldProtect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE ||
            (OldProtect & PAGE_EXECUTE_WRITECOPY) == PAGE_EXECUTE_WRITECOPY) {

            (void)ZwProtectVirtualMemory(
                hProcess,
                &Base,
                &RegionSize,
                OldProtect,
                &OldProtect
            );
            Status = ZwWriteVirtualMemory(
                hProcess,
                lpBaseAddress,
                (PVOID)lpBuffer,
                nSize,
                &NtNumberOfBytesWritten
            );

            if (lpNumberOfBytesWritten != NULL) {
                *lpNumberOfBytesWritten = NtNumberOfBytesWritten;
            }

            if (!NT_SUCCESS(Status)) {
                SetLastError(Status);
                return FALSE;
            }
            ZwFlushInstructionCache(hProcess, lpBaseAddress, nSize);
            return TRUE;
        }
        else {

            //
            // See if the previous protection was read only or no access. If
            // this is the case, restore the previous protection and return
            // an access violation error.
            //
            if ((OldProtect & PAGE_NOACCESS) == PAGE_NOACCESS ||
                (OldProtect & PAGE_READONLY) == PAGE_READONLY) {

                (void)ZwProtectVirtualMemory(
                    hProcess,
                    &Base,
                    &RegionSize,
                    OldProtect,
                    &OldProtect
                );
                SetLastError((DWORD)STATUS_ACCESS_VIOLATION);
                return FALSE;
            }
            else {

                //
                // The previous protection must have been code and the caller
                // is trying to set a breakpoint or edit the code. Do the write
                // and then restore the previous protection.
                //

                Status = ZwWriteVirtualMemory(
                    hProcess,
                    lpBaseAddress,
                    (PVOID)lpBuffer,
                    nSize,
                    &NtNumberOfBytesWritten
                );

                if (lpNumberOfBytesWritten != NULL) {
                    *lpNumberOfBytesWritten = NtNumberOfBytesWritten;
                }

                (void)ZwProtectVirtualMemory(
                    hProcess,
                    &Base,
                    &RegionSize,
                    OldProtect,
                    &OldProtect
                );
                if (!NT_SUCCESS(Status)) {
                    SetLastError((DWORD)STATUS_ACCESS_VIOLATION);
                    return FALSE;
                }
                (void)ZwFlushInstructionCache(hProcess, lpBaseAddress, nSize);
                return TRUE;
            }
        }
    }
    else {
        SetLastError(Status);
        return FALSE;
    }
}

_Ret_maybenull_
_Post_writable_byte_size_(dwSize)
LPVOID WINAPI VirtualAllocEx(
    _In_ HANDLE hProcess,
    _In_opt_ LPVOID lpAddress,
    _In_ SIZE_T dwSize,
    _In_ DWORD flAllocationType,
    _In_ DWORD flProtect
)
{
    NTSTATUS Status;

    __try {
        Status = NtAllocateVirtualMemory(hProcess,
            &lpAddress,
            0,
            &dwSize,
            flAllocationType,
            flProtect
        );
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
    }

    if (NT_SUCCESS(Status)) {
        return(lpAddress);
    }

    SetLastError(Status);
    return NULL;
}

BOOL WINAPI VirtualFreeEx(
    _In_ HANDLE hProcess,
    _Pre_notnull_ _When_(dwFreeType == MEM_DECOMMIT, _Post_invalid_) _When_(dwFreeType == MEM_RELEASE, _Post_ptr_invalid_) LPVOID lpAddress,
    _In_ SIZE_T dwSize,
    _In_ DWORD dwFreeType
)
{
    NTSTATUS Status;

    if ((dwFreeType & MEM_RELEASE) && dwSize != 0) {
        SetLastError((DWORD)STATUS_INVALID_PARAMETER);
        return FALSE;
    }

    Status = NtFreeVirtualMemory(
        hProcess,
        &lpAddress,
        &dwSize,
        dwFreeType
    );

    if (NT_SUCCESS(Status)) {
        return(TRUE);
    }

    SetLastError(Status);
    return FALSE;
}

_Success_(return != FALSE)
BOOL WINAPI VirtualProtectEx(
    _In_ HANDLE hProcess,
    _In_ LPVOID lpAddress,
    _In_ SIZE_T dwSize,
    _In_ DWORD flNewProtect,
    _Out_ PDWORD lpflOldProtect)
{
    NTSTATUS Status;

    Status = ZwProtectVirtualMemory(
        hProcess,
        &lpAddress,
        &dwSize,
        flNewProtect,
        lpflOldProtect);

    if (NT_SUCCESS(Status)) {
        return(TRUE);
    }

    SetLastError(Status);
    return FALSE;
}

SIZE_T WINAPI VirtualQueryEx(
    _In_ HANDLE hProcess,
    _In_opt_ LPCVOID lpAddress,
    _Out_writes_bytes_to_(dwLength, return) PMEMORY_BASIC_INFORMATION lpBuffer,
    _In_ SIZE_T dwLength)
{
    NTSTATUS Status;
    SIZE_T ReturnLength = 0u;

    Status = ZwQueryVirtualMemory(
        hProcess,
        (LPVOID)lpAddress,
        MemoryBasicInformation,
        (PMEMORY_BASIC_INFORMATION)lpBuffer,
        dwLength,
        &ReturnLength);
    if (NT_SUCCESS(Status))
    {
        return(ReturnLength);
    }

    SetLastError(Status);
    return 0;
}

}

#endif // DETOURS_KERNEL


================================================
FILE: Detours/api_thunks.h
================================================
#pragma once

namespace Detours::Thunks
{
    VOID WINAPI SetLastError(_In_ DWORD Win32Error);
    DWORD WINAPI GetLastError(VOID);

    HANDLE WINAPI GetCurrentProcess(VOID);
    HANDLE WINAPI GetCurrentThread(VOID);
    DWORD WINAPI GetCurrentProcessId(VOID);
    DWORD WINAPI GetCurrentThreadId(VOID);

    BOOL WINAPI IsWow64Process(
        _In_ HANDLE hProcess,
        _Out_ PBOOL Wow64Process
    );

    BOOL WINAPI ReadProcessMemory(
        _In_ HANDLE hProcess,
        _In_ LPCVOID lpBaseAddress,
        _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer,
        _In_ SIZE_T nSize,
        _Out_opt_ SIZE_T * lpNumberOfBytesRead
    );

    BOOL WINAPI WriteProcessMemory(
        _In_ HANDLE hProcess,
        _In_ LPVOID lpBaseAddress,
        _In_reads_bytes_(nSize) LPCVOID lpBuffer,
        _In_ SIZE_T nSize,
        _Out_opt_ SIZE_T* lpNumberOfBytesWritten
    );

    LPVOID WINAPI VirtualAllocEx(
        _In_ HANDLE hProcess,
        _In_opt_ LPVOID lpAddress,
        _In_ SIZE_T dwSize,
        _In_ DWORD flAllocationType,
        _In_ DWORD flProtect
    );

    BOOL WINAPI VirtualFreeEx(
        _In_ HANDLE hProcess,
        _Pre_notnull_ _When_(dwFreeType == MEM_DECOMMIT, _Post_invalid_) _When_(dwFreeType == MEM_RELEASE, _Post_ptr_invalid_) LPVOID lpAddress,
        _In_ SIZE_T dwSize,
        _In_ DWORD dwFreeType
    );

    BOOL WINAPI VirtualProtectEx(
        _In_ HANDLE hProcess,
        _In_ LPVOID lpAddress,
        _In_ SIZE_T dwSize,
        _In_ DWORD flNewProtect,
        _Out_ PDWORD lpflOldProtect
    );

    SIZE_T WINAPI VirtualQueryEx(
        _In_ HANDLE hProcess,
        _In_opt_ LPCVOID lpAddress,
        _Out_writes_bytes_to_(dwLength, return) PMEMORY_BASIC_INFORMATION lpBuffer,
        _In_ SIZE_T dwLength
    );

}

#define SetLastError ::Detours::Thunks::SetLastError
#define GetLastError ::Detours::Thunks::GetLastError

#define GetCurrentProcess ::Detours::Thunks::GetCurrentProcess
#define GetCurrentThread ::Detours::Thunks::GetCurrentThread
#define GetCurrentProcessId ::Detours::Thunks::GetCurrentProcessId
#define GetCurrentThreadId ::Detours::Thunks::GetCurrentThreadId

#define IsWow64Process ::Detours::Thunks::IsWow64Process

#define ReadProcessMemory ::Detours::Thunks::ReadProcessMemory
#define WriteProcessMemory ::Detours::Thunks::WriteProcessMemory

#define VirtualAllocEx ::Detours::Thunks::VirtualAllocEx
#define VirtualFreeEx ::Detours::Thunks::VirtualFreeEx
#define VirtualProtectEx ::Detours::Thunks::VirtualProtectEx
#define VirtualQueryEx ::Detours::Thunks::VirtualQueryEx


================================================
FILE: Detours/creatwth.cpp
================================================
//////////////////////////////////////////////////////////////////////////////
//
//  Create a process with a DLL (creatwth.cpp of detours.lib)
//
//  Microsoft Research Detours Package, Version 4.0.1
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//

#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable:4091) // empty typedef
#endif

#if defined(_KERNEL_MODE)
#define DETOURS_KERNEL
#endif

#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1
#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1

#include <Veil.h>

#ifdef DETOURS_KERNEL
#include "api_thunks.h"
#endif

#include <stddef.h>
#pragma warning(push)
#if _MSC_VER > 1400
#pragma warning(disable:6102 6103) // /analyze warnings
#endif
#include <strsafe.h>
#pragma warning(pop)

// #define DETOUR_DEBUG 1
#define DETOURS_INTERNAL

#include "detours.h"

#if DETOURS_VERSION != 0x4c0c1   // 0xMAJORcMINORcPATCH
#error detours.h version mismatch
#endif

#if _MSC_VER >= 1900
#pragma warning(pop)
#endif

#define IMPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
#define BOUND_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
#define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
#define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]

//////////////////////////////////////////////////////////////////////////////
//
const GUID DETOUR_EXE_RESTORE_GUID = {
    0x2ed7a3ff, 0x3339, 0x4a8d,
    { 0x80, 0x5c, 0xd4, 0x98, 0x15, 0x3f, 0xc2, 0x8f } };

const GUID DETOUR_EXE_HELPER_GUID = { /* ea0251b9-5cde-41b5-98d0-2af4a26b0fee */
    0xea0251b9, 0x5cde, 0x41b5,
    { 0x98, 0xd0, 0x2a, 0xf4, 0xa2, 0x6b, 0x0f, 0xee }};

//////////////////////////////////////////////////////////////////////////////
//
// Enumate through modules in the target process.
//
static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess,
                                           HMODULE hModule,
                                           PIMAGE_NT_HEADERS32 pNtHeader)
{
    PBYTE pbModule = (PBYTE)hModule;

    if (pbModule == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    MEMORY_BASIC_INFORMATION mbi;
    ZeroMemory(&mbi, sizeof(mbi));

    if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) {
        return FALSE;
    }

    IMAGE_DOS_HEADER idh;

    if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
                      pbModule, pbModule + sizeof(idh), GetLastError()));
        return FALSE;
    }

    if (idh.e_magic != IMAGE_DOS_SIGNATURE ||
        (DWORD)idh.e_lfanew > mbi.RegionSize ||
        (DWORD)idh.e_lfanew < sizeof(idh)) {

        SetLastError(ERROR_BAD_EXE_FORMAT);
        return FALSE;
    }

    if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew,
                           pNtHeader, sizeof(*pNtHeader), NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %lu\n",
                      pbModule + idh.e_lfanew,
                      pbModule + idh.e_lfanew + sizeof(*pNtHeader),
                      pbModule,
                      GetLastError()));
        return FALSE;
    }

    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return FALSE;
    }

    return TRUE;
}

static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess,
                                                HMODULE hModuleLast,
                                                PIMAGE_NT_HEADERS32 pNtHeader)
{
    PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;

    MEMORY_BASIC_INFORMATION mbi;
    ZeroMemory(&mbi, sizeof(mbi));

    // Find the next memory region that contains a mapped PE image.
    //

    for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
        if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) {
            break;
        }

        // Usermode address space has such an unaligned region size always at the
        // end and only at the end.
        //
        if ((mbi.RegionSize & 0xfff) == 0xfff) {
            break;
        }
        if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) {
            break;
        }

        // Skip uncommitted regions and guard pages.
        //
        if ((mbi.State != MEM_COMMIT) ||
            ((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
            (mbi.Protect & PAGE_GUARD)) {
            continue;
        }

        if (LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader)) {
            return (HMODULE)pbLast;
        }
    }
    return NULL;
}

//////////////////////////////////////////////////////////////////////////////
//
// Find a region of memory in which we can create a replacement import table.
//
static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbBase, DWORD cbAlloc)
{
    MEMORY_BASIC_INFORMATION mbi;
    ZeroMemory(&mbi, sizeof(mbi));

    PBYTE pbLast = pbBase;
    for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {

        ZeroMemory(&mbi, sizeof(mbi));
        if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) {
            if (GetLastError() == ERROR_INVALID_PARAMETER) {
                break;
            }
            DETOUR_TRACE(("VirtualQueryEx(%p) failed: %lu\n",
                          pbLast, GetLastError()));
            break;
        }
        // Usermode address space has such an unaligned region size always at the
        // end and only at the end.
        //
        if ((mbi.RegionSize & 0xfff) == 0xfff) {
            break;
        }

        // Skip anything other than a pure free region.
        //
        if (mbi.State != MEM_FREE) {
            continue;
        }

        PBYTE pbAddress = (PBYTE)(((DWORD_PTR)mbi.BaseAddress + 0xffff) & ~(DWORD_PTR)0xffff);

#ifdef _WIN64
        // The distance from pbBase to pbAddress must fit in 32 bits.
        //
        const size_t GB4 = ((((size_t)1) << 32) - 1);
        if ((size_t)(pbAddress - pbBase) > GB4) {
            DETOUR_TRACE(("FindAndAllocateNearBase(1) failing due to distance >4GB %p\n", pbAddress));
            return NULL;
        }
#endif

        DETOUR_TRACE(("Free region %p..%p\n",
                      mbi.BaseAddress,
                      (PBYTE)mbi.BaseAddress + mbi.RegionSize));

        for (; pbAddress < (PBYTE)mbi.BaseAddress + mbi.RegionSize; pbAddress += MM_ALLOCATION_GRANULARITY) {
            PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
                                                  MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            if (pbAlloc == NULL) {
                DETOUR_TRACE(("VirtualAllocEx(%p) failed: %lu\n", pbAddress, GetLastError()));
                continue;
            }
#ifdef _WIN64
            // The distance from pbBase to pbAddress must fit in 32 bits.
            //
            if ((size_t)(pbAddress - pbBase) > GB4) {
                DETOUR_TRACE(("FindAndAllocateNearBase(2) failing due to distance >4GB %p\n", pbAddress));
                return NULL;
            }
#endif
            DETOUR_TRACE(("[%p..%p] Allocated for import table.\n",
                          pbAlloc, pbAlloc + cbAlloc));
            return pbAlloc;
        }
    }
    return NULL;
}

static inline DWORD PadToDword(DWORD dw)
{
    return (dw + 3) & ~3u;
}

static inline DWORD PadToDwordPtr(DWORD dw)
{
    return (dw + 7) & ~7u;
}

static inline HRESULT ReplaceOptionalSizeA(_Inout_z_count_(cchDest) LPSTR pszDest,
                                           _In_ size_t cchDest,
                                           _In_z_ LPCSTR pszSize)
{
    if (cchDest == 0 || pszDest == NULL || pszSize == NULL ||
        pszSize[0] == '\0' || pszSize[1] == '\0' || pszSize[2] != '\0') {

        // can not write into empty buffer or with string other than two chars.
        return ERROR_INVALID_PARAMETER;
    }

    for (; cchDest >= 2; cchDest--, pszDest++) {
        if (pszDest[0] == '?' && pszDest[1] == '?') {
            pszDest[0] = pszSize[0];
            pszDest[1] = pszSize[1];
            break;
        }
    }

    return S_OK;
}

static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTORE& der)
{
    // Save the various headers for DetourRestoreAfterWith.
    ZeroMemory(&der, sizeof(der));
    der.cb = sizeof(der);

    der.pidh = (PBYTE)hModule;
    der.cbidh = sizeof(der.idh);
    if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
                      der.pidh, der.pidh + der.cbidh, GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("IDH: %p..%p\n", der.pidh, der.pidh + der.cbidh));

    // We read the NT header in two passes to get the full size.
    // First we read just the Signature and FileHeader.
    der.pinh = der.pidh + der.idh.e_lfanew;
    der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader);
    if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
                      der.pinh, der.pinh + der.cbinh, GetLastError()));
        return FALSE;
    }

    // Second we read the OptionalHeader and Section headers.
    der.cbinh = (FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
                 der.inh.FileHeader.SizeOfOptionalHeader +
                 der.inh.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));

    if (der.cbinh > sizeof(der.raw)) {
        return FALSE;
    }

    if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
                      der.pinh, der.pinh + der.cbinh, GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("INH: %p..%p\n", der.pinh, der.pinh + der.cbinh));

    // Third, we read the CLR header

    if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
        if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 &&
            der.inh32.CLR_DIRECTORY.Size != 0) {

            DETOUR_TRACE(("CLR32.VirtAddr=%lx, CLR.Size=%lx\n",
                          der.inh32.CLR_DIRECTORY.VirtualAddress,
                          der.inh32.CLR_DIRECTORY.Size));

            der.pclr = ((PBYTE)hModule) + der.inh32.CLR_DIRECTORY.VirtualAddress;
        }
    }
    else if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
        if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 &&
            der.inh64.CLR_DIRECTORY.Size != 0) {

            DETOUR_TRACE(("CLR64.VirtAddr=%lx, CLR.Size=%lx\n",
                          der.inh64.CLR_DIRECTORY.VirtualAddress,
                          der.inh64.CLR_DIRECTORY.Size));

            der.pclr = ((PBYTE)hModule) + der.inh64.CLR_DIRECTORY.VirtualAddress;
        }
    }

    if (der.pclr != 0) {
        der.cbclr = sizeof(der.clr);
        if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) {
            DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %lu\n",
                          der.pclr, der.pclr + der.cbclr, GetLastError()));
            return FALSE;
        }
        DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));
    }

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
#if DETOURS_32BIT
#define DWORD_XX                        DWORD32
#define IMAGE_NT_HEADERS_XX             IMAGE_NT_HEADERS32
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX  IMAGE_NT_OPTIONAL_HDR32_MAGIC
#define IMAGE_ORDINAL_FLAG_XX           IMAGE_ORDINAL_FLAG32
#define UPDATE_IMPORTS_XX               UpdateImports32
#define DETOURS_BITS_XX                 32
#include "uimports.cpp"
#undef DETOUR_EXE_RESTORE_FIELD_XX
#undef DWORD_XX
#undef IMAGE_NT_HEADERS_XX
#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX
#undef IMAGE_ORDINAL_FLAG_XX
#undef UPDATE_IMPORTS_XX
#endif // DETOURS_32BIT

#if DETOURS_64BIT
#define DWORD_XX                        DWORD64
#define IMAGE_NT_HEADERS_XX             IMAGE_NT_HEADERS64
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX  IMAGE_NT_OPTIONAL_HDR64_MAGIC
#define IMAGE_ORDINAL_FLAG_XX           IMAGE_ORDINAL_FLAG64
#define UPDATE_IMPORTS_XX               UpdateImports64
#define DETOURS_BITS_XX                 64
#include "uimports.cpp"
#undef DETOUR_EXE_RESTORE_FIELD_XX
#undef DWORD_XX
#undef IMAGE_NT_HEADERS_XX
#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX
#undef IMAGE_ORDINAL_FLAG_XX
#undef UPDATE_IMPORTS_XX
#endif // DETOURS_64BIT

//////////////////////////////////////////////////////////////////////////////
//
#if DETOURS_64BIT

C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == sizeof(IMAGE_NT_HEADERS32) + 16);

static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
                             DETOUR_EXE_RESTORE& der)
{
    IMAGE_DOS_HEADER idh;
    IMAGE_NT_HEADERS32 inh32;
    IMAGE_NT_HEADERS64 inh64;
    IMAGE_SECTION_HEADER sects[32];
    PBYTE pbModule = (PBYTE)hModule;
    DWORD n;

    ZeroMemory(&inh32, sizeof(inh32));
    ZeroMemory(&inh64, sizeof(inh64));
    ZeroMemory(sects, sizeof(sects));

    DETOUR_TRACE(("UpdateFrom32To64(%04x)\n", machine));
    //////////////////////////////////////////////////////// Read old headers.
    //
    if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
                      pbModule, pbModule + sizeof(idh), GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p)\n",
                  pbModule, pbModule + sizeof(idh)));

    PBYTE pnh = pbModule + idh.e_lfanew;
    if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
                      pnh, pnh + sizeof(inh32), GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh32)));

    if (inh32.FileHeader.NumberOfSections > (sizeof(sects)/sizeof(sects[0]))) {
        return FALSE;
    }

    PBYTE psects = pnh +
        FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
        inh32.FileHeader.SizeOfOptionalHeader;
    ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    if (!ReadProcessMemory(hProcess, psects, &sects, cb, NULL)) {
        DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
                      psects, psects + cb, GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p)\n", psects, psects + cb));

    ////////////////////////////////////////////////////////// Convert header.
    //
    inh64.Signature = inh32.Signature;
    inh64.FileHeader = inh32.FileHeader;
    inh64.FileHeader.Machine = machine;
    inh64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);

    inh64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    inh64.OptionalHeader.MajorLinkerVersion = inh32.OptionalHeader.MajorLinkerVersion;
    inh64.OptionalHeader.MinorLinkerVersion = inh32.OptionalHeader.MinorLinkerVersion;
    inh64.OptionalHeader.SizeOfCode = inh32.OptionalHeader.SizeOfCode;
    inh64.OptionalHeader.SizeOfInitializedData = inh32.OptionalHeader.SizeOfInitializedData;
    inh64.OptionalHeader.SizeOfUninitializedData = inh32.OptionalHeader.SizeOfUninitializedData;
    inh64.OptionalHeader.AddressOfEntryPoint = inh32.OptionalHeader.AddressOfEntryPoint;
    inh64.OptionalHeader.BaseOfCode = inh32.OptionalHeader.BaseOfCode;
    inh64.OptionalHeader.ImageBase = inh32.OptionalHeader.ImageBase;
    inh64.OptionalHeader.SectionAlignment = inh32.OptionalHeader.SectionAlignment;
    inh64.OptionalHeader.FileAlignment = inh32.OptionalHeader.FileAlignment;
    inh64.OptionalHeader.MajorOperatingSystemVersion
        = inh32.OptionalHeader.MajorOperatingSystemVersion;
    inh64.OptionalHeader.MinorOperatingSystemVersion
        = inh32.OptionalHeader.MinorOperatingSystemVersion;
    inh64.OptionalHeader.MajorImageVersion = inh32.OptionalHeader.MajorImageVersion;
    inh64.OptionalHeader.MinorImageVersion = inh32.OptionalHeader.MinorImageVersion;
    inh64.OptionalHeader.MajorSubsystemVersion = inh32.OptionalHeader.MajorSubsystemVersion;
    inh64.OptionalHeader.MinorSubsystemVersion = inh32.OptionalHeader.MinorSubsystemVersion;
    inh64.OptionalHeader.Win32VersionValue = inh32.OptionalHeader.Win32VersionValue;
    inh64.OptionalHeader.SizeOfImage = inh32.OptionalHeader.SizeOfImage;
    inh64.OptionalHeader.SizeOfHeaders = inh32.OptionalHeader.SizeOfHeaders;
    inh64.OptionalHeader.CheckSum = inh32.OptionalHeader.CheckSum;
    inh64.OptionalHeader.Subsystem = inh32.OptionalHeader.Subsystem;
    inh64.OptionalHeader.DllCharacteristics = inh32.OptionalHeader.DllCharacteristics;
    inh64.OptionalHeader.SizeOfStackReserve = inh32.OptionalHeader.SizeOfStackReserve;
    inh64.OptionalHeader.SizeOfStackCommit = inh32.OptionalHeader.SizeOfStackCommit;
    inh64.OptionalHeader.SizeOfHeapReserve = inh32.OptionalHeader.SizeOfHeapReserve;
    inh64.OptionalHeader.SizeOfHeapCommit = inh32.OptionalHeader.SizeOfHeapCommit;
    inh64.OptionalHeader.LoaderFlags = inh32.OptionalHeader.LoaderFlags;
    inh64.OptionalHeader.NumberOfRvaAndSizes = inh32.OptionalHeader.NumberOfRvaAndSizes;
    for (n = 0; n < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; n++) {
        inh64.OptionalHeader.DataDirectory[n] = inh32.OptionalHeader.DataDirectory[n];
    }

    /////////////////////////////////////////////////////// Write new headers.
    //
    DWORD dwProtect = 0;
    if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders,
                                           PAGE_EXECUTE_READWRITE, &dwProtect)) {
        return FALSE;
    }

    if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
        DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
                      pnh, pnh + sizeof(inh64), GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh64)));

    psects = pnh +
        FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
        inh64.FileHeader.SizeOfOptionalHeader;
    cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    if (!WriteProcessMemory(hProcess, psects, &sects, cb, NULL)) {
        DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %lu\n",
                      psects, psects + cb, GetLastError()));
        return FALSE;
    }
    DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p)\n", psects, psects + cb));

    // Record the updated headers.
    if (!RecordExeRestore(hProcess, hModule, der)) {
        return FALSE;
    }

    // Remove the import table.
    if (der.pclr != NULL && (der.clr.Flags & 1)) {
        inh64.IMPORT_DIRECTORY.VirtualAddress = 0;
        inh64.IMPORT_DIRECTORY.Size = 0;

        if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
            DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
                          pnh, pnh + sizeof(inh64), GetLastError()));
            return FALSE;
        }
    }

    DWORD dwOld = 0;
    if (!VirtualProtectEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders,
                          dwProtect, &dwOld)) {
        return FALSE;
    }

    return TRUE;
}
#endif // DETOURS_64BIT

//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
                                       _In_reads_(nDlls) LPCSTR *rlpDlls,
                                       _In_ DWORD nDlls)
{
    // Find the next memory region that contains a mapped PE image.
    //
    BOOL bHas64BitDll = FALSE;
    BOOL bHas32BitExe = FALSE;
    BOOL bIs32BitProcess;
    HMODULE hModule = NULL;
    HMODULE hLast = NULL;

    DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%lu)\n", hProcess, nDlls));

    for (;;) {
        IMAGE_NT_HEADERS32 inh;

        if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh)) == NULL) {
            break;
        }

        DETOUR_TRACE(("%p  machine=%04x magic=%04x\n",
                      (void*)hLast, inh.FileHeader.Machine, inh.OptionalHeader.Magic));

        if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
            hModule = hLast;
            if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
                && inh.FileHeader.Machine != 0) {

                bHas32BitExe = TRUE;
            }
            DETOUR_TRACE(("%p  Found EXE\n", (void*)hLast));
        }
        else {
            if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
                && inh.FileHeader.Machine != 0) {

                bHas64BitDll = TRUE;
            }
        }
    }

    if (hModule == NULL) {
        SetLastError(ERROR_INVALID_OPERATION);
        return FALSE;
    }

    if (!bHas32BitExe) {
        bIs32BitProcess = FALSE;
    }
    else if (!bHas64BitDll) {
        bIs32BitProcess = TRUE;
    }
    else {
        if (!IsWow64Process(hProcess, &bIs32BitProcess)) {
            return FALSE;
        }
    }

    DETOUR_TRACE(("    32BitExe=%d 32BitProcess=%d\n", bHas32BitExe, bIs32BitProcess));

    return DetourUpdateProcessWithDllEx(hProcess,
                                        hModule,
                                        bIs32BitProcess,
                                        rlpDlls,
                                        nDlls);
}

BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
                                         _In_ HMODULE hModule,
                                         _In_ BOOL bIs32BitProcess,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_ DWORD nDlls)
{
    // Find the next memory region that contains a mapped PE image.
    //
    BOOL bIs32BitExe = FALSE;

    DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%lu)\n", hProcess, (void*)hModule, nDlls));

    IMAGE_NT_HEADERS32 inh;

    if (hModule == NULL || LoadNtHeaderFromProcess(hProcess, hModule, &inh) == FALSE) {
        SetLastError(ERROR_INVALID_OPERATION);
        return FALSE;
    }

    if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
        && inh.FileHeader.Machine != 0) {

        bIs32BitExe = TRUE;
    }

    DETOUR_TRACE(("    32BitExe=%d 32BitProcess=%d\n", bIs32BitExe, bIs32BitProcess));

    if (hModule == NULL) {
        SetLastError(ERROR_INVALID_OPERATION);
        return FALSE;
    }

    // Save the various headers for DetourRestoreAfterWith.
    //
    DETOUR_EXE_RESTORE der;

    if (!RecordExeRestore(hProcess, hModule, der)) {
        return FALSE;
    }

#if defined(DETOURS_64BIT)
    // Try to convert a neutral 32-bit managed binary to a 64-bit managed binary.
    if (bIs32BitExe && !bIs32BitProcess) {
        if (!der.pclr                       // Native binary
            || (der.clr.Flags & 1) == 0     // Or mixed-mode MSIL
            || (der.clr.Flags & 2) != 0) {  // Or 32BIT Required MSIL

            SetLastError(ERROR_INVALID_HANDLE);
            return FALSE;
        }

        if (!UpdateFrom32To64(hProcess, hModule,
#if defined(DETOURS_X64)
                              IMAGE_FILE_MACHINE_AMD64,
#elif defined(DETOURS_IA64)
                              IMAGE_FILE_MACHINE_IA64,
#elif defined(DETOURS_ARM64)
                              IMAGE_FILE_MACHINE_ARM64,
#else
#error Must define one of DETOURS_X64 or DETOURS_IA64 or DETOURS_ARM64 on 64-bit.
#endif
                              der)) {
            return FALSE;
        }
        bIs32BitExe = FALSE;
    }
#endif // DETOURS_64BIT

    // Now decide if we can insert the detour.

#if defined(DETOURS_32BIT)
    if (bIs32BitProcess) {
        // 32-bit native or 32-bit managed process on any platform.
        if (!UpdateImports32(hProcess, hModule, rlpDlls, nDlls)) {
            return FALSE;
        }
    }
    else {
        // 64-bit native or 64-bit managed process.
        //
        // Can't detour a 64-bit process with 32-bit code.
        // Note: This happens for 32-bit PE binaries containing only
        // manage code that have been marked as 64-bit ready.
        //
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }
#elif defined(DETOURS_64BIT)
    if (bIs32BitProcess || bIs32BitExe) {
        // Can't detour a 32-bit process with 64-bit code.
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }
    else {
        // 64-bit native or 64-bit managed process on any platform.
        if (!UpdateImports64(hProcess, hModule, rlpDlls, nDlls)) {
            return FALSE;
        }
    }
#else
#pragma Must define one of DETOURS_32BIT or DETOURS_64BIT.
#endif // DETOURS_64BIT

    /////////////////////////////////////////////////// Update the CLR header.
    //
    if (der.pclr != NULL) {
        DETOUR_CLR_HEADER clr;
        CopyMemory(&clr, &der.clr, sizeof(clr));
        clr.Flags &= 0xfffffffe;    // Clear the IL_ONLY flag.

        DWORD dwProtect;
        if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
            DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %lu\n", GetLastError()));
            return FALSE;
        }

        if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) {
            DETOUR_TRACE(("WriteProcessMemory(clr) failed: %lu\n", GetLastError()));
            return FALSE;
        }

        if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) {
            DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %lu\n", GetLastError()));
            return FALSE;
        }
        DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));

#if DETOURS_64BIT
        if (der.clr.Flags & 0x2) { // Is the 32BIT Required Flag set?
            // X64 never gets here because the process appears as a WOW64 process.
            // However, on IA64, it doesn't appear to be a WOW process.
            DETOUR_TRACE(("CLR Requires 32-bit, %p...%p\n", der.pclr, der.pclr + der.cbclr));
            SetLastError(ERROR_INVALID_HANDLE);
            return FALSE;
        }
#endif // DETOURS_64BIT
    }

    //////////////////////////////// Save the undo data to the target process.
    //
    if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
        DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
        return FALSE;
    }
    return TRUE;
}

#ifndef DETOURS_KERNEL
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName,
                                        _Inout_opt_ LPSTR lpCommandLine,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                        _In_ BOOL bInheritHandles,
                                        _In_ DWORD dwCreationFlags,
                                        _In_opt_ LPVOID lpEnvironment,
                                        _In_opt_ LPCSTR lpCurrentDirectory,
                                        _In_ LPSTARTUPINFOA lpStartupInfo,
                                        _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                        _In_ LPCSTR lpDllName,
                                        _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
{
    DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
    PROCESS_INFORMATION pi;
    BOOL fResult = FALSE;

    if (pfCreateProcessA == NULL) {
        pfCreateProcessA = CreateProcessA;
    }

    fResult = pfCreateProcessA(lpApplicationName,
                               lpCommandLine,
                               lpProcessAttributes,
                               lpThreadAttributes,
                               bInheritHandles,
                               dwMyCreationFlags,
                               lpEnvironment,
                               lpCurrentDirectory,
                               lpStartupInfo,
                               &pi);

    if (lpProcessInformation != NULL) {
        CopyMemory(lpProcessInformation, &pi, sizeof(pi));
    }

    if (!fResult) {
        return FALSE;
    }

    LPCSTR rlpDlls[2];
    DWORD nDlls = 0;
    if (lpDllName != NULL) {
        rlpDlls[nDlls++] = lpDllName;
    }

    if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) {
        TerminateProcess(pi.hProcess, ~0u);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(pi.hThread);
    }
    return TRUE;
}


BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
                                        _Inout_opt_ LPWSTR lpCommandLine,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                        _In_ BOOL bInheritHandles,
                                        _In_ DWORD dwCreationFlags,
                                        _In_opt_ LPVOID lpEnvironment,
                                        _In_opt_ LPCWSTR lpCurrentDirectory,
                                        _In_ LPSTARTUPINFOW lpStartupInfo,
                                        _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                        _In_ LPCSTR lpDllName,
                                        _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
    PROCESS_INFORMATION pi;

    if (pfCreateProcessW == NULL) {
        pfCreateProcessW = CreateProcessW;
    }

    BOOL fResult = pfCreateProcessW(lpApplicationName,
                                    lpCommandLine,
                                    lpProcessAttributes,
                                    lpThreadAttributes,
                                    bInheritHandles,
                                    dwMyCreationFlags,
                                    lpEnvironment,
                                    lpCurrentDirectory,
                                    lpStartupInfo,
                                    &pi);

    if (lpProcessInformation) {
        CopyMemory(lpProcessInformation, &pi, sizeof(pi));
    }

    if (!fResult) {
        return FALSE;
    }

    LPCSTR rlpDlls[2];
    DWORD nDlls = 0;
    if (lpDllName != NULL) {
        rlpDlls[nDlls++] = lpDllName;
    }

    if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) {
        TerminateProcess(pi.hProcess, ~0u);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(pi.hThread);
    }
    return TRUE;
}
#endif // DETOURS_KERNEL

BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
                                       _In_ REFGUID rguid,
                                       _In_reads_bytes_(cbData) PVOID pvData,
                                       _In_ DWORD cbData)
{
    DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) +
                     sizeof(IMAGE_NT_HEADERS) +
                     sizeof(IMAGE_SECTION_HEADER) +
                     sizeof(DETOUR_SECTION_HEADER) +
                     sizeof(DETOUR_SECTION_RECORD) +
                     cbData);

    PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal,
                                         MEM_COMMIT, PAGE_READWRITE);
    if (pbBase == NULL) {
        DETOUR_TRACE(("VirtualAllocEx(%lu) failed: %lu\n", cbTotal, GetLastError()));
        return FALSE;
    }

    PBYTE pbTarget = pbBase;
    IMAGE_DOS_HEADER idh;
    IMAGE_NT_HEADERS inh;
    IMAGE_SECTION_HEADER ish;
    DETOUR_SECTION_HEADER dsh;
    DETOUR_SECTION_RECORD dsr;
    SIZE_T cbWrote = 0;

    ZeroMemory(&idh, sizeof(idh));
    idh.e_magic = IMAGE_DOS_SIGNATURE;
    idh.e_lfanew = sizeof(idh);
    if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) ||
        cbWrote != sizeof(idh)) {
        DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
        return FALSE;
    }
    pbTarget += sizeof(idh);

    ZeroMemory(&inh, sizeof(inh));
    inh.Signature = IMAGE_NT_SIGNATURE;
    inh.FileHeader.SizeOfOptionalHeader = sizeof(inh.OptionalHeader);
    inh.FileHeader.Characteristics = IMAGE_FILE_DLL;
    inh.FileHeader.NumberOfSections = 1;
    inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
    if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) ||
        cbWrote != sizeof(inh)) {
        return FALSE;
    }
    pbTarget += sizeof(inh);

    ZeroMemory(&ish, sizeof(ish));
    memcpy(ish.Name, ".detour", sizeof(ish.Name));
    ish.VirtualAddress = (DWORD)((pbTarget + sizeof(ish)) - pbBase);
    ish.SizeOfRawData = (sizeof(DETOUR_SECTION_HEADER) +
                         sizeof(DETOUR_SECTION_RECORD) +
                         cbData);
    if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) ||
        cbWrote != sizeof(ish)) {
        return FALSE;
    }
    pbTarget += sizeof(ish);

    ZeroMemory(&dsh, sizeof(dsh));
    dsh.cbHeaderSize = sizeof(dsh);
    dsh.nSignature = DETOUR_SECTION_HEADER_SIGNATURE;
    dsh.nDataOffset = sizeof(DETOUR_SECTION_HEADER);
    dsh.cbDataSize = (sizeof(DETOUR_SECTION_HEADER) +
                      sizeof(DETOUR_SECTION_RECORD) +
                      cbData);
    if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) ||
        cbWrote != sizeof(dsh)) {
        return FALSE;
    }
    pbTarget += sizeof(dsh);

    ZeroMemory(&dsr, sizeof(dsr));
    dsr.cbBytes = cbData + sizeof(DETOUR_SECTION_RECORD);
    dsr.nReserved = 0;
    dsr.guid = rguid;
    if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) ||
        cbWrote != sizeof(dsr)) {
        return FALSE;
    }
    pbTarget += sizeof(dsr);

    if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) ||
        cbWrote != cbData) {
        return FALSE;
    }
    pbTarget += cbData;

    DETOUR_TRACE(("Copied %lu byte payload into target process at %p\n",
                  cbTotal, pbTarget - cbTotal));
    return TRUE;
}

#ifndef DETOURS_KERNEL
static BOOL s_fSearchedForHelper = FALSE;
static PDETOUR_EXE_HELPER s_pHelper = NULL;

VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
                                        _In_ HINSTANCE,
                                        _In_ LPSTR,
                                        _In_ INT)
{
    LPCSTR * rlpDlls = NULL;
    DWORD Result = 9900;
    HANDLE hProcess = nullptr;
    DWORD cSize = 0;
    DWORD cOffset = 0;

    if (s_pHelper == NULL) {
        DETOUR_TRACE(("DetourFinishHelperProcess called with s_pHelper = NULL.\n"));
        Result = 9905;
        goto Cleanup;
    }

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid);
    if (hProcess == NULL) {
        DETOUR_TRACE(("OpenProcess(pid=%lu) failed: %lu\n",
                      s_pHelper->pid, GetLastError()));
        Result = 9901;
        goto Cleanup;
    }

    rlpDlls = new NOTHROW LPCSTR [s_pHelper->nDlls];
    cSize = s_pHelper->cb - sizeof(DETOUR_EXE_HELPER);
    cOffset = 0;
    for (DWORD n = 0; n < s_pHelper->nDlls; n++) {
        size_t cchDest = 0;
        HRESULT hr = StringCchLengthA(&s_pHelper->rDlls[cOffset], cSize - cOffset, &cchDest);
        if (!SUCCEEDED(hr)) {
            Result = 9902;
            goto Cleanup;
        }

        rlpDlls[n] = &s_pHelper->rDlls[cOffset];
        cOffset += (DWORD)cchDest + 1;
    }

    if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) {
        DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%lu) failed: %lu\n",
                      s_pHelper->pid, GetLastError()));
        Result = 9903;
        goto Cleanup;
    }
    Result = 0;

  Cleanup:
    if (rlpDlls != NULL) {
        delete[] rlpDlls;
        rlpDlls = NULL;
    }

    ExitProcess(Result);
}

BOOL WINAPI DetourIsHelperProcess(VOID)
{
    PVOID pvData;
    DWORD cbData;

    if (s_fSearchedForHelper) {
        return (s_pHelper != NULL);
    }

    s_fSearchedForHelper = TRUE;
    pvData = DetourFindPayloadEx(DETOUR_EXE_HELPER_GUID, &cbData);

    if (pvData == NULL || cbData < sizeof(DETOUR_EXE_HELPER)) {
        return FALSE;
    }

    s_pHelper = (PDETOUR_EXE_HELPER)pvData;
    if (s_pHelper->cb < sizeof(*s_pHelper)) {
        s_pHelper = NULL;
        return FALSE;
    }

    return TRUE;
}

static
BOOL WINAPI AllocExeHelper(_Out_ PDETOUR_EXE_HELPER *pHelper,
                           _In_ DWORD dwTargetPid,
                           _In_ DWORD nDlls,
                           _In_reads_(nDlls) LPCSTR *rlpDlls)
{
    PDETOUR_EXE_HELPER Helper = NULL;
    BOOL Result = FALSE;
    DWORD cSize = 0;
    _Field_range_(0, cSize - 4) DWORD cOffset = 0;

    if (pHelper == NULL) {
        goto Cleanup;
    }
    *pHelper = NULL;

    if (nDlls < 1 || nDlls > 4096) {
        SetLastError(ERROR_INVALID_PARAMETER);
        goto Cleanup;
    }

    cSize = 4;
    for (DWORD n = 0; n < nDlls; n++) {
        HRESULT hr;
        size_t cchDest = 0;

        hr = StringCchLengthA(rlpDlls[n], 4096, &cchDest);
        if (!SUCCEEDED(hr)) {
            goto Cleanup;
        }

        cSize += (DWORD)cchDest + 1;
    }

    Helper = (PDETOUR_EXE_HELPER) new NOTHROW BYTE[sizeof(DETOUR_EXE_HELPER) + cSize];
    if (Helper == NULL) {
        goto Cleanup;
    }

    Helper->cb = sizeof(DETOUR_EXE_HELPER) + cSize;
    Helper->pid = dwTargetPid;
    Helper->nDlls = nDlls;

    for (DWORD n = 0; n < nDlls; n++) {
        HRESULT hr;
        size_t cchDest = 0;

        if (cOffset > 0x10000 || cSize > 0x10000 || cOffset + 2 >= cSize) {
            goto Cleanup;
        }

        if (cOffset + 2 >= cSize || cOffset + 65536 < cSize) {
            goto Cleanup;
        }

        _Analysis_assume_(cOffset + 1 < cSize);
        _Analysis_assume_(cOffset < 0x10000);
        _Analysis_assume_(cSize < 0x10000);

        PCHAR psz = &Helper->rDlls[cOffset];

        hr = StringCchCopyA(psz, cSize - cOffset, rlpDlls[n]);
        if (!SUCCEEDED(hr)) {
            goto Cleanup;
        }

// REVIEW 28020 The expression '1<=_Param_(2)& &_Param_(2)<=2147483647' is not true at this call.
// REVIEW 28313 Analysis will not proceed past this point because of annotation evaluation. The annotation expression *_Param_(3)<_Param_(2)&&*_Param_(3)<=stringLength$(_Param_(1)) cannot be true under any assumptions at this point in the program.
#pragma warning(suppress:28020 28313)
        hr = StringCchLengthA(psz, cSize - cOffset, &cchDest);
        if (!SUCCEEDED(hr)) {
            goto Cleanup;
        }

        // Replace "32." with "64." or "64." with "32."

        for (DWORD c = (DWORD)cchDest + 1; c > 3; c--) {
#if DETOURS_32BIT
            if (psz[c - 3] == '3' && psz[c - 2] == '2' && psz[c - 1] == '.') {
                psz[c - 3] = '6'; psz[c - 2] = '4';
                break;
            }
#else
            if (psz[c - 3] == '6' && psz[c - 2] == '4' && psz[c - 1] == '.') {
                psz[c - 3] = '3'; psz[c - 2] = '2';
                break;
            }
#endif
        }

        cOffset += (DWORD)cchDest + 1;
    }

    *pHelper = Helper;
    Helper = NULL;
    Result = TRUE;

  Cleanup:
    if (Helper != NULL) {
        delete[] (PBYTE)Helper;
        Helper = NULL;
    }
    return Result;
}

static
VOID WINAPI FreeExeHelper(PDETOUR_EXE_HELPER *pHelper)
{
    if (*pHelper != NULL) {
        delete[] (PBYTE)*pHelper;
        *pHelper = NULL;
    }
}

BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid,
                                    _In_ LPCSTR lpDllName,
                                    _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
{
    return DetourProcessViaHelperDllsA(dwTargetPid, 1, &lpDllName, pfCreateProcessA);
}


BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
                                        _In_ DWORD nDlls,
                                        _In_reads_(nDlls) LPCSTR *rlpDlls,
                                        _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
{
    BOOL Result = FALSE;
    PROCESS_INFORMATION pi;
    STARTUPINFOA si;
    CHAR szExe[MAX_PATH];
    CHAR szCommand[MAX_PATH];
    PDETOUR_EXE_HELPER helper = NULL;
    HRESULT hr;
    DWORD nLen = 0;

    DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
    if (nDlls < 1 || nDlls > 4096) {
        SetLastError(ERROR_INVALID_PARAMETER);
        goto Cleanup;
    }
    if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) {
        goto Cleanup;
    }

    nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe));
    if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) {
        goto Cleanup;
    }

#if DETOURS_OPTION_BITS
#if DETOURS_32BIT
    hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\sysnative\\rundll32.exe");
#else // !DETOURS_32BIT
    hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\syswow64\\rundll32.exe");
#endif // !DETOURS_32BIT
#else // DETOURS_OPTIONS_BITS
    hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\system32\\rundll32.exe");
#endif // DETOURS_OPTIONS_BITS
    if (!SUCCEEDED(hr)) {
        goto Cleanup;
    }

    hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand),
                          "rundll32.exe \"%hs\",#1", &helper->rDlls[0]);
    if (!SUCCEEDED(hr)) {
        goto Cleanup;
    }

    ZeroMemory(&pi, sizeof(pi));
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%hs\", \"%hs\")\n", szExe, szCommand));
    if (pfCreateProcessA(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED,
                         NULL, NULL, &si, &pi)) {

        if (!DetourCopyPayloadToProcess(pi.hProcess,
                                        DETOUR_EXE_HELPER_GUID,
                                        helper, helper->cb)) {
            DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
            TerminateProcess(pi.hProcess, ~0u);
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            goto Cleanup;
        }

        ResumeThread(pi.hThread);
        WaitForSingleObject(pi.hProcess, INFINITE);

        DWORD dwResult = 500;
        GetExitCodeProcess(pi.hProcess, &dwResult);

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        if (dwResult != 0) {
            DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
            goto Cleanup;
        }
        Result = TRUE;
    }
    else {
        DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
        goto Cleanup;
    }

  Cleanup:
    FreeExeHelper(&helper);
    return Result;
}

BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid,
                                    _In_ LPCSTR lpDllName,
                                    _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    return DetourProcessViaHelperDllsW(dwTargetPid, 1, &lpDllName, pfCreateProcessW);
}

BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
                                        _In_ DWORD nDlls,
                                        _In_reads_(nDlls) LPCSTR *rlpDlls,
                                        _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    BOOL Result = FALSE;
    PROCESS_INFORMATION pi;
    STARTUPINFOW si;
    WCHAR szExe[MAX_PATH];
    WCHAR szCommand[MAX_PATH];
    PDETOUR_EXE_HELPER helper = NULL;
    HRESULT hr;
    DWORD nLen = 0;

    DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
    if (nDlls < 1 || nDlls > 4096) {
        SetLastError(ERROR_INVALID_PARAMETER);
        goto Cleanup;
    }
    if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) {
        goto Cleanup;
    }

    nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe));
    if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) {
        goto Cleanup;
    }

#if DETOURS_OPTION_BITS
#if DETOURS_32BIT
    hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\sysnative\\rundll32.exe");
#else // !DETOURS_32BIT
    hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\syswow64\\rundll32.exe");
#endif // !DETOURS_32BIT
#else // DETOURS_OPTIONS_BITS
    hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\system32\\rundll32.exe");
#endif // DETOURS_OPTIONS_BITS
    if (!SUCCEEDED(hr)) {
        goto Cleanup;
    }

    hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand),
                          L"rundll32.exe \"%hs\",#1", &helper->rDlls[0]);
    if (!SUCCEEDED(hr)) {
        goto Cleanup;
    }

    ZeroMemory(&pi, sizeof(pi));
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%ls\", \"%ls\")\n", szExe, szCommand));
    if (pfCreateProcessW(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED,
                         NULL, NULL, &si, &pi)) {

        if (!DetourCopyPayloadToProcess(pi.hProcess,
                                        DETOUR_EXE_HELPER_GUID,
                                        helper, helper->cb)) {
            DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
            TerminateProcess(pi.hProcess, ~0u);
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            goto Cleanup;
        }

        ResumeThread(pi.hThread);

        ResumeThread(pi.hThread);
        WaitForSingleObject(pi.hProcess, INFINITE);

        DWORD dwResult = 500;
        GetExitCodeProcess(pi.hProcess, &dwResult);

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        if (dwResult != 0) {
            DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
            goto Cleanup;
        }
        Result = TRUE;
    }
    else {
        DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
        goto Cleanup;
    }

  Cleanup:
    FreeExeHelper(&helper);
    return Result;
}

BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName,
                                          _Inout_opt_ LPSTR lpCommandLine,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                          _In_ BOOL bInheritHandles,
                                          _In_ DWORD dwCreationFlags,
                                          _In_opt_ LPVOID lpEnvironment,
                                          _In_opt_ LPCSTR lpCurrentDirectory,
                                          _In_ LPSTARTUPINFOA lpStartupInfo,
                                          _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                          _In_ LPCSTR lpDllName,
                                          _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
{
    if (pfCreateProcessA == NULL) {
        pfCreateProcessA = CreateProcessA;
    }

    PROCESS_INFORMATION backup;
    if (lpProcessInformation == NULL) {
        lpProcessInformation = &backup;
        ZeroMemory(&backup, sizeof(backup));
    }

    if (!pfCreateProcessA(lpApplicationName,
                          lpCommandLine,
                          lpProcessAttributes,
                          lpThreadAttributes,
                          bInheritHandles,
                          dwCreationFlags | CREATE_SUSPENDED,
                          lpEnvironment,
                          lpCurrentDirectory,
                          lpStartupInfo,
                          lpProcessInformation)) {
        return FALSE;
    }

    LPCSTR szDll = lpDllName;

    if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &szDll, 1) &&
        !DetourProcessViaHelperA(lpProcessInformation->dwProcessId,
                                 lpDllName,
                                 pfCreateProcessA)) {

        TerminateProcess(lpProcessInformation->hProcess, ~0u);
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(lpProcessInformation->hThread);
    }

    if (lpProcessInformation == &backup) {
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
    }

    return TRUE;
}

BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName,
                                          _Inout_opt_  LPWSTR lpCommandLine,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                          _In_ BOOL bInheritHandles,
                                          _In_ DWORD dwCreationFlags,
                                          _In_opt_ LPVOID lpEnvironment,
                                          _In_opt_ LPCWSTR lpCurrentDirectory,
                                          _In_ LPSTARTUPINFOW lpStartupInfo,
                                          _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                          _In_ LPCSTR lpDllName,
                                          _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    if (pfCreateProcessW == NULL) {
        pfCreateProcessW = CreateProcessW;
    }

    PROCESS_INFORMATION backup;
    if (lpProcessInformation == NULL) {
        lpProcessInformation = &backup;
        ZeroMemory(&backup, sizeof(backup));
    }

    if (!pfCreateProcessW(lpApplicationName,
                          lpCommandLine,
                          lpProcessAttributes,
                          lpThreadAttributes,
                          bInheritHandles,
                          dwCreationFlags | CREATE_SUSPENDED,
                          lpEnvironment,
                          lpCurrentDirectory,
                          lpStartupInfo,
                          lpProcessInformation)) {
        return FALSE;
    }


    LPCSTR sz = lpDllName;

    if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &sz, 1) &&
        !DetourProcessViaHelperW(lpProcessInformation->dwProcessId,
                                 lpDllName,
                                 pfCreateProcessW)) {

        TerminateProcess(lpProcessInformation->hProcess, ~0u);
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(lpProcessInformation->hThread);
    }

    if (lpProcessInformation == &backup) {
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
    }
    return TRUE;
}

BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName,
                                         _Inout_opt_ LPSTR lpCommandLine,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                         _In_ BOOL bInheritHandles,
                                         _In_ DWORD dwCreationFlags,
                                         _In_opt_ LPVOID lpEnvironment,
                                         _In_opt_ LPCSTR lpCurrentDirectory,
                                         _In_ LPSTARTUPINFOA lpStartupInfo,
                                         _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                         _In_ DWORD nDlls,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
{
    if (pfCreateProcessA == NULL) {
        pfCreateProcessA = CreateProcessA;
    }

    PROCESS_INFORMATION backup;
    if (lpProcessInformation == NULL) {
        lpProcessInformation = &backup;
        ZeroMemory(&backup, sizeof(backup));
    }

    if (!pfCreateProcessA(lpApplicationName,
                          lpCommandLine,
                          lpProcessAttributes,
                          lpThreadAttributes,
                          bInheritHandles,
                          dwCreationFlags | CREATE_SUSPENDED,
                          lpEnvironment,
                          lpCurrentDirectory,
                          lpStartupInfo,
                          lpProcessInformation)) {
        return FALSE;
    }

    if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) &&
        !DetourProcessViaHelperDllsA(lpProcessInformation->dwProcessId,
                                     nDlls,
                                     rlpDlls,
                                     pfCreateProcessA)) {

        TerminateProcess(lpProcessInformation->hProcess, ~0u);
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(lpProcessInformation->hThread);
    }

    if (lpProcessInformation == &backup) {
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
    }

    return TRUE;
}

BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName,
                                         _Inout_opt_ LPWSTR lpCommandLine,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                         _In_ BOOL bInheritHandles,
                                         _In_ DWORD dwCreationFlags,
                                         _In_opt_ LPVOID lpEnvironment,
                                         _In_opt_ LPCWSTR lpCurrentDirectory,
                                         _In_ LPSTARTUPINFOW lpStartupInfo,
                                         _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                         _In_ DWORD nDlls,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    if (pfCreateProcessW == NULL) {
        pfCreateProcessW = CreateProcessW;
    }

    PROCESS_INFORMATION backup;
    if (lpProcessInformation == NULL) {
        lpProcessInformation = &backup;
        ZeroMemory(&backup, sizeof(backup));
    }

    if (!pfCreateProcessW(lpApplicationName,
                          lpCommandLine,
                          lpProcessAttributes,
                          lpThreadAttributes,
                          bInheritHandles,
                          dwCreationFlags | CREATE_SUSPENDED,
                          lpEnvironment,
                          lpCurrentDirectory,
                          lpStartupInfo,
                          lpProcessInformation)) {
        return FALSE;
    }


    if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) &&
        !DetourProcessViaHelperDllsW(lpProcessInformation->dwProcessId,
                                     nDlls,
                                     rlpDlls,
                                     pfCreateProcessW)) {

        TerminateProcess(lpProcessInformation->hProcess, ~0u);
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
        return FALSE;
    }

    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(lpProcessInformation->hThread);
    }

    if (lpProcessInformation == &backup) {
        CloseHandle(lpProcessInformation->hProcess);
        CloseHandle(lpProcessInformation->hThread);
    }
    return TRUE;
}
#endif // !DETOURS_KERNEL

//
///////////////////////////////////////////////////////////////// End of File.


================================================
FILE: Detours/detours.cpp
================================================
//////////////////////////////////////////////////////////////////////////////
//
//  Core Detours Functionality (detours.cpp of detours.lib)
//
//  Microsoft Research Detours Package, Version 4.0.1
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//

#pragma warning(disable:4068) // unknown pragma (suppress)

#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable:4091) // empty typedef
#endif

#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1
#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1

#include <Veil.h>

#if (_MSC_VER < 1299)
#pragma warning(disable: 4710)
#endif

// #define DETOUR_DEBUG 1
#define DETOURS_INTERNAL

#include "detours.h"

#if DETOURS_VERSION != 0x4c0c1   // 0xMAJORcMINORcPATCH
#error detours.h version mismatch
#endif

#if _MSC_VER >= 1900
#pragma warning(pop)
#endif

#define NOTHROW

//////////////////////////////////////////////////////////////////////////////
//
struct _DETOUR_ALIGN
{
    BYTE    obTarget        : 3;
    BYTE    obTrampoline    : 5;
};

C_ASSERT(sizeof(_DETOUR_ALIGN) == 1);

//////////////////////////////////////////////////////////////////////////////
//
// Region reserved for system DLLs, which cannot be used for trampolines.
//
static PVOID    s_pSystemRegionLowerBound   = (PVOID)(ULONG_PTR)0x70000000;
static PVOID    s_pSystemRegionUpperBound   = (PVOID)(ULONG_PTR)0x80000000;

//////////////////////////////////////////////////////////////////////////////
//
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
{
    MEMORY_BASIC_INFORMATION mbi;
    VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
    __try {
        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
        if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
            return false;
        }

        PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
                                                          pDosHeader->e_lfanew);
        if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
            return false;
        }

        if (pbAddress >= ((PBYTE)pDosHeader +
                          pNtHeader->OptionalHeader
                          .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
            pbAddress < ((PBYTE)pDosHeader +
                         pNtHeader->OptionalHeader
                         .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
                         pNtHeader->OptionalHeader
                         .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
            return true;
        }
    }
#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
    __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
             EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        return false;
    }
    return false;
}

inline ULONG_PTR detour_2gb_below(ULONG_PTR address)
{
    return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000;
}

inline ULONG_PTR detour_2gb_above(ULONG_PTR address)
{
#if defined(DETOURS_64BIT)
    return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000;
#else
    return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000;
#endif
}

///////////////////////////////////////////////////////////////////////// X86.
//
#ifdef DETOURS_X86

struct _DETOUR_TRAMPOLINE
{
    BYTE            rbCode[30];     // target code + jmp to pbRemain
    BYTE            cbCode;         // size of moved target code.
    BYTE            cbCodeBreak;    // padding to make debugging easier.
    BYTE            rbRestore[22];  // original target code.
    BYTE            cbRestore;      // size of original target code.
    BYTE            cbRestoreBreak; // padding to make debugging easier.
    _DETOUR_ALIGN   rAlign[8];      // instruction alignment array.
    PBYTE           pbRemain;       // first instruction after moved code. [free list]
    PBYTE           pbDetour;       // first instruction of detour function.
};

C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72);

enum {
    SIZE_OF_JMP = 5
};

inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
{
    PBYTE pbJmpSrc = pbCode + 5;
    *pbCode++ = 0xE9;   // jmp +imm32
    *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
    return pbCode;
}

inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
{
    *pbCode++ = 0xff;   // jmp [+imm32]
    *pbCode++ = 0x25;
    *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal);
    return pbCode;
}

inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
{
    while (pbCode < pbLimit) {
        *pbCode++ = 0xcc;   // brk;
    }
    return pbCode;
}

inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
{
    if (pbCode == NULL) {
        return NULL;
    }
    if (ppGlobals != NULL) {
        *ppGlobals = NULL;
    }

    // First, skip over the import vector if there is one.
    if (pbCode[0] == 0xff && pbCode[1] == 0x25) {   // jmp [imm32]
        // Looks like an import alias jump, then get the code it points to.
        PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
        if (detour_is_imported(pbCode, pbTarget)) {
            PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
            DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
            pbCode = pbNew;
        }
    }

    // Then, skip over a patch jump
    if (pbCode[0] == 0xeb) {   // jmp +imm8
        PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
        DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
        pbCode = pbNew;

        // First, skip over the import vector if there is one.
        if (pbCode[0] == 0xff && pbCode[1] == 0x25) {   // jmp [imm32]
            // Looks like an import alias jump, then get the code it points to.
            PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
            if (detour_is_imported(pbCode, pbTarget)) {
                pbNew = *(UNALIGNED PBYTE *)pbTarget;
                DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
                pbCode = pbNew;
            }
        }
        // Finally, skip over a long jump if it is the target of the patch jump.
        else if (pbCode[0] == 0xe9) {   // jmp +imm32
            pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
            DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
            pbCode = pbNew;
        }
    }
    return pbCode;
}

inline void detour_find_jmp_bounds(PBYTE pbCode,
                                   PDETOUR_TRAMPOLINE *ppLower,
                                   PDETOUR_TRAMPOLINE *ppUpper)
{
    // We have to place trampolines within +/- 2GB of code.
    ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
    ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
    DETOUR_TRACE(("[%Ix..%p..%Ix]\n", lo, pbCode, hi));

    // And, within +/- 2GB of relative jmp targets.
    if (pbCode[0] == 0xe9) {   // jmp +imm32
        PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];

        if (pbNew < pbCode) {
            hi = detour_2gb_above((ULONG_PTR)pbNew);
        }
        else {
            lo = detour_2gb_below((ULONG_PTR)pbNew);
        }
        DETOUR_TRACE(("[%Ix..%p..%Ix] +imm32\n", lo, pbCode, hi));
    }

    *ppLower = (PDETOUR_TRAMPOLINE)lo;
    *ppUpper = (PDETOUR_TRAMPOLINE)hi;
}

inline BOOL detour_does_code_end_function(PBYTE pbCode)
{
    if (pbCode[0] == 0xeb ||    // jmp +imm8
        pbCode[0] == 0xe9 ||    // jmp +imm32
        pbCode[0] == 0xe0 ||    // jmp eax
        pbCode[0] == 0xc2 ||    // ret +imm8
        pbCode[0] == 0xc3 ||    // ret
        pbCode[0] == 0xcc) {    // brk
        return TRUE;
    }
    else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) {  // rep ret
        return TRUE;
    }
    else if (pbCode[0] == 0xff && pbCode[1] == 0x25) {  // jmp [+imm32]
        return TRUE;
    }
    else if ((pbCode[0] == 0x26 ||      // jmp es:
              pbCode[0] == 0x2e ||      // jmp cs:
              pbCode[0] == 0x36 ||      // jmp ss:
              pbCode[0] == 0x3e ||      // jmp ds:
              pbCode[0] == 0x64 ||      // jmp fs:
              pbCode[0] == 0x65) &&     // jmp gs:
             pbCode[1] == 0xff &&       // jmp [+imm32]
             pbCode[2] == 0x25) {
        return TRUE;
    }
    return FALSE;
}

inline ULONG detour_is_code_filler(PBYTE pbCode)
{
    // 1-byte through 11-byte NOPs.
    if (pbCode[0] == 0x90) {
        return 1;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
        return 2;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
        return 3;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
        pbCode[3] == 0x00) {
        return 4;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00) {
        return 5;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
        pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
        return 6;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00) {
        return 7;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00) {
        return 8;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
        pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
        return 9;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
        pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
        pbCode[9] == 0x00) {
        return 10;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
        pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
        pbCode[9] == 0x00 && pbCode[10] == 0x00) {
        return 11;
    }

    // int 3.
    if (pbCode[0] == 0xcc) {
        return 1;
    }
    return 0;
}

#endif // DETOURS_X86

///////////////////////////////////////////////////////////////////////// X64.
//
#ifdef DETOURS_X64

struct _DETOUR_TRAMPOLINE
{
    // An X64 instuction can be 15 bytes long.
    // In practice 11 seems to be the limit.
    BYTE            rbCode[30];     // target code + jmp to pbRemain.
    BYTE            cbCode;         // size of moved target code.
    BYTE            cbCodeBreak;    // padding to make debugging easier.
    BYTE            rbRestore[30];  // original target code.
    BYTE            cbRestore;      // size of original target code.
    BYTE            cbRestoreBreak; // padding to make debugging easier.
    _DETOUR_ALIGN   rAlign[8];      // instruction alignment array.
    PBYTE           pbRemain;       // first instruction after moved code. [free list]
    PBYTE           pbDetour;       // first instruction of detour function.
    BYTE            rbCodeIn[8];    // jmp [pbDetour]
};

C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96);

enum {
    SIZE_OF_JMP = 5
};

inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
{
    PBYTE pbJmpSrc = pbCode + 5;
    *pbCode++ = 0xE9;   // jmp +imm32
    *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
    return pbCode;
}

inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
{
    PBYTE pbJmpSrc = pbCode + 6;
    *pbCode++ = 0xff;   // jmp [+imm32]
    *pbCode++ = 0x25;
    *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);
    return pbCode;
}

inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
{
    while (pbCode < pbLimit) {
        *pbCode++ = 0xcc;   // brk;
    }
    return pbCode;
}

inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
{
    if (pbCode == NULL) {
        return NULL;
    }
    if (ppGlobals != NULL) {
        *ppGlobals = NULL;
    }

    // First, skip over the import vector if there is one.
    if (pbCode[0] == 0xff && pbCode[1] == 0x25) {   // jmp [+imm32]
        // Looks like an import alias jump, then get the code it points to.
        PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
        if (detour_is_imported(pbCode, pbTarget)) {
            PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
            DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
            pbCode = pbNew;
        }
    }

    // Then, skip over a patch jump
    if (pbCode[0] == 0xeb) {   // jmp +imm8
        PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
        DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
        pbCode = pbNew;

        // First, skip over the import vector if there is one.
        if (pbCode[0] == 0xff && pbCode[1] == 0x25) {   // jmp [+imm32]
            // Looks like an import alias jump, then get the code it points to.
            PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
            if (detour_is_imported(pbCode, pbTarget)) {
                pbNew = *(UNALIGNED PBYTE *)pbTarget;
                DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
                pbCode = pbNew;
            }
        }
        // Finally, skip over a long jump if it is the target of the patch jump.
        else if (pbCode[0] == 0xe9) {   // jmp +imm32
            pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
            DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
            pbCode = pbNew;
        }
    }
    return pbCode;
}

inline void detour_find_jmp_bounds(PBYTE pbCode,
                                   PDETOUR_TRAMPOLINE *ppLower,
                                   PDETOUR_TRAMPOLINE *ppUpper)
{
    // We have to place trampolines within +/- 2GB of code.
    ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
    ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
    DETOUR_TRACE(("[%Ix..%p..%Ix]\n", lo, pbCode, hi));

    // And, within +/- 2GB of relative jmp vectors.
    if (pbCode[0] == 0xff && pbCode[1] == 0x25) {   // jmp [+imm32]
        PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];

        if (pbNew < pbCode) {
            hi = detour_2gb_above((ULONG_PTR)pbNew);
        }
        else {
            lo = detour_2gb_below((ULONG_PTR)pbNew);
        }
        DETOUR_TRACE(("[%Ix..%p..%Ix] [+imm32]\n", lo, pbCode, hi));
    }
    // And, within +/- 2GB of relative jmp targets.
    else if (pbCode[0] == 0xe9) {   // jmp +imm32
        PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];

        if (pbNew < pbCode) {
            hi = detour_2gb_above((ULONG_PTR)pbNew);
        }
        else {
            lo = detour_2gb_below((ULONG_PTR)pbNew);
        }
        DETOUR_TRACE(("[%Ix..%p..%Ix] +imm32\n", lo, pbCode, hi));
    }

    *ppLower = (PDETOUR_TRAMPOLINE)lo;
    *ppUpper = (PDETOUR_TRAMPOLINE)hi;
}

inline BOOL detour_does_code_end_function(PBYTE pbCode)
{
    if (pbCode[0] == 0xeb ||    // jmp +imm8
        pbCode[0] == 0xe9 ||    // jmp +imm32
        pbCode[0] == 0xe0 ||    // jmp eax
        pbCode[0] == 0xc2 ||    // ret +imm8
        pbCode[0] == 0xc3 ||    // ret
        pbCode[0] == 0xcc) {    // brk
        return TRUE;
    }
    else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) {  // rep ret
        return TRUE;
    }
    else if (pbCode[0] == 0xff && pbCode[1] == 0x25) {  // jmp [+imm32]
        return TRUE;
    }
    else if ((pbCode[0] == 0x26 ||      // jmp es:
              pbCode[0] == 0x2e ||      // jmp cs:
              pbCode[0] == 0x36 ||      // jmp ss:
              pbCode[0] == 0x3e ||      // jmp ds:
              pbCode[0] == 0x64 ||      // jmp fs:
              pbCode[0] == 0x65) &&     // jmp gs:
             pbCode[1] == 0xff &&       // jmp [+imm32]
             pbCode[2] == 0x25) {
        return TRUE;
    }
    return FALSE;
}

inline ULONG detour_is_code_filler(PBYTE pbCode)
{
    // 1-byte through 11-byte NOPs.
    if (pbCode[0] == 0x90) {
        return 1;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
        return 2;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
        return 3;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
        pbCode[3] == 0x00) {
        return 4;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00) {
        return 5;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
        pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
        return 6;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00) {
        return 7;
    }
    if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
        pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00) {
        return 8;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
        pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
        return 9;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
        pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
        pbCode[9] == 0x00) {
        return 10;
    }
    if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
        pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
        pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
        pbCode[9] == 0x00 && pbCode[10] == 0x00) {
        return 11;
    }

    // int 3.
    if (pbCode[0] == 0xcc) {
        return 1;
    }
    return 0;
}

#endif // DETOURS_X64

//////////////////////////////////////////////////////////////////////// IA64.
//
#ifdef DETOURS_IA64

struct _DETOUR_TRAMPOLINE
{
    // On the IA64, a trampoline is used for both incoming and outgoing calls.
    //
    // The trampoline contains the following bundles for the outgoing call:
    //      movl gp=target_gp;
    //      <relocated target bundle>
    //      brl  target_code;
    //
    // The trampoline contains the following bundles for the incoming call:
    //      alloc  r41=ar.pfs, b, 0, 8, 0
    //      mov    r40=rp
    //
    //      adds   r50=0, r39
    //      adds   r49=0, r38
    //      adds   r48=0, r37 ;;
    //
    //      adds   r47=0, r36
    //      adds   r46=0, r35
    //      adds   r45=0, r34
    //
    //      adds   r44=0, r33
    //      adds   r43=0, r32
    //      adds   r42=0, gp ;;
    //
    //      movl   gp=ffffffff`ffffffff ;;
    //
    //      brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;;
    //
    //      adds   gp=0, r42
    //      mov    rp=r40, +0 ;;
    //      mov.i  ar.pfs=r41
    //
    //      br.ret.sptk.many rp ;;
    //
    // This way, we only have to relocate a single bundle.
    //
    // The complicated incoming trampoline is required because we have to
    // create an additional stack frame so that we save and restore the gp.
    // We must do this because gp is a caller-saved register, but not saved
    // if the caller thinks the target is in the same DLL, which changes
    // when we insert a detour.
    //
    DETOUR_IA64_BUNDLE  bMovlTargetGp;  // Bundle which sets target GP
    BYTE                rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle.
    DETOUR_IA64_BUNDLE  bBrlRemainEip;  // Brl to pbRemain
    // This must be adjacent to bBranchIslands.

    // Each instruction in the moved bundle could be a IP-relative chk or branch or call.
    // Any such instructions are changed to point to a brl in bBranchIslands.
    // This must be adjacent to bBrlRemainEip -- see "pbPool".
    DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE];

    // Target of brl inserted in target function
    DETOUR_IA64_BUNDLE  bAllocFrame;    // alloc frame
    DETOUR_IA64_BUNDLE  bSave37to39;    // save r37, r38, r39.
    DETOUR_IA64_BUNDLE  bSave34to36;    // save r34, r35, r36.
    DETOUR_IA64_BUNDLE  bSaveGPto33;    // save gp, r32, r33.
    DETOUR_IA64_BUNDLE  bMovlDetourGp;  // set detour GP.
    DETOUR_IA64_BUNDLE  bCallDetour;    // call detour.
    DETOUR_IA64_BUNDLE  bPopFrameGp;    // pop frame and restore gp.
    DETOUR_IA64_BUNDLE  bReturn;        // return to caller.

    PLABEL_DESCRIPTOR   pldTrampoline;

    BYTE                rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle.
    BYTE                cbRestore;      // size of original target code.
    BYTE                cbCode;         // size of moved target code.
    _DETOUR_ALIGN       rAlign[14];     // instruction alignment array.
    PBYTE               pbRemain;       // first instruction after moved code. [free list]
    PBYTE               pbDetour;       // first instruction of detour function.
    PPLABEL_DESCRIPTOR  ppldDetour;     // [pbDetour,gpDetour]
    PPLABEL_DESCRIPTOR  ppldTarget;     // [pbTarget,gpDetour]
};

C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16);
C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16);

enum {
    SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE)
};

inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals)
{
    PBYTE pGlobals = NULL;
    PBYTE pbCode = NULL;

    if (pPointer != NULL) {
        PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer;
        pbCode = (PBYTE)ppld->EntryPoint;
        pGlobals = (PBYTE)ppld->GlobalPointer;
    }
    if (ppGlobals != NULL) {
        *ppGlobals = pGlobals;
    }
    if (pbCode == NULL) {
        return NULL;
    }

    DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode;

    // IA64 Local Import Jumps look like:
    //      addl   r2=ffffffff`ffe021c0, gp ;;
    //      ld8    r2=[r2]
    //      nop.i  0 ;;
    //
    //      ld8    r3=[r2], 8 ;;
    //      ld8    gp=[r2]
    //      mov    b6=r3, +0
    //
    //      nop.m  0
    //      nop.i  0
    //      br.cond.sptk.few b6
    //

    //                     002024000200100b
    if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b &&
        pb[0].wide[1] == 0x0004000000203008 &&
        pb[1].wide[0] == 0x001014180420180a &&
        pb[1].wide[1] == 0x07000830c0203008 &&
        pb[2].wide[0] == 0x0000000100000010 &&
        pb[2].wide[1] == 0x0080006000000200) {

        ULONG64 offset =
            ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) |  // imm7b
            ((pb[0].wide[0] & 0x000001ff00000000) >> 25) |  // imm9d
            ((pb[0].wide[0] & 0x00000000f8000000) >> 11);   // imm5c
        if (pb[0].wide[0] & 0x0000020000000000) {           // sign
            offset |= 0xffffffffffe00000;
        }
        PBYTE pbTarget = pGlobals + offset;
        DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget));

        if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) {
            DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget));

            PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget;
            pbCode = (PBYTE)ppld->EntryPoint;
            pGlobals = (PBYTE)ppld->GlobalPointer;
            if (ppGlobals != NULL) {
                *ppGlobals = pGlobals;
            }
        }
    }
    return pbCode;
}


inline void detour_find_jmp_bounds(PBYTE pbCode,
                                   PDETOUR_TRAMPOLINE *ppLower,
                                   PDETOUR_TRAMPOLINE *ppUpper)
{
    (void)pbCode;
    *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000;
    *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000;
}

inline BOOL detour_does_code_end_function(PBYTE pbCode)
{
    // Routine not needed on IA64.
    (void)pbCode;
    return FALSE;
}

inline ULONG detour_is_code_filler(PBYTE pbCode)
{
    // Routine not needed on IA64.
    (void)pbCode;
    return 0;
}

#endif // DETOURS_IA64

#ifdef DETOURS_ARM

struct _DETOUR_TRAMPOLINE
{
    // A Thumb-2 instruction can be 2 or 4 bytes long.
    BYTE            rbCode[62];     // target code + jmp to pbRemain
    BYTE            cbCode;         // size of moved target code.
    BYTE            cbCodeBreak;    // padding to make debugging easier.
    BYTE            rbRestore[22];  // original target code.
    BYTE            cbRestore;      // size of original target code.
    BYTE            cbRestoreBreak; // padding to make debugging easier.
    _DETOUR_ALIGN   rAlign[8];      // instruction alignment array.
    PBYTE           pbRemain;       // first instruction after moved code. [free list]
    PBYTE           pbDetour;       // first instruction of detour function.
};

C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104);

enum {
    SIZE_OF_JMP = 8
};

inline PBYTE align4(PBYTE pValue)
{
    return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u);
}

inline ULONG fetch_thumb_opcode(PBYTE pbCode)
{
    ULONG Opcode = *(UINT16 *)&pbCode[0];
    if (Opcode >= 0xe800) {
        Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2];
    }
    return Opcode;
}

inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode)
{
    if (Opcode >= 0x10000) {
        *((UINT16*&)pbCode)++ = Opcode >> 16;
    }
    *((UINT16*&)pbCode)++ = (UINT16)Opcode;
}

PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
{
    PBYTE pbLiteral;
    if (ppPool != NULL) {
        *ppPool = *ppPool - 4;
        pbLiteral = *ppPool;
    }
    else {
        pbLiteral = align4(pbCode + 6);
    }

    *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal);
    LONG delta = pbLiteral - align4(pbCode + 4);

    write_thumb_opcode(pbCode, 0xf8dff000 | delta);     // LDR PC,[PC+n]

    if (ppPool == NULL) {
        if (((ULONG)pbCode & 2) != 0) {
            write_thumb_opcode(pbCode, 0xdefe);         // BREAK
        }
        pbCode += 4;
    }
    return pbCode;
}

inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
{
    while (pbCode < pbLimit) {
        write_thumb_opcode(pbCode, 0xdefe);
    }
    return pbCode;
}

inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
{
    if (pbCode == NULL) {
        return NULL;
    }
    if (ppGlobals != NULL) {
        *ppGlobals = NULL;
    }

    // Skip over the import jump if there is one.
    pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode);
    ULONG Opcode = fetch_thumb_opcode(pbCode);

    if ((Opcode & 0xfbf08f00) == 0xf2400c00) {          // movw r12,#xxxx
        ULONG Opcode2 = fetch_thumb_opcode(pbCode+4);

        if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) {      // movt r12,#xxxx
            ULONG Opcode3 = fetch_thumb_opcode(pbCode+8);
            if (Opcode3 == 0xf8dcf000) {                 // ldr  pc,[r12]
                PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) |
                                         ((Opcode2 <<  1) & 0x08000000) |
                                         ((Opcode2 << 16) & 0x00ff0000) |
                                         ((Opcode  >>  4) & 0x0000f700) |
                                         ((Opcode  >> 15) & 0x00000800) |
                                         ((Opcode  >>  0) & 0x000000ff));
                if (detour_is_imported(pbCode, pbTarget)) {
                    PBYTE pbNew = *(PBYTE *)pbTarget;
                    pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew);
                    DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
                    return pbNew;
                }
            }
        }
    }
    return pbCode;
}

inline void detour_find_jmp_bounds(PBYTE pbCode,
                                   PDETOUR_TRAMPOLINE *ppLower,
                                   PDETOUR_TRAMPOLINE *ppUpper)
{
    // We have to place trampolines within +/- 2GB of code.
    ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
    ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
    DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));

    *ppLower = (PDETOUR_TRAMPOLINE)lo;
    *ppUpper = (PDETOUR_TRAMPOLINE)hi;
}


inline BOOL detour_does_code_end_function(PBYTE pbCode)
{
    ULONG Opcode = fetch_thumb_opcode(pbCode);
    if ((Opcode & 0xffffff87) == 0x4700 ||          // bx <reg>
        (Opcode & 0xf800d000) == 0xf0009000) {      // b <imm20>
        return TRUE;
    }
    if ((Opcode & 0xffff8000) == 0xe8bd8000) {      // pop {...,pc}
        __debugbreak();
        return TRUE;
    }
    if ((Opcode & 0xffffff00) == 0x0000bd00) {      // pop {...,pc}
        __debugbreak();
        return TRUE;
    }
    return FALSE;
}

inline ULONG detour_is_code_filler(PBYTE pbCode)
{
    if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop.
        return 2;
    }
    if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding.
        return 2;
    }
    return 0;
}

#endif // DETOURS_ARM

#ifdef DETOURS_ARM64

struct _DETOUR_TRAMPOLINE
{
    // An ARM64 instruction is 4 bytes long.
    BYTE            rbCode[64];     // target code + jmp to pbRemain
    BYTE            cbCode;         // size of moved target code.
    BYTE            cbCodeBreak[3]; // padding to make debugging easier.
    BYTE            rbRestore[24];  // original target code.
    BYTE            cbRestore;      // size of original target code.
    BYTE            cbRestoreBreak[3]; // padding to make debugging easier.
    _DETOUR_ALIGN   rAlign[8];      // instruction alignment array.
    PBYTE           pbRemain;       // first instruction after moved code. [free list]
    PBYTE           pbDetour;       // first instruction of detour function.
};

C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 120);

enum {
    SIZE_OF_JMP = 8
};

inline ULONG fetch_opcode(PBYTE pbCode)
{
    return *(ULONG *)pbCode;
}

inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
{
    *(ULONG *)pbCode = Opcode;
    pbCode += 4;
}

PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
{
    PBYTE pbLiteral;
    if (ppPool != NULL) {
        *ppPool = *ppPool - 8;
        pbLiteral = *ppPool;
    }
    else {
        pbLiteral = pbCode + 2*4;
    }

    *((PBYTE*&)pbLiteral) = pbJmpVal;
    LONG delta = (LONG)(pbLiteral - pbCode);

    write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5));  // LDR X17,[PC+n]
    write_opcode(pbCode, 0xd61f0000 | (17 << 5));           // BR X17

    if (ppPool == NULL) {
        pbCode += 8;
    }
    return pbCode;
}

inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
{
    while (pbCode < pbLimit) {
        write_opcode(pbCode, 0xd4100000 | (0xf000 << 5));
    }
    return pbCode;
}

inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
{
    if (pbCode == NULL) {
        return NULL;
    }
    if (ppGlobals != NULL) {
        *ppGlobals = NULL;
    }

    // Skip over the import jump if there is one.
    pbCode = (PBYTE)pbCode;
    ULONG Opcode = fetch_opcode(pbCode);
    if ((Opcode & 0x9f00001f) == 0x90000010) {           // adrp  x16, IAT
        ULONG Opcode2 = fetch_opcode(pbCode+4);

        if ((Opcode2 & 0xffe003ff) == 0xf9400210) {      // ldr   x16, [x16, IAT]
            ULONG Opcode3 = fetch_opcode(pbCode+8);

            if (Opcode3 == 0xd61f0200) {                 // br    x16

                ULONG PageOffset = ((Opcode & 0x60000000) >> 29) | ((Opcode & 0x00ffffe0) >> 3);
                PageOffset = (LONG)(Opcode << 11) >> 11;

                PBYTE pbTarget = (PBYTE)(((ULONG64)pbCode & 0xfffffffffffff000ULL) + PageOffset +
                                         ((Opcode2 >> 10) & 0xfff));
                if (detour_is_imported(pbCode, pbTarget)) {
                    PBYTE pbNew = *(PBYTE *)pbTarget;
                    DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
                    return pbNew;
                }
            }
        }
    }
    return pbCode;
}

inline void detour_find_jmp_bounds(PBYTE pbCode,
    PDETOUR_TRAMPOLINE* ppLower,
    PDETOUR_TRAMPOLINE* ppUpper)
{
    // The encoding used by detour_gen_jmp_indirect actually enables a
    // displacement of +/- 4GiB. In the future, this could be changed to
    // reflect that. For now, just reuse the x86 logic which is plenty.

    ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
    ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
    DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));

    *ppLower = (PDETOUR_TRAMPOLINE)lo;
    *ppUpper = (PDETOUR_TRAMPOLINE)hi;
}

inline BOOL detour_does_code_end_function(PBYTE pbCode)
{
    ULONG Opcode = fetch_opcode(pbCode);
    if ((Opcode & 0xfffffc1f) == 0xd65f0000 ||      // br <reg>
        (Opcode & 0xfc000000) == 0x14000000) {      // b <imm26>
        return TRUE;
    }
    return FALSE;
}

inline ULONG detour_is_code_filler(PBYTE pbCode)
{
    if (*(ULONG *)pbCode == 0xd503201f) {   // nop.
        return 4;
    }
    if (*(ULONG *)pbCode == 0x00000000) {   // zero-filled padding.
        return 4;
    }
    return 0;
}

#endif // DETOURS_ARM64

//////////////////////////////////////////////// Trampoline Memory Management.
//
struct DETOUR_REGION
{
    ULONG               dwSignature;
    DETOUR_REGION *     pNext;  // Next region in list of regions.
    DETOUR_TRAMPOLINE * pFree;  // List of free trampolines in this region.
};
typedef DETOUR_REGION * PDETOUR_REGION;

const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd';
const ULONG DETOUR_REGION_SIZE = 0x10000;
const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE
                                             / sizeof(DETOUR_TRAMPOLINE)) - 1;
static PDETOUR_REGION s_pRegions = NULL;            // List of all regions.
static PDETOUR_REGION s_pRegion = NULL;             // Default region.

static DWORD detour_writable_trampoline_regions()
{
    // Mark all of the regions as writable.
    for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
        DWORD dwOld;
        if (!VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld)) {
            return GetLastError();
        }
    }
    return NO_ERROR;
}

static void detour_runnable_trampoline_regions()
{
    HANDLE hProcess = GetCurrentProcess();

    // Mark all of the regions as executable.
    for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
        DWORD dwOld;
        VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld);
        FlushInstructionCache(hProcess, pRegion, DETOUR_REGION_SIZE);
    }
}

static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry)
{
    // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
    ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
    if (extra != 0) {
        pbTry -= extra;
    }
    return pbTry;
}

static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry)
{
    // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
    ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
    if (extra != 0) {
        ULONG_PTR adjust = DETOUR_REGION_SIZE - extra;
        pbTry += adjust;
    }
    return pbTry;
}

// Starting at pbLo, try to allocate a memory region, continue until pbHi.

static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
{
    PBYTE pbTry = detour_alloc_round_up_to_region(pbLo);

    DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));

    for (; pbTry < pbHi;) {
        MEMORY_BASIC_INFORMATION mbi;

        if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
            // Skip region reserved for system DLLs, but preserve address space entropy.
            pbTry += 0x08000000;
            continue;
        }

        ZeroMemory(&mbi, sizeof(mbi));
        if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
            break;
        }

        DETOUR_TRACE(("  Try %p => %p..%p %6lx\n",
                      pbTry,
                      mbi.BaseAddress,
                      (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
                      mbi.State));

        if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {

            PVOID pv = VirtualAlloc(pbTry,
                                    DETOUR_REGION_SIZE,
                                    MEM_COMMIT|MEM_RESERVE,
                                    PAGE_EXECUTE_READWRITE);
            if (pv != NULL) {
                return pv;
            }
            pbTry += DETOUR_REGION_SIZE;
        }
        else {
            pbTry = detour_alloc_round_up_to_region((PBYTE)mbi.BaseAddress + mbi.RegionSize);
        }
    }
    return NULL;
}

// Starting at pbHi, try to allocate a memory region, continue until pbLo.

static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
{
    PBYTE pbTry = detour_alloc_round_down_to_region(pbHi - DETOUR_REGION_SIZE);

    DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));

    for (; pbTry > pbLo;) {
        MEMORY_BASIC_INFORMATION mbi;

        DETOUR_TRACE(("  Try %p\n", pbTry));
        if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
            // Skip region reserved for system DLLs, but preserve address space entropy.
            pbTry -= 0x08000000;
            continue;
        }

        ZeroMemory(&mbi, sizeof(mbi));
        if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
            break;
        }

        DETOUR_TRACE(("  Try %p => %p..%p %6lx\n",
                      pbTry,
                      mbi.BaseAddress,
                      (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
                      mbi.State));

        if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {

            PVOID pv = VirtualAlloc(pbTry,
                                    DETOUR_REGION_SIZE,
                                    MEM_COMMIT|MEM_RESERVE,
                                    PAGE_EXECUTE_READWRITE);
            if (pv != NULL) {
                return pv;
            }
            pbTry -= DETOUR_REGION_SIZE;
        }
        else {
            pbTry = detour_alloc_round_down_to_region((PBYTE)mbi.AllocationBase
                                                      - DETOUR_REGION_SIZE);
        }
    }
    return NULL;
}

static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
{
    // We have to place trampolines within +/- 2GB of target.

    PDETOUR_TRAMPOLINE pLo;
    PDETOUR_TRAMPOLINE pHi;

    detour_find_jmp_bounds(pbTarget, &pLo, &pHi);

    PDETOUR_TRAMPOLINE pTrampoline = NULL;

    // Insure that there is a default region.
    if (s_pRegion == NULL && s_pRegions != NULL) {
        s_pRegion = s_pRegions;
    }

    // First check the default region for an valid free block.
    if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
        s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {

      found_region:
        pTrampoline = s_pRegion->pFree;
        // do a last sanity check on region.
        if (pTrampoline < pLo || pTrampoline > pHi) {
            return NULL;
        }
        s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain;
        memset(pTrampoline, 0xcc, sizeof(*pTrampoline));
        return pTrampoline;
    }

    // Then check the existing regions for a valid free block.
    for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) {
        if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
            s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
            goto found_region;
        }
    }

    // We need to allocate a new region.

    // Round pbTarget down to 64KB block.
    pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff);

    PVOID pbTry = NULL;

    // NB: We must always also start the search at an offset from pbTarget
    //     in order to maintain ASLR entropy.

#if defined(DETOURS_64BIT)
    // Try looking 1GB below or lower.
    if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
        pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000);
    }
    // Try looking 1GB above or higher.
    if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
        pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi);
    }
    // Try looking 1GB below or higher.
    if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
        pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget);
    }
    // Try looking 1GB above or lower.
    if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
        pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000);
    }
#endif

    // Try anything below.
    if (pbTry == NULL) {
        pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget);
    }
    // try anything above.
    if (pbTry == NULL) {
        pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi);
    }

    if (pbTry != NULL) {
        s_pRegion = (DETOUR_REGION*)pbTry;
        s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;
        s_pRegion->pFree = NULL;
        s_pRegion->pNext = s_pRegions;
        s_pRegions = s_pRegion;
        DETOUR_TRACE(("  Allocated region %p..%p\n\n",
                      (void*)s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1));

        // Put everything but the first trampoline on the free list.
        PBYTE pFree = NULL;
        pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1;
        for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) {
            pTrampoline[i].pbRemain = pFree;
            pFree = (PBYTE)&pTrampoline[i];
        }
        s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree;
        goto found_region;
    }

    DETOUR_TRACE(("Couldn't find available memory region!\n"));
    return NULL;
}

static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
{
    PDETOUR_REGION pRegion = (PDETOUR_REGION)
        ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff);

    memset(pTrampoline, 0, sizeof(*pTrampoline));
    pTrampoline->pbRemain = (PBYTE)pRegion->pFree;
    pRegion->pFree = pTrampoline;
}

static BOOL detour_is_region_empty(PDETOUR_REGION pRegion)
{
    // Stop if the region isn't a region (this would be bad).
    if (pRegion->dwSignature != DETOUR_REGION_SIGNATURE) {
        return FALSE;
    }

    PBYTE pbRegionBeg = (PBYTE)pRegion;
    PBYTE pbRegionLim  = pbRegionBeg + DETOUR_REGION_SIZE;

    // Stop if any of the trampolines aren't free.
    PDETOUR_TRAMPOLINE pTrampoline = ((PDETOUR_TRAMPOLINE)pRegion) + 1;
    for (int i = 0; i < DETOUR_TRAMPOLINES_PER_REGION; i++) {
        if (pTrampoline[i].pbRemain != NULL &&
            (pTrampoline[i].pbRemain < pbRegionBeg ||
             pTrampoline[i].pbRemain >= pbRegionLim)) {
            return FALSE;
        }
    }

    // OK, the region is empty.
    return TRUE;
}

static void detour_free_unused_trampoline_regions()
{
    PDETOUR_REGION *ppRegionBase = &s_pRegions;
    PDETOUR_REGION pRegion = s_pRegions;

    while (pRegion != NULL) {
        if (detour_is_region_empty(pRegion)) {
            *ppRegionBase = pRegion->pNext;

            VirtualFree(pRegion, 0, MEM_RELEASE);
            s_pRegion = NULL;
        }
        else {
            ppRegionBase = &pRegion->pNext;
        }
        pRegion = *ppRegionBase;
    }
}

///////////////////////////////////////////////////////// Transaction Structs.
//
struct DetourThread
{
    DetourThread *      pNext;
    HANDLE              hThread;
};

struct DetourOperation
{
    DetourOperation *   pNext;
    BOOL                fIsRemove;
    PBYTE *             ppbPointer;
    PBYTE               pbTarget;
    PDETOUR_TRAMPOLINE  pTrampoline;
    ULONG               dwPerm;
};

static BOOL                 s_fIgnoreTooSmall       = FALSE;
static BOOL                 s_fRetainRegions        = FALSE;

static LONG                 s_nPendingThreadId      = 0; // Thread owning pending transaction.
static LONG                 s_nPendingError         = NO_ERROR;
static PVOID *              s_ppPendingError        = NULL;
static DetourThread *       s_pPendingThreads       = NULL;
static DetourOperation *    s_pPendingOperations    = NULL;

//////////////////////////////////////////////////////////////////////////////
//
PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
                                   _Out_opt_ PVOID *ppGlobals)
{
    return detour_skip_jmp((PBYTE)pPointer, ppGlobals);
}

//////////////////////////////////////////////////////////// Transaction APIs.
//
BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore)
{
    BOOL fPrevious = s_fIgnoreTooSmall;
    s_fIgnoreTooSmall = fIgnore;
    return fPrevious;
}

BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain)
{
    BOOL fPrevious = s_fRetainRegions;
    s_fRetainRegions = fRetain;
    return fPrevious;
}

PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound)
{
    PVOID pPrevious = s_pSystemRegionLowerBound;
    s_pSystemRegionLowerBound = pSystemRegionLowerBound;
    return pPrevious;
}

PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound)
{
    PVOID pPrevious = s_pSystemRegionUpperBound;
    s_pSystemRegionUpperBound = pSystemRegionUpperBound;
    return pPrevious;
}

LONG WINAPI DetourTransactionBegin()
{
    // Only one transaction is allowed at a time.
_Benign_race_begin_
    if (s_nPendingThreadId != 0) {
        return ERROR_INVALID_OPERATION;
    }
_Benign_race_end_

    // Make sure only one thread can start a transaction.
    if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) {
        return ERROR_INVALID_OPERATION;
    }

    s_pPendingOperations = NULL;
    s_pPendingThreads = NULL;
    s_ppPendingError = NULL;

    // Make sure the trampoline pages are writable.
    s_nPendingError = detour_writable_trampoline_regions();

    return s_nPendingError;
}

LONG WINAPI DetourTransactionAbort()
{
    if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
        return ERROR_INVALID_OPERATION;
    }

    // Restore all of the page permissions.
    for (DetourOperation *o = s_pPendingOperations; o != NULL;) {
        // We don't care if this fails, because the code is still accessible.
        DWORD dwOld;
        VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore,
                       o->dwPerm, &dwOld);

        if (!o->fIsRemove) {
            if (o->pTrampoline) {
                detour_free_trampoline(o->pTrampoline);
                o->pTrampoline = NULL;
            }
        }

        DetourOperation *n = o->pNext;
        delete o;
        o = n;
    }
    s_pPendingOperations = NULL;

    // Make sure the trampoline pages are no longer writable.
    detour_runnable_trampoline_regions();

    // Resume any suspended threads.
    for (DetourThread *t = s_pPendingThreads; t != NULL;) {
        // There is nothing we can do if this fails.
        ResumeThread(t->hThread);

        DetourThread *n = t->pNext;
        delete t;
        t = n;
    }
    s_pPendingThreads = NULL;
    s_nPendingThreadId = 0;

    return NO_ERROR;
}

LONG WINAPI DetourTransactionCommit()
{
    return DetourTransactionCommitEx(NULL);
}

static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline, BYTE obTrampoline)
{
    for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
        if (pTrampoline->rAlign[n].obTrampoline == obTrampoline) {
            return pTrampoline->rAlign[n].obTarget;
        }
    }
    return 0;
}

static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LONG obTarget)
{
    for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
        if (pTrampoline->rAlign[n].obTarget == obTarget) {
            return pTrampoline->rAlign[n].obTrampoline;
        }
    }
    return 0;
}

LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
{
    if (pppFailedPointer != NULL) {
        // Used to get the last error.
        *pppFailedPointer = s_ppPendingError;
    }
    if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
        return ERROR_INVALID_OPERATION;
    }

    // If any of the pending operations failed, then we abort the whole transaction.
    if (s_nPendingError != NO_ERROR) {
        DETOUR_BREAK();
        DetourTransactionAbort();
        return s_nPendingError;
    }

    // Common variables.
    DetourOperation *o;
    DetourThread *t;
    BOOL freed = FALSE;

    // Insert or remove each of the detours.
    for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
        if (o->fIsRemove) {
            CopyMemory(o->pbTarget,
                       o->pTrampoline->rbRestore,
                       o->pTrampoline->cbRestore);
#ifdef DETOURS_IA64
            *o->ppbPointer = (PBYTE)o->pTrampoline->ppldTarget;
#endif // DETOURS_IA64

#ifdef DETOURS_X86
            *o->ppbPointer = o->pbTarget;
#endif // DETOURS_X86

#ifdef DETOURS_X64
            *o->ppbPointer = o->pbTarget;
#endif // DETOURS_X64

#ifdef DETOURS_ARM
            *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pbTarget);
#endif // DETOURS_ARM

#ifdef DETOURS_ARM64
            *o->ppbPointer = o->pbTarget;
#endif // DETOURS_ARM
        }
        else {
            DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n",
                          (void*)o->pTrampoline,
                          o->pTrampoline->pbRemain,
                          o->pTrampoline->pbDetour,
                          o->pTrampoline->cbRestore));

            DETOUR_TRACE(("detours: pbTarget=%p: "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x [before]\n",
                          o->pbTarget,
                          o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
                          o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
                          o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));

#ifdef DETOURS_IA64
            ((DETOUR_IA64_BUNDLE*)o->pbTarget)
                ->SetBrl((UINT64)&o->pTrampoline->bAllocFrame);
            *o->ppbPointer = (PBYTE)&o->pTrampoline->pldTrampoline;
#endif // DETOURS_IA64

#ifdef DETOURS_X64
            detour_gen_jmp_indirect(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour);
            PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->rbCodeIn);
            pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
            *o->ppbPointer = o->pTrampoline->rbCode;
            UNREFERENCED_PARAMETER(pbCode);
#endif // DETOURS_X64

#ifdef DETOURS_X86
            PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour);
            pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
            *o->ppbPointer = o->pTrampoline->rbCode;
            UNREFERENCED_PARAMETER(pbCode);
#endif // DETOURS_X86

#ifdef DETOURS_ARM
            PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
            pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
            *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pTrampoline->rbCode);
            UNREFERENCED_PARAMETER(pbCode);
#endif // DETOURS_ARM

#ifdef DETOURS_ARM64
            PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
            pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
            *o->ppbPointer = o->pTrampoline->rbCode;
            UNREFERENCED_PARAMETER(pbCode);
#endif // DETOURS_ARM64

            DETOUR_TRACE(("detours: pbTarget=%p: "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x [after]\n",
                          o->pbTarget,
                          o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
                          o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
                          o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));

            DETOUR_TRACE(("detours: pbTramp =%p: "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x "
                          "%02x %02x %02x %02x\n",
                          (void*)o->pTrampoline,
                          o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1],
                          o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3],
                          o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5],
                          o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7],
                          o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9],
                          o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11]));

#ifdef DETOURS_IA64
            DETOUR_TRACE(("\n"));
            DETOUR_TRACE(("detours:  &pldTrampoline  =%p\n",
                          &o->pTrampoline->pldTrampoline));
            DETOUR_TRACE(("detours:  &bMovlTargetGp  =%p [%p]\n",
                          &o->pTrampoline->bMovlTargetGp,
                          o->pTrampoline->bMovlTargetGp.GetMovlGp()));
            DETOUR_TRACE(("detours:  &rbCode         =%p [%p]\n",
                          &o->pTrampoline->rbCode,
                          ((DETOUR_IA64_BUNDLE&)o->pTrampoline->rbCode).GetBrlTarget()));
            DETOUR_TRACE(("detours:  &bBrlRemainEip  =%p [%p]\n",
                          &o->pTrampoline->bBrlRemainEip,
                          o->pTrampoline->bBrlRemainEip.GetBrlTarget()));
            DETOUR_TRACE(("detours:  &bMovlDetourGp  =%p [%p]\n",
                          &o->pTrampoline->bMovlDetourGp,
                          o->pTrampoline->bMovlDetourGp.GetMovlGp()));
            DETOUR_TRACE(("detours:  &bBrlDetourEip  =%p [%p]\n",
                          &o->pTrampoline->bCallDetour,
                          o->pTrampoline->bCallDetour.GetBrlTarget()));
            DETOUR_TRACE(("detours:  pldDetour       =%p [%p]\n",
                          o->pTrampoline->ppldDetour->EntryPoint,
                          o->pTrampoline->ppldDetour->GlobalPointer));
            DETOUR_TRACE(("detours:  pldTarget       =%p [%p]\n",
                          o->pTrampoline->ppldTarget->EntryPoint,
                          o->pTrampoline->ppldTarget->GlobalPointer));
            DETOUR_TRACE(("detours:  pbRemain        =%p\n",
                          o->pTrampoline->pbRemain));
            DETOUR_TRACE(("detours:  pbDetour        =%p\n",
                          o->pTrampoline->pbDetour));
            DETOUR_TRACE(("\n"));
#endif // DETOURS_IA64
        }
    }

    // Update any suspended threads.
    for (t = s_pPendingThreads; t != NULL; t = t->pNext) {
        CONTEXT cxt;
        cxt.ContextFlags = CONTEXT_CONTROL;

#undef DETOURS_EIP

#ifdef DETOURS_X86
#define DETOURS_EIP         Eip
#endif // DETOURS_X86

#ifdef DETOURS_X64
#define DETOURS_EIP         Rip
#endif // DETOURS_X64

#ifdef DETOURS_IA64
#define DETOURS_EIP         StIIP
#endif // DETOURS_IA64

#ifdef DETOURS_ARM
#define DETOURS_EIP         Pc
#endif // DETOURS_ARM

#ifdef DETOURS_ARM64
#define DETOURS_EIP         Pc
#endif // DETOURS_ARM64

typedef ULONG_PTR DETOURS_EIP_TYPE;

        if (GetThreadContext(t->hThread, &cxt)) {
            for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
                if (o->fIsRemove) {
                    if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline &&
                        cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline
                                                             + sizeof(o->pTrampoline))
                       ) {

                        cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
                            ((ULONG_PTR)o->pbTarget
                             + detour_align_from_trampoline(o->pTrampoline,
                                                            (BYTE)(cxt.DETOURS_EIP
                                                                   - (DETOURS_EIP_TYPE)(ULONG_PTR)
                                                                   o->pTrampoline)));

                        SetThreadContext(t->hThread, &cxt);
                    }
                }
                else {
                    if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget &&
                        cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget
                                                             + o->pTrampoline->cbRestore)
                       ) {

                        cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
                            ((ULONG_PTR)o->pTrampoline
                             + detour_align_from_target(o->pTrampoline,
                                                        (BYTE)(cxt.DETOURS_EIP
                                                               - (DETOURS_EIP_TYPE)(ULONG_PTR)
                                                               o->pbTarget)));

                        SetThreadContext(t->hThread, &cxt);
                    }
                }
            }
        }
#undef DETOURS_EIP
    }

    // Restore all of the page permissions and flush the icache.
    HANDLE hProcess = GetCurrentProcess();
    for (o = s_pPendingOperations; o != NULL;) {
        // We don't care if this fails, because the code is still accessible.
        DWORD dwOld;
        VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, o->dwPerm, &dwOld);
        FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore);

        if (o->fIsRemove && o->pTrampoline) {
            detour_free_trampoline(o->pTrampoline);
            o->pTrampoline = NULL;
            freed = true;
        }

        DetourOperation *n = o->pNext;
        delete o;
        o = n;
    }
    s_pPendingOperations = NULL;

    // Free any trampoline regions that are now unused.
    if (freed && !s_fRetainRegions) {
        detour_free_unused_trampoline_regions();
    }

    // Make sure the trampoline pages are no longer writable.
    detour_runnable_trampoline_regions();

    // Resume any suspended threads.
    for (t = s_pPendingThreads; t != NULL;) {
        // There is nothing we can do if this fails.
        ResumeThread(t->hThread);

        DetourThread *n = t->pNext;
        delete t;
        t = n;
    }
    s_pPendingThreads = NULL;
    s_nPendingThreadId = 0;

    if (pppFailedPointer != NULL) {
        *pppFailedPointer = s_ppPendingError;
    }

    return s_nPendingError;
}

LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread)
{
    LONG error;

    // If any of the pending operations failed, then we don't need to do this.
    if (s_nPendingError != NO_ERROR) {
        return s_nPendingError;
    }

    // Silently (and safely) drop any attempt to suspend our own thread.
    if (hThread == GetCurrentThread()) {
        return NO_ERROR;
    }

    DetourThread *t = new NOTHROW DetourThread;
    if (t == NULL) {
        error = ERROR_NOT_ENOUGH_MEMORY;
      fail:
        if (t != NULL) {
            delete t;
            t = NULL;
        }
        s_nPendingError = error;
        s_ppPendingError = NULL;
        DETOUR_BREAK();
        return error;
    }

    if (SuspendThread(hThread) == (DWORD)-1) {
        error = (LONG)GetLastError();
        DETOUR_BREAK();
        goto fail;
    }

    t->hThread = hThread;
    t->pNext = s_pPendingThreads;
    s_pPendingThreads = t;

    return NO_ERROR;
}

///////////////////////////////////////////////////////////// Transacted APIs.
//
LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
                         _In_ PVOID pDetour)
{
    return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL);
}

LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
                           _In_ PVOID pDetour,
                           _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
                           _Out_opt_ PVOID *ppRealTarget,
                           _Out_opt_ PVOID *ppRealDetour)
{
    LONG error = NO_ERROR;

    if (ppRealTrampoline != NULL) {
        *ppRealTrampoline = NULL;
    }
    if (ppRealTarget != NULL) {
        *ppRealTarget = NULL;
    }
    if (ppRealDetour != NULL) {
        *ppRealDetour = NULL;
    }
    if (pDetour == NULL) {
        DETOUR_TRACE(("empty detour\n"));
        return ERROR_INVALID_PARAMETER;
    }

    if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
        DETOUR_TRACE(("transaction conflict with thread id=%ld\n", s_nPendingThreadId));
        return ERROR_INVALID_OPERATION;
    }

    // If any of the pending operations failed, then we don't need to do this.
    if (s_nPendingError != NO_ERROR) {
        DETOUR_TRACE(("pending transaction error=%ld\n", s_nPendingError));
        return s_nPendingError;
    }

    if (ppPointer == NULL) {
        DETOUR_TRACE(("ppPointer is null\n"));
        return ERROR_INVALID_HANDLE;
    }
    if (*ppPointer == NULL) {
        error = ERROR_INVALID_HANDLE;
        s_nPendingError = error;
        s_ppPendingError = ppPointer;
        DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", (void*)ppPointer));
        DETOUR_BREAK();
        return error;
    }

    PBYTE pbTarget = (PBYTE)*ppPointer;
    PDETOUR_TRAMPOLINE pTrampoline = NULL;
    DetourOperation *o = NULL;

#ifdef DETOURS_IA64
    PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
    PPLABEL_DESCRIPTOR ppldTarget = (PPLABEL_DESCRIPTOR)pbTarget;
    PVOID pDetourGlobals = NULL;
    PVOID pTargetGlobals = NULL;

    pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
    pbTarget = (PBYTE)DetourCodeFromPointer(ppldTarget, &pTargetGlobals);
    DETOUR_TRACE(("  ppldDetour=%p, code=%p [gp=%p]\n",
                  ppldDetour, pDetour, pDetourGlobals));
    DETOUR_TRACE(("  ppldTarget=%p, code=%p [gp=%p]\n",
                  ppldTarget, pbTarget, pTargetGlobals));
#else // DETOURS_IA64
    pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL);
    pDetour = DetourCodeFromPointer(pDetour, NULL);
#endif // !DETOURS_IA64

    // Don't follow a jump if its destination is the target function.
    // This happens when the detour does nothing other than call the target.
    if (pDetour == (PVOID)pbTarget) {
        if (s_fIgnoreTooSmall) {
            goto stop;
        }
        else {
            DETOUR_BREAK();
            goto fail;
        }
    }

    if (ppRealTarget != NULL) {
        *ppRealTarget = pbTarget;
    }
    if (ppRealDetour != NULL) {
        *ppRealDetour = pDetour;
    }

    o = new NOTHROW DetourOperation;
    if (o == NULL) {
        error = ERROR_NOT_ENOUGH_MEMORY;
      fail:
        s_nPendingError = error;
        DETOUR_BREAK();
      stop:
        if (pTrampoline != NULL) {
            detour_free_trampoline(pTrampoline);
            pTrampoline = NULL;
            if (ppRealTrampoline != NULL) {
                *ppRealTrampoline = NULL;
            }
        }
        if (o != NULL) {
            delete o;
            o = NULL;
        }
        s_ppPendingError = ppPointer;
        return error;
    }

    pTrampoline = detour_alloc_trampoline(pbTarget);
    if (pTrampoline == NULL) {
        error = ERROR_NOT_ENOUGH_MEMORY;
        DETOUR_BREAK();
        goto fail;
    }

    if (ppRealTrampoline != NULL) {
        *ppRealTrampoline = pTrampoline;
    }

    DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", (void*)pTrampoline, pDetour));

    memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign));

    // Determine the number of movable target instructions.
    PBYTE pbSrc = pbTarget;
    PBYTE pbTrampoline = pTrampoline->rbCode;
#ifdef DETOURS_IA64
    PBYTE pbPool = (PBYTE)(&pTrampoline->bBranchIslands + 1);
#else
    PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode);
#endif
    ULONG cbTarget = 0;
    ULONG cbJump = SIZE_OF_JMP;
    ULONG nAlign = 0;

#ifdef DETOURS_ARM
    // On ARM, we need an extra instruction when the function isn't 32-bit aligned.
    // Check if the existing code is another detour (or at least a similar
    // "ldr pc, [PC+0]" jump.
    if ((ULONG)pbTarget & 2) {
        cbJump += 2;

        ULONG op = fetch_thumb_opcode(pbSrc);
        if (op == 0xbf00) {
            op = fetch_thumb_opcode(pbSrc + 2);
            if (op == 0xf8dff000) { // LDR PC,[PC]
                *((PUSHORT&)pbTrampoline)++ = *((PUSHORT&)pbSrc)++;
                *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
                *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
                cbTarget = (LONG)(pbSrc - pbTarget);
                // We will fall through the "while" because cbTarget is now >= cbJump.
            }
        }
    }
    else {
        ULONG op = fetch_thumb_opcode(pbSrc);
        if (op == 0xf8dff000) { // LDR PC,[PC]
            *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
            *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
            cbTarget = (LONG)(pbSrc - pbTarget);
            // We will fall through the "while" because cbTarget is now >= cbJump.
        }
    }
#endif

    while (cbTarget < cbJump) {
        PBYTE pbOp = pbSrc;
        LONG lExtra = 0;

        DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n",
                      pbTrampoline, pbSrc));
        pbSrc = (PBYTE)
            DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra);
        DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n",
                      pbSrc, (int)(pbSrc - pbOp)));
        pbTrampoline += (pbSrc - pbOp) + lExtra;
        cbTarget = (LONG)(pbSrc - pbTarget);
        pTrampoline->rAlign[nAlign].obTarget = cbTarget;
        pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode;
        nAlign++;

        if (nAlign >= ARRAYSIZE(pTrampoline->rAlign)) {
            break;
        }

        if (detour_does_code_end_function(pbOp)) {
            break;
        }
    }

    // Consume, but don't duplicate padding if it is needed and available.
    while (cbTarget < cbJump) {
        LONG cFiller = detour_is_code_filler(pbSrc);
        if (cFiller == 0) {
            break;
        }

        pbSrc += cFiller;
        cbTarget = (LONG)(pbSrc - pbTarget);
    }

#if DETOUR_DEBUG
    {
        DETOUR_TRACE((" detours: rAlign ["));
        LONG n = 0;
        for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
            if (pTrampoline->rAlign[n].obTarget == 0 &&
                pTrampoline->rAlign[n].obTrampoline == 0) {
                break;
            }
            DETOUR_TRACE((" %d/%d",
                          pTrampoline->rAlign[n].obTarget,
                          pTrampoline->rAlign[n].obTrampoline
                          ));

        }
        DETOUR_TRACE((" ]\n"));
    }
#endif

    if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) {
        // Too few instructions.

        error = ERROR_INVALID_BLOCK;
        if (s_fIgnoreTooSmall) {
            goto stop;
        }
        else {
            DETOUR_BREAK();
            goto fail;
        }
    }

    if (pbTrampoline > pbPool) {
        __debugbreak();
    }

    pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode);
    pTrampoline->cbRestore = (BYTE)cbTarget;
    CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget);

#if !defined(DETOURS_IA64)
    if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) {
        // Too many instructions.
        error = ERROR_INVALID_HANDLE;
        DETOUR_BREAK();
        goto fail;
    }
#endif // !DETOURS_IA64

    pTrampoline->pbRemain = pbTarget + cbTarget;
    pTrampoline->pbDetour = (PBYTE)pDetour;

#ifdef DETOURS_IA64
    pTrampoline->ppldDetour = ppldDetour;
    pTrampoline->ppldTarget = ppldTarget;
    pTrampoline->pldTrampoline.EntryPoint = (UINT64)&pTrampoline->bMovlTargetGp;
    pTrampoline->pldTrampoline.GlobalPointer = (UINT64)pDetourGlobals;

    ((DETOUR_IA64_BUNDLE *)pTrampoline->rbCode)->SetStop();

    pTrampoline->bMovlTargetGp.SetMovlGp((UINT64)pTargetGlobals);
    pTrampoline->bBrlRemainEip.SetBrl((UINT64)pTrampoline->pbRemain);

    // Alloc frame:      alloc r41=ar.pfs,11,0,8,0; mov r40=rp
    pTrampoline->bAllocFrame.wide[0] = 0x00000580164d480c;
    pTrampoline->bAllocFrame.wide[1] = 0x00c4000500000200;
    // save r36, r37, r38.
    pTrampoline->bSave37to39.wide[0] = 0x031021004e019001;
    pTrampoline->bSave37to39.wide[1] = 0x8401280600420098;
    // save r34,r35,r36: adds r47=0,r36; adds r46=0,r35; adds r45=0,r34
    pTrampoline->bSave34to36.wide[0] = 0x02e0210048017800;
    pTrampoline->bSave34to36.wide[1] = 0x84011005a042008c;
    // save gp,r32,r33"  adds r44=0,r33; adds r43=0,r32; adds r42=0,gp ;;
    pTrampoline->bSaveGPto33.wide[0] = 0x02b0210042016001;
    pTrampoline->bSaveGPto33.wide[1] = 0x8400080540420080;
    // set detour GP.
    pTrampoline->bMovlDetourGp.SetMovlGp((UINT64)pDetourGlobals);
    // call detour:      brl.call.sptk.few rp=detour ;;
    pTrampoline->bCallDetour.wide[0] = 0x0000000100000005;
    pTrampoline->bCallDetour.wide[1] = 0xd000001000000000;
    pTrampoline->bCallDetour.SetBrlTarget((UINT64)pDetour);
    // pop frame & gp:   adds gp=0,r42; mov rp=r40,+0;; mov.i ar.pfs=r41
    pTrampoline->bPopFrameGp.wide[0] = 0x4000210054000802;
    pTrampoline->bPopFrameGp.wide[1] = 0x00aa029000038005;
    // return to caller: br.ret.sptk.many rp ;;
    pTrampoline->bReturn.wide[0] = 0x0000000100000019;
    pTrampoline->bReturn.wide[1] = 0x0084000880000200;

    DETOUR_TRACE(("detours: &bMovlTargetGp=%p\n", &pTrampoline->bMovlTargetGp));
    DETOUR_TRACE(("detours: &bMovlDetourGp=%p\n", &pTrampoline->bMovlDetourGp));
#endif // DETOURS_IA64

    pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode;
#ifdef DETOURS_X64
    pbTrampoline = detour_gen_jmp_indirect(pbTrampoline, &pTrampoline->pbRemain);
    pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
#endif // DETOURS_X64

#ifdef DETOURS_X86
    pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain);
    pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
#endif // DETOURS_X86

#ifdef DETOURS_ARM
    pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
    pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
#endif // DETOURS_ARM

#ifdef DETOURS_ARM64
    pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
    pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
#endif // DETOURS_ARM64

    (void)pbTrampoline;

    DWORD dwOld = 0;
    if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) {
        error = GetLastError();
        DETOUR_BREAK();
        goto fail;
    }

    DETOUR_TRACE(("detours: pbTarget=%p: "
                  "%02x %02x %02x %02x "
                  "%02x %02x %02x %02x "
                  "%02x %02x %02x %02x\n",
                  pbTarget,
                  pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3],
                  pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7],
                  pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11]));
    DETOUR_TRACE(("detours: pbTramp =%p: "
                  "%02x %02x %02x %02x "
                  "%02x %02x %02x %02x "
                  "%02x %02x %02x %02x\n",
                  (void*)pTrampoline,
                  pTrampoline->rbCode[0], pTrampoline->rbCode[1],
                  pTrampoline->rbCode[2], pTrampoline->rbCode[3],
                  pTrampoline->rbCode[4], pTrampoline->rbCode[5],
                  pTrampoline->rbCode[6], pTrampoline->rbCode[7],
                  pTrampoline->rbCode[8], pTrampoline->rbCode[9],
                  pTrampoline->rbCode[10], pTrampoline->rbCode[11]));

    o->fIsRemove = FALSE;
    o->ppbPointer = (PBYTE*)ppPointer;
    o->pTrampoline = pTrampoline;
    o->pbTarget = pbTarget;
    o->dwPerm = dwOld;
    o->pNext = s_pPendingOperations;
    s_pPendingOperations = o;

    return NO_ERROR;
}

LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
                         _In_ PVOID pDetour)
{
    LONG error = NO_ERROR;

    if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
        return ERROR_INVALID_OPERATION;
    }

    // If any of the pending operations failed, then we don't need to do this.
    if (s_nPendingError != NO_ERROR) {
        return s_nPendingError;
    }

    if (pDetour == NULL) {
        return ERROR_INVALID_PARAMETER;
    }
    if (ppPointer == NULL) {
        return ERROR_INVALID_HANDLE;
    }
    if (*ppPointer == NULL) {
        error = ERROR_INVALID_HANDLE;
        s_nPendingError = error;
        s_ppPendingError = ppPointer;
        DETOUR_BREAK();
        return error;
    }

    DetourOperation *o = new NOTHROW DetourOperation;
    if (o == NULL) {
        error = ERROR_NOT_ENOUGH_MEMORY;
      fail:
        s_nPendingError = error;
        DETOUR_BREAK();
      stop:
        if (o != NULL) {
            delete o;
            o = NULL;
        }
        s_ppPendingError = ppPointer;
        return error;
    }


#ifdef DETOURS_IA64
    PPLABEL_DESCRIPTOR ppldTrampo = (PPLABEL_DESCRIPTOR)*ppPointer;
    PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
    PVOID pDetourGlobals = NULL;
    PVOID pTrampoGlobals = NULL;

    pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
    PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE)
        DetourCodeFromPointer(ppldTrampo, &pTrampoGlobals);
    DETOUR_TRACE(("  ppldDetour=%p, code=%p [gp=%p]\n",
                  ppldDetour, pDetour, pDetourGlobals));
    DETOUR_TRACE(("  ppldTrampo=%p, code=%p [gp=%p]\n",
                  ppldTrampo, pTrampoline, pTrampoGlobals));


    DETOUR_TRACE(("\n"));
    DETOUR_TRACE(("detours:  &pldTrampoline  =%p\n",
                  &pTrampoline->pldTrampoline));
    DETOUR_TRACE(("detours:  &bMovlTargetGp  =%p [%p]\n",
                  &pTrampoline->bMovlTargetGp,
                  pTrampoline->bMovlTargetGp.GetMovlGp()));
    DETOUR_TRACE(("detours:  &rbCode         =%p [%p]\n",
                  &pTrampoline->rbCode,
                  ((DETOUR_IA64_BUNDLE&)pTrampoline->rbCode).GetBrlTarget()));
    DETOUR_TRACE(("detours:  &bBrlRemainEip  =%p [%p]\n",
                  &pTrampoline->bBrlRemainEip,
                  pTrampoline->bBrlRemainEip.GetBrlTarget()));
    DETOUR_TRACE(("detours:  &bMovlDetourGp  =%p [%p]\n",
                  &pTrampoline->bMovlDetourGp,
                  pTrampoline->bMovlDetourGp.GetMovlGp()));
    DETOUR_TRACE(("detours:  &bBrlDetourEip  =%p [%p]\n",
                  &pTrampoline->bCallDetour,
                  pTrampoline->bCallDetour.GetBrlTarget()));
    DETOUR_TRACE(("detours:  pldDetour       =%p [%p]\n",
                  pTrampoline->ppldDetour->EntryPoint,
                  pTrampoline->ppldDetour->GlobalPointer));
    DETOUR_TRACE(("detours:  pldTarget       =%p [%p]\n",
                  pTrampoline->ppldTarget->EntryPoint,
                  pTrampoline->ppldTarget->GlobalPointer));
    DETOUR_TRACE(("detours:  pbRemain        =%p\n",
                  pTrampoline->pbRemain));
    DETOUR_TRACE(("detours:  pbDetour        =%p\n",
                  pTrampoline->pbDetour));
    DETOUR_TRACE(("\n"));
#else // !DETOURS_IA64
    PDETOUR_TRAMPOLINE pTrampoline =
        (PDETOUR_TRAMPOLINE)DetourCodeFromPointer(*ppPointer, NULL);
    pDetour = DetourCodeFromPointer(pDetour, NULL);
#endif // !DETOURS_IA64

    ////////////////////////////////////// Verify that Trampoline is in place.
    //
    LONG cbTarget = pTrampoline->cbRestore;
    PBYTE pbTarget = pTrampoline->pbRemain - cbTarget;
    if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) {
        error = ERROR_INVALID_BLOCK;
        if (s_fIgnoreTooSmall) {
            goto stop;
        }
        else {
            DETOUR_BREAK();
            goto fail;
        }
    }

    if (pTrampoline->pbDetour != pDetour) {
        error = ERROR_INVALID_BLOCK;
        if (s_fIgnoreTooSmall) {
            goto stop;
        }
        else {
            DETOUR_BREAK();
            goto fail;
        }
    }

    DWORD dwOld = 0;
    if (!VirtualProtect(pbTarget, cbTarget,
                        PAGE_EXECUTE_READWRITE, &dwOld)) {
        error = (LONG)GetLastError();
        DETOUR_BREAK();
        goto fail;
    }

    o->fIsRemove = TRUE;
    o->ppbPointer = (PBYTE*)ppPointer;
    o->pTrampoline = pTrampoline;
    o->pbTarget = pbTarget;
    o->dwPerm = dwOld;
    o->pNext = s_pPendingOperations;
    s_pPendingOperations = o;

    return NO_ERROR;
}

//////////////////////////////////////////////////////////////////////////////
//
// Helpers for manipulating page protection.
//

// For reference:
//   PAGE_NOACCESS          0x01
//   PAGE_READONLY          0x02
//   PAGE_READWRITE         0x04
//   PAGE_WRITECOPY         0x08
//   PAGE_EXECUTE           0x10
//   PAGE_EXECUTE_READ      0x20
//   PAGE_EXECUTE_READWRITE 0x40
//   PAGE_EXECUTE_WRITECOPY 0x80
//   PAGE_GUARD             ...
//   PAGE_NOCACHE           ...
//   PAGE_WRITECOMBINE      ...

#define DETOUR_PAGE_EXECUTE_ALL    (PAGE_EXECUTE |              \
                                    PAGE_EXECUTE_READ |         \
                                    PAGE_EXECUTE_READWRITE |    \
                                    PAGE_EXECUTE_WRITECOPY)

#define DETOUR_PAGE_NO_EXECUTE_ALL (PAGE_NOACCESS |             \
                                    PAGE_READONLY |             \
                                    PAGE_READWRITE |            \
                                    PAGE_WRITECOPY)

#define DETOUR_PAGE_ATTRIBUTES     (~(DETOUR_PAGE_EXECUTE_ALL | DETOUR_PAGE_NO_EXECUTE_ALL))

C_ASSERT((DETOUR_PAGE_NO_EXECUTE_ALL << 4) == DETOUR_PAGE_EXECUTE_ALL);

static DWORD DetourPageProtectAdjustExecute(_In_  DWORD dwOldProtect,
                                            _In_  DWORD dwNewProtect)
//  Copy EXECUTE from dwOldProtect to dwNewProtect.
{
    bool const fOldExecute = ((dwOldProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);
    bool const fNewExecute = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);

    if (fOldExecute && !fNewExecute) {
        dwNewProtect = ((dwNewProtect & DETOUR_PAGE_NO_EXECUTE_ALL) << 4)
            | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
    }
    else if (!fOldExecute && fNewExecute) {
        dwNewProtect = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) >> 4)
            | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
    }
    return dwNewProtect;
}

_Success_(return != FALSE)
BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_  HANDLE hProcess,
                                              _In_  PVOID pAddress,
                                              _In_  SIZE_T nSize,
                                              _In_  DWORD dwNewProtect,
                                              _Out_ PDWORD pdwOldProtect)
// Some systems do not allow executability of a page to change. This function applies
// dwNewProtect to [pAddress, nSize), but preserving the previous executability.
// This function is meant to be a drop-in replacement for some uses of VirtualProtectEx.
// When "restoring" page protection, there is no need to use this function.
{
    MEMORY_BASIC_INFORMATION mbi;

    // Query to get existing execute access.

    ZeroMemory(&mbi, sizeof(mbi));

    if (VirtualQueryEx(hProcess, pAddress, &mbi, sizeof(mbi)) == 0) {
        return FALSE;
    }
    return VirtualProtectEx(hProcess, pAddress, nSize,
                            DetourPageProtectAdjustExecute(mbi.Protect, dwNewProtect),
                            pdwOldProtect);
}

_Success_(return != FALSE)
BOOL WINAPI DetourVirtualProtectSameExecute(_In_  PVOID pAddress,
                                            _In_  SIZE_T nSize,
                                            _In_  DWORD dwNewProtect,
                                            _Out_ PDWORD pdwOldProtect)
{
    return DetourVirtualProtectSameExecuteEx(GetCurrentProcess(),
                                             pAddress, nSize, dwNewProtect, pdwOldProtect);
}

//  End of File


================================================
FILE: Detours/detours.h
================================================
/////////////////////////////////////////////////////////////////////////////
//
//  Core Detours Functionality (detours.h of detours.lib)
//
//  Microsoft Research Detours Package, Version 4.0.1
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//

#pragma once
#ifndef _DETOURS_H_
#define _DETOURS_H_

#if defined(_KERNEL_MODE)
#define DETOURS_KERNEL
#endif

#ifdef DETOURS_KERNEL
#include <minwindef.h>
#include <ntimage.h>
#endif

#define DETOURS_VERSION     0x4c0c1   // 0xMAJORcMINORcPATCH

//////////////////////////////////////////////////////////////////////////////
//

#undef DETOURS_X64
#undef DETOURS_X86
#undef DETOURS_IA64
#undef DETOURS_ARM
#undef DETOURS_ARM64
#undef DETOURS_BITS
#undef DETOURS_32BIT
#undef DETOURS_64BIT

#if defined(_X86_)
#define DETOURS_X86
#define DETOURS_OPTION_BITS 64

#elif defined(_AMD64_)
#define DETOURS_X64
#define DETOURS_OPTION_BITS 32

#elif defined(_IA64_)
#define DETOURS_IA64
#define DETOURS_OPTION_BITS 32

#elif defined(_ARM_)
#define DETOURS_ARM

#elif defined(_ARM64_)
#define DETOURS_ARM64

#else
#error Unknown architecture (x86, amd64, ia64, arm, arm64)
#endif

#ifdef _WIN64
#undef DETOURS_32BIT
#define DETOURS_64BIT 1
#define DETOURS_BITS 64
// If all 64bit kernels can run one and only one 32bit architecture.
//#define DETOURS_OPTION_BITS 32
#else
#define DETOURS_32BIT 1
#undef DETOURS_64BIT
#define DETOURS_BITS 32
// If all 64bit kernels can run one and only one 32bit architecture.
//#define DETOURS_OPTION_BITS 32
#endif

#define VER_DETOURS_BITS    DETOUR_STRINGIFY(DETOURS_BITS)

//////////////////////////////////////////////////////////////////////////////
//

#if (_MSC_VER < 1299)
typedef LONG LONG_PTR;
typedef ULONG ULONG_PTR;
#endif

///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL.
//
//  These definitions are include so that Detours will build even if the
//  compiler doesn't have full SAL 2.0 support.
//
#ifndef DETOURS_DONT_REMOVE_SAL_20

#ifdef DETOURS_TEST_REMOVE_SAL_20
#undef _Analysis_assume_
#undef _Benign_race_begin_
#undef _Benign_race_end_
#undef _Field_range_
#undef _Field_size_
#undef _In_
#undef _In_bytecount_
#undef _In_count_
#undef _In_opt_
#undef _In_opt_bytecount_
#undef _In_opt_count_
#undef _In_opt_z_
#undef _In_range_
#undef _In_reads_
#undef _In_reads_bytes_
#undef _In_reads_opt_
#undef _In_reads_opt_bytes_
#undef _In_reads_or_z_
#undef _In_z_
#undef _Inout_
#undef _Inout_opt_
#undef _Inout_z_count_
#undef _Out_
#undef _Out_opt_
#undef _Out_writes_
#undef _Outptr_result_maybenull_
#undef _Readable_bytes_
#undef _Success_
#undef _Writable_bytes_
#undef _Pre_notnull_
#endif

#if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_)
#define _Outptr_result_maybenull_ _Deref_out_opt_z_
#endif

#if defined(_In_count_) && !defined(_In_reads_)
#define _In_reads_(x) _In_count_(x)
#endif

#if defined(_In_opt_count_) && !defined(_In_reads_opt_)
#define _In_reads_opt_(x) _In_opt_count_(x)
#endif

#if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_)
#define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x)
#endif

#if defined(_In_bytecount_) && !defined(_In_reads_bytes_)
#define _In_reads_bytes_(x) _In_bytecount_(x)
#endif

#ifndef _In_
#define _In_
#endif

#ifndef _In_bytecount_
#define _In_bytecount_(x)
#endif

#ifndef _In_count_
#define _In_count_(x)
#endif

#ifndef _In_opt_
#define _In_opt_
#endif

#ifndef _In_opt_bytecount_
#define _In_opt_bytecount_(x)
#endif

#ifndef _In_opt_count_
#define _In_opt_count_(x)
#endif

#ifndef _In_opt_z_
#define _In_opt_z_
#endif

#ifndef _In_range_
#define _In_range_(x,y)
#endif

#ifndef _In_reads_
#define _In_reads_(x)
#endif

#ifndef _In_reads_bytes_
#define _In_reads_bytes_(x)
#endif

#ifndef _In_reads_opt_
#define _In_reads_opt_(x)
#endif

#ifndef _In_reads_opt_bytes_
#define _In_reads_opt_bytes_(x)
#endif

#ifndef _In_reads_or_z_
#define _In_reads_or_z_
#endif

#ifndef _In_z_
#define _In_z_
#endif

#ifndef _Inout_
#define _Inout_
#endif

#ifndef _Inout_opt_
#define _Inout_opt_
#endif

#ifndef _Inout_z_count_
#define _Inout_z_count_(x)
#endif

#ifndef _Out_
#define _Out_
#endif

#ifndef _Out_opt_
#define _Out_opt_
#endif

#ifndef _Out_writes_
#define _Out_writes_(x)
#endif

#ifndef _Outptr_result_maybenull_
#define _Outptr_result_maybenull_
#endif

#ifndef _Writable_bytes_
#define _Writable_bytes_(x)
#endif

#ifndef _Readable_bytes_
#define _Readable_bytes_(x)
#endif

#ifndef _Success_
#define _Success_(x)
#endif

#ifndef _Pre_notnull_
#define _Pre_notnull_
#endif

#ifdef DETOURS_INTERNAL

#pragma warning(disable:4615) // unknown warning type (suppress with older compilers)

#ifndef _Benign_race_begin_
#define _Benign_race_begin_
#endif

#ifndef _Benign_race_end_
#define _Benign_race_end_
#endif

#ifndef _Field_size_
#define _Field_size_(x)
#endif

#ifndef _Field_range_
#define _Field_range_(x,y)
#endif

#ifndef _Analysis_assume_
#define _Analysis_assume_(x)
#endif

#endif // DETOURS_INTERNAL
#endif // DETOURS_DONT_REMOVE_SAL_20

//////////////////////////////////////////////////////////////////////////////
//
#ifndef GUID_DEFINED
#define GUID_DEFINED
typedef struct  _GUID
{
    DWORD Data1;
    WORD Data2;
    WORD Data3;
    BYTE Data4[ 8 ];
} GUID;

#ifdef INITGUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
        const GUID name \
                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
#else
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    const GUID name
#endif // INITGUID
#endif // !GUID_DEFINED

#if defined(__cplusplus)
#ifndef _REFGUID_DEFINED
#define _REFGUID_DEFINED
#define REFGUID             const GUID &
#endif // !_REFGUID_DEFINED
#else // !__cplusplus
#ifndef _REFGUID_DEFINED
#define _REFGUID_DEFINED
#define REFGUID             const GUID * const
#endif // !_REFGUID_DEFINED
#endif // !__cplusplus

#ifndef ARRAYSIZE
#define ARRAYSIZE(x)    (sizeof(x)/sizeof(x[0]))
#endif

//
//////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

//
// Constants
//
#define MoveMemory RtlMoveMemory
#define CopyMemory RtlCopyMemory
#define FillMemory RtlFillMemory
#define ZeroMemory RtlZeroMemory

#undef  NULL
#define NULL nullptr

/////////////////////////////////////////////////// Instruction Target Macros.
//
#define DETOUR_INSTRUCTION_TARGET_NONE          ((PVOID)0)
#define DETOUR_INSTRUCTION_TARGET_DYNAMIC       ((PVOID)(LONG_PTR)-1)
#define DETOUR_SECTION_HEADER_SIGNATURE         0x00727444   // "Dtr\0"

extern const GUID DETOUR_EXE_RESTORE_GUID;
extern const GUID DETOUR_EXE_HELPER_GUID;

#define DETOUR_TRAMPOLINE_SIGNATURE             0x21727444  // Dtr!
typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE;

/////////////////////////////////////////////////////////// Binary Structures.
//
#pragma pack(push, 8)
typedef struct _DETOUR_SECTION_HEADER
{
    DWORD       cbHeaderSize;
    DWORD       nSignature;
    DWORD       nDataOffset;
    DWORD       cbDataSize;

    DWORD       nOriginalImportVirtualAddress;
    DWORD       nOriginalImportSize;
    DWORD       nOriginalBoundImportVirtualAddress;
    DWORD       nOriginalBoundImportSize;

    DWORD       nOriginalIatVirtualAddress;
    DWORD       nOriginalIatSize;
    DWORD       nOriginalSizeOfImage;
    DWORD       cbPrePE;

    DWORD       nOriginalClrFlags;
    DWORD       reserved1;
    DWORD       reserved2;
    DWORD       reserved3;

    // Followed by cbPrePE bytes of data.
} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER;

typedef struct _DETOUR_SECTION_RECORD
{
    DWORD       cbBytes;
    DWORD       nReserved;
    GUID        guid;
} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD;

typedef struct _DETOUR_CLR_HEADER
{
    // Header versioning
    ULONG                   cb;
    USHORT                  MajorRuntimeVersion;
    USHORT                  MinorRuntimeVersion;

    // Symbol table and startup information
    IMAGE_DATA_DIRECTORY    MetaData;
    ULONG                   Flags;

    // Followed by the rest of the IMAGE_COR20_HEADER
} DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER;

typedef struct _DETOUR_EXE_RESTORE
{
    DWORD               cb;
    DWORD               cbidh;
    DWORD               cbinh;
    DWORD               cbclr;

    PBYTE               pidh;
    PBYTE               pinh;
    PBYTE               pclr;

    IMAGE_DOS_HEADER    idh;
    union {
        IMAGE_NT_HEADERS    inh;
        IMAGE_NT_HEADERS32  inh32;
        IMAGE_NT_HEADERS64  inh64;
        BYTE                raw[sizeof(IMAGE_NT_HEADERS64) +
                                sizeof(IMAGE_SECTION_HEADER) * 32];
    };
    DETOUR_CLR_HEADER   clr;

} DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE;

typedef struct _DETOUR_EXE_HELPER
{
    DWORD               cb;
    DWORD               pid;
    DWORD               nDlls;
    CHAR                rDlls[4];
} DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER;

#pragma pack(pop)

#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \
{ \
      sizeof(DETOUR_SECTION_HEADER),\
      DETOUR_SECTION_HEADER_SIGNATURE,\
      sizeof(DETOUR_SECTION_HEADER),\
      (cbSectionSize),\
      \
      0,\
      0,\
      0,\
      0,\
      \
      0,\
      0,\
      0,\
      0,\
}

/////////////////////////////////////////////////////////////// Helper Macros.
//
#define DETOURS_STRINGIFY(x)    DETOURS_STRINGIFY_(x)
#define DETOURS_STRINGIFY_(x)    #x

#ifndef DETOURS_KERNEL
///////////////////////////////////////////////////////////// Binary Typedefs.
//
typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)(
    _In_opt_ PVOID pContext,
    _In_opt_ LPCSTR pszFile,
    _Outptr_result_maybenull_ LPCSTR *ppszOutFile);

typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)(
    _In_opt_ PVOID pContext,
    _In_ LPCSTR pszOrigFile,
    _In_ LPCSTR pszFile,
    _Outptr_result_maybenull_ LPCSTR *ppszOutFile);

typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)(
    _In_opt_ PVOID pContext,
    _In_ ULONG nOrigOrdinal,
    _In_ ULONG nOrdinal,
    _Out_ ULONG *pnOutOrdinal,
    _In_opt_ LPCSTR pszOrigSymbol,
    _In_opt_ LPCSTR pszSymbol,
    _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol);

typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)(
    _In_opt_ PVOID pContext);

typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext,
                                                             _In_ ULONG nOrdinal,
                                                             _In_opt_ LPCSTR pszName,
                                                             _In_opt_ PVOID pCode);

typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext,
                                                        _In_opt_ HMODULE hModule,
                                                        _In_opt_ LPCSTR pszFile);

typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext,
                                                        _In_ DWORD nOrdinal,
                                                        _In_opt_ LPCSTR pszFunc,
                                                        _In_opt_ PVOID pvFunc);

// Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter.
typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext,
                                                           _In_ DWORD nOrdinal,
                                                           _In_opt_ LPCSTR pszFunc,
                                                           _In_opt_ PVOID* ppvFunc);

typedef VOID * PDETOUR_BINARY;
typedef VOID * PDETOUR_LOADED_BINARY;
#endif //!DETOURS_KERNEL

//////////////////////////////////////////////////////////// Transaction APIs.
//
LONG WINAPI DetourTransactionBegin(VOID);
LONG WINAPI DetourTransactionAbort(VOID);
LONG WINAPI DetourTransactionCommit(VOID);
LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer);

LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread);

LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
                         _In_ PVOID pDetour);

LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
                           _In_ PVOID pDetour,
                           _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
                           _Out_opt_ PVOID *ppRealTarget,
                           _Out_opt_ PVOID *ppRealDetour);

LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
                         _In_ PVOID pDetour);

BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore);
BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain);
PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound);
PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound);

////////////////////////////////////////////////////////////// Code Functions.
//
PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
                                   _Out_opt_ PVOID *ppGlobals);
PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst,
                                   _Inout_opt_ PVOID *ppDstPool,
                                   _In_ PVOID pSrc,
                                   _Out_opt_ PVOID *ppTarget,
                                   _Out_opt_ LONG *plExtra);

#ifndef DETOURS_KERNEL
PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
    _In_ LPCSTR pszFunction);
BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule,
                                _In_ BOOL fLimitReferencesToModule);
#endif // !DETOURS_KERNEL

#ifndef DETOURS_KERNEL
///////////////////////////////////////////////////// Loaded Binary Functions.
//
HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr);
HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast);
PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule);
ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule);
BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule,
                                   _In_opt_ PVOID pContext,
                                   _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport);
BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
                                   _In_opt_ PVOID pContext,
                                   _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
                                   _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc);

BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule,
                                     _In_opt_ PVOID pContext,
                                     _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
                                     _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx);

_Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
                               _In_ REFGUID rguid,
                               _Out_ DWORD *pcbData);

_Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
                                 _Out_ DWORD * pcbData);

DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule);
#endif // !DETOURS_KERNEL

#ifndef DETOURS_KERNEL
///////////////////////////////////////////////// Persistent Binary Functions.
//

PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile);

_Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary,
                                           _Out_opt_ GUID *pGuid,
                                           _Out_ DWORD *pcbData,
                                           _Inout_ DWORD *pnIterator);

_Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary,
                                     _In_ REFGUID rguid,
                                     _Out_ DWORD *pcbData);

PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary,
                                    _In_ REFGUID rguid,
                                    _In_reads_opt_(cbData) PVOID pData,
                                    _In_ DWORD cbData);
BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid);
BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary);
BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary);
BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary,
                                    _In_opt_ PVOID pContext,
                                    _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway,
                                    _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile,
                                    _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol,
                                    _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit);
BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile);
BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary);
#endif // !DETOURS_KERNEL

#ifndef DETOURS_KERNEL
/////////////////////////////////////////////////// Create Process & Load Dll.
//
typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)(
    _In_opt_ LPCSTR lpApplicationName,
    _Inout_opt_ LPSTR lpCommandLine,
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOA lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation);

typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)(
    _In_opt_ LPCWSTR lpApplicationName,
    _Inout_opt_ LPWSTR lpCommandLine,
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCWSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOW lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation);

BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName,
                                        _Inout_opt_ LPSTR lpCommandLine,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                        _In_ BOOL bInheritHandles,
                                        _In_ DWORD dwCreationFlags,
                                        _In_opt_ LPVOID lpEnvironment,
                                        _In_opt_ LPCSTR lpCurrentDirectory,
                                        _In_ LPSTARTUPINFOA lpStartupInfo,
                                        _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                        _In_ LPCSTR lpDllName,
                                        _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA);

BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
                                        _Inout_opt_ LPWSTR lpCommandLine,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                        _In_ BOOL bInheritHandles,
                                        _In_ DWORD dwCreationFlags,
                                        _In_opt_ LPVOID lpEnvironment,
                                        _In_opt_ LPCWSTR lpCurrentDirectory,
                                        _In_ LPSTARTUPINFOW lpStartupInfo,
                                        _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                        _In_ LPCSTR lpDllName,
                                        _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW);

#ifdef UNICODE
#define DetourCreateProcessWithDll      DetourCreateProcessWithDllW
#define PDETOUR_CREATE_PROCESS_ROUTINE  PDETOUR_CREATE_PROCESS_ROUTINEW
#else
#define DetourCreateProcessWithDll      DetourCreateProcessWithDllA
#define PDETOUR_CREATE_PROCESS_ROUTINE  PDETOUR_CREATE_PROCESS_ROUTINEA
#endif // !UNICODE

BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName,
                                          _Inout_opt_ LPSTR lpCommandLine,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                          _In_ BOOL bInheritHandles,
                                          _In_ DWORD dwCreationFlags,
                                          _In_opt_ LPVOID lpEnvironment,
                                          _In_opt_ LPCSTR lpCurrentDirectory,
                                          _In_ LPSTARTUPINFOA lpStartupInfo,
                                          _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                          _In_ LPCSTR lpDllName,
                                          _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA);

BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName,
                                          _Inout_opt_  LPWSTR lpCommandLine,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                          _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                          _In_ BOOL bInheritHandles,
                                          _In_ DWORD dwCreationFlags,
                                          _In_opt_ LPVOID lpEnvironment,
                                          _In_opt_ LPCWSTR lpCurrentDirectory,
                                          _In_ LPSTARTUPINFOW lpStartupInfo,
                                          _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                          _In_ LPCSTR lpDllName,
                                          _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW);

#ifdef UNICODE
#define DetourCreateProcessWithDllEx    DetourCreateProcessWithDllExW
#else
#define DetourCreateProcessWithDllEx    DetourCreateProcessWithDllExA
#endif // !UNICODE

BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName,
                                         _Inout_opt_ LPSTR lpCommandLine,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                         _In_ BOOL bInheritHandles,
                                         _In_ DWORD dwCreationFlags,
                                         _In_opt_ LPVOID lpEnvironment,
                                         _In_opt_ LPCSTR lpCurrentDirectory,
                                         _In_ LPSTARTUPINFOA lpStartupInfo,
                                         _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                         _In_ DWORD nDlls,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA);

BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName,
                                         _Inout_opt_ LPWSTR lpCommandLine,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
                                         _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                         _In_ BOOL bInheritHandles,
                                         _In_ DWORD dwCreationFlags,
                                         _In_opt_ LPVOID lpEnvironment,
                                         _In_opt_ LPCWSTR lpCurrentDirectory,
                                         _In_ LPSTARTUPINFOW lpStartupInfo,
                                         _Out_ LPPROCESS_INFORMATION lpProcessInformation,
                                         _In_ DWORD nDlls,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW);

#ifdef UNICODE
#define DetourCreateProcessWithDlls     DetourCreateProcessWithDllsW
#else
#define DetourCreateProcessWithDlls     DetourCreateProcessWithDllsA
#endif // !UNICODE

BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid,
                                    _In_ LPCSTR lpDllName,
                                    _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA);

BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid,
                                    _In_ LPCSTR lpDllName,
                                    _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW);

#ifdef UNICODE
#define DetourProcessViaHelper          DetourProcessViaHelperW
#else
#define DetourProcessViaHelper          DetourProcessViaHelperA
#endif // !UNICODE

BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
                                        _In_ DWORD nDlls,
                                        _In_reads_(nDlls) LPCSTR *rlpDlls,
                                        _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA);

BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
                                        _In_ DWORD nDlls,
                                        _In_reads_(nDlls) LPCSTR *rlpDlls,
                                        _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW);

#ifdef UNICODE
#define DetourProcessViaHelperDlls      DetourProcessViaHelperDllsW
#else
#define DetourProcessViaHelperDlls      DetourProcessViaHelperDllsA
#endif // !UNICODE

#endif // !DETOURS_KERNEL

BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
                                       _In_reads_(nDlls) LPCSTR *rlpDlls,
                                       _In_ DWORD nDlls);

BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
                                         _In_ HMODULE hImage,
                                         _In_ BOOL bIs32Bit,
                                         _In_reads_(nDlls) LPCSTR *rlpDlls,
                                         _In_ DWORD nDlls);

BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
                                       _In_ REFGUID rguid,
                                       _In_reads_bytes_(cbData) PVOID pvData,
                                       _In_ DWORD cbData);

#ifndef DETOURS_KERNEL
BOOL WINAPI DetourRestoreAfterWith(VOID);
BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
                                     _In_ DWORD cbData);
BOOL WINAPI DetourIsHelperProcess(VOID);
VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
                                        _In_ HINSTANCE,
                                        _In_ LPSTR,
                                        _In_ INT);
#endif // !DETOURS_KERNEL

//
//////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif // __cplusplus

//////////////////////////////////////////////// Detours Internal Definitions.
//
#ifdef __cplusplus
#ifdef DETOURS_INTERNAL

#define NOTHROW
// #define NOTHROW (nothrow)

//////////////////////////////////////////////////////////////////////////////
//
#ifndef DETOURS_KERNEL
#if (_MSC_VER < 1299)
#include <imagehlp.h>
typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64;
typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64;
typedef IMAGEHLP_SYMBOL SYMBOL_INFO;
typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO;

static inline
LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval)
{
    return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval);
}
#else
#pragma warning(push)
#pragma warning(disable:4091) // empty typedef
#include <dbghelp.h>
#pragma warning(pop)
#endif

#ifdef IMAGEAPI // defined by DBGHELP.H
typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion);

typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess,
                                       _In_opt_ LPCSTR UserSearchPath,
                                       _In_ BOOL fInvadeProcess);
typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions);
typedef DWORD (NTAPI *PF_SymGetOptions)(VOID);
typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess,
                                            _In_opt_ HANDLE hFile,
                                            _In_ LPSTR ImageName,
                                            _In_opt_ LPSTR ModuleName,
                                            _In_ DWORD64 BaseOfDll,
                                            _In_opt_ DWORD SizeOfDll);
typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess,
                                            _In_ DWORD64 qwAddr,
                                            _Out_ PIMAGEHLP_MODULE64 ModuleInfo);
typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess,
                                     _In_ LPSTR Name,
                                     _Out_ PSYMBOL_INFO Symbol);

typedef struct _DETOUR_SYM_INFO
{
    HANDLE                  hProcess;
    HMODULE                 hDbgHelp;
    PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx;
    PF_SymInitialize        pfSymInitialize;
    PF_SymSetOptions        pfSymSetOptions;
    PF_SymGetOptions        pfSymGetOptions;
    PF_SymLoadModule64      pfSymLoadModule64;
    PF_SymGetModuleInfo64   pfSymGetModuleInfo64;
    PF_SymFromName          pfSymFromName;
} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO;

PDETOUR_SYM_INFO DetourLoadImageHlp(VOID);

#endif // IMAGEAPI
#endif // !DETOURS_KERNEL

#if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS)
#error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier)
#endif
#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1

#ifndef DETOUR_TRACE
#if DETOUR_DEBUG && !defined(DETOURS_KERNEL)
#define DETOUR_TRACE(x) printf x
#define DETOUR_BREAK()  __debugbreak()
#include <stdio.h>
#include <limits.h>
#else
#define DETOUR_TRACE(x)
#define DETOUR_BREAK()
#endif
#endif

#if 1 || defined(DETOURS_IA64)

//
// IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle.
//

#define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3)

#define DETOUR_IA64_TEMPLATE_OFFSET (0)
#define DETOUR_IA64_TEMPLATE_SIZE   (5)

#define DETOUR_IA64_INSTRUCTION_SIZE (41)
#define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE)
#define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE)
#define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE)

C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128);

__declspec(align(16)) struct DETOUR_IA64_BUNDLE
{
  public:
    union
    {
        BYTE    data[16];
        UINT64  wide[2];
    };

    enum {
        A_UNIT  = 1u,
        I_UNIT  = 2u,
        M_UNIT  = 3u,
        B_UNIT  = 4u,
        F_UNIT  = 5u,
        L_UNIT  = 6u,
        X_UNIT  = 7u,
    };
    struct DETOUR_IA64_METADATA
    {
        ULONG       nTemplate       : 8;    // Instruction template.
        ULONG       nUnit0          : 4;    // Unit for slot 0
        ULONG       nUnit1          : 4;    // Unit for slot 1
        ULONG       nUnit2          : 4;    // Unit for slot 2
    };

  protected:
    static const DETOUR_IA64_METADATA s_rceCopyTable[33];

    UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const;

    bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst,
                             _In_ BYTE slot,
                             _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const;

    // 120 112 104 96 88 80 72 64 56 48 40 32 24 16  8  0
    //  f.  e.  d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0.

    //                                      00
    // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0.
    // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0]
    // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41..  5]
    // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42]
    // 0000 0000 0007 ffff ffff c000 0000 0000 : One  [ 82.. 46]
    // 0000 0000 0078 0000 0000 0000 0000 0000 : One  [ 86.. 83]
    // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two  [123.. 87]
    // f000 0000 0000 0000 0000 0000 0000 0000 : Two  [127..124]
    BYTE    GetTemplate() const;
    // Get 4 bit opcodes.
    BYTE    GetInst0() const;
    BYTE    GetInst1() const;
    BYTE    GetInst2() const;
    BYTE    GetUnit(BYTE slot) const;
    BYTE    GetUnit0() const;
    BYTE    GetUnit1() const;
    BYTE    GetUnit2() const;
    // Get 37 bit data.
    UINT64  GetData0() const;
    UINT64  GetData1() const;
    UINT64  GetData2() const;

    // Get/set the full 41 bit instructions.
    UINT64  GetInstruction(BYTE slot) const;
    UINT64  GetInstruction0() const;
    UINT64  GetInstruction1() const;
    UINT64  GetInstruction2() const;
    void    SetInstruction(BYTE slot, UINT64 instruction);
    void    SetInstruction0(UINT64 instruction);
    void    SetInstruction1(UINT64 instruction);
    void    SetInstruction2(UINT64 instruction);

    // Get/set bitfields.
    static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count);
    static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field);

    // Get specific read-only fields.
    static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode
    static UINT64 GetX(UINT64 instruction); // 1bit opcode extension
    static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension
    static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension

    // Get/set specific fields.
    static UINT64 GetImm7a(UINT64 instruction);
    static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a);
    static UINT64 GetImm13c(UINT64 instruction);
    static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c);
    static UINT64 GetSignBit(UINT64 instruction);
    static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit);
    static UINT64 GetImm20a(UINT64 instruction);
    static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a);
    static UINT64 GetImm20b(UINT64 instruction);
    static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b);

    static UINT64 SignExtend(UINT64 Value, UINT64 Offset);

    BOOL    IsMovlGp() const;

    VOID    SetInst(BYTE Slot, BYTE nInst);
    VOID    SetInst0(BYTE nInst);
    VOID    SetInst1(BYTE nInst);
    VOID    SetInst2(BYTE nInst);
    VOID    SetData(BYTE Slot, UINT64 nData);
    VOID    SetData0(UINT64 nData);
    VOID    SetData1(UINT64 nData);
    VOID    SetData2(UINT64 nData);
    BOOL    SetNop(BYTE Slot);
    BOOL    SetNop0();
    BOOL    SetNop1();
    BOOL    SetNop2();

  public:
    BOOL    IsBrl() const;
    VOID    SetBrl();
    VOID    SetBrl(UINT64 target);
    UINT64  GetBrlTarget() const;
    VOID    SetBrlTarget(UINT64 target);
    VOID    SetBrlImm(UINT64 imm);
    UINT64  GetBrlImm() const;

    UINT64  GetMovlGp() const;
    VOID    SetMovlGp(UINT64 gp);

    VOID    SetStop();

    UINT    Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const;
};
#endif // DETOURS_IA64

#ifdef DETOURS_ARM

#define DETOURS_PFUNC_TO_PBYTE(p)  ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1))
#define DETOURS_PBYTE_TO_PFUNC(p)  ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1))

#endif // DETOURS_ARM

//////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#define DETOUR_OFFLINE_LIBRARY(x)                                       \
PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst,              \
                                      _Inout_opt_ PVOID *ppDstPool,     \
                                      _In_ PVOID pSrc,                  \
                                      _Out_opt_ PVOID *ppTarget,        \
                                      _Out_opt_ LONG *plExtra);         \
                                                                        \
BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule,                \
                                   _In_ BOOL fLimitReferencesToModule); \

DETOUR_OFFLINE_LIBRARY(X86)
DETOUR_OFFLINE_LIBRARY(X64)
DETOUR_OFFLINE_LIBRARY(ARM)
DETOUR_OFFLINE_LIBRARY(ARM64)
DETOUR_OFFLINE_LIBRARY(IA64)

#undef DETOUR_OFFLINE_LIBRARY

//////////////////////////////////////////////////////////////////////////////
//
// Helpers for manipulating page protection.
//

_Success_(return != FALSE)
BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_  HANDLE hProcess,
                                              _In_  PVOID pAddress,
                                              _In_  SIZE_T nSize,
                                              _In_  DWORD dwNewProtect,
                                              _Out_ PDWORD pdwOldProtect);

_Success_(return != FALSE)
BOOL WINAPI DetourVirtualProtectSameExecute
Download .txt
gitextract_reyt6s3d/

├── .gitignore
├── BuildAllTargets.cmd
├── BuildAllTargets.proj
├── Detours/
│   ├── api_thunks.cpp
│   ├── api_thunks.h
│   ├── creatwth.cpp
│   ├── detours.cpp
│   ├── detours.h
│   ├── detoursx.cpp
│   ├── detver.h
│   ├── disasm.cpp
│   ├── disolarm.cpp
│   ├── disolarm64.cpp
│   ├── disolia64.cpp
│   ├── disolx64.cpp
│   ├── disolx86.cpp
│   ├── image.cpp
│   ├── modules.cpp
│   └── uimports.cpp
├── Detours.StaticLibrary/
│   └── Detours.StaticLibrary.vcxproj
├── Detours.StaticLibraryForDriver/
│   └── Detours.StaticLibraryForDriver.vcxproj
├── Detours.Test/
│   ├── Detours.Test.vcxproj
│   ├── Main.cpp
│   └── Module.def
├── Detours.TestForDriver/
│   ├── Detours.TestForDriver.inf
│   ├── Detours.TestForDriver.vcxproj
│   └── Main.cpp
├── DetoursX.slnx
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.Cpp.props
├── InitializeVisualStudioEnvironment.cmd
├── LICENSE
├── README.md
├── README.zh-CN.md
└── global.json
Download .txt
SYMBOL INDEX (519 symbols across 12 files)

FILE: Detours.Test/Main.cpp
  type Hook (line 10) | namespace Hook
    class DetourLockGuard (line 12) | class DetourLockGuard
      method DetourLockGuard (line 17) | explicit DetourLockGuard(volatile long& atom) noexcept
    function NTSTATUS (line 39) | NTSTATUS NTAPI ZwOpenFile(
    function NTSTATUS (line 69) | NTSTATUS NTAPI ZwCreateFile(
  type Detours::Test (line 109) | namespace Detours::Test
    function EXTERN_C (line 111) | EXTERN_C LONG MainEntry()
    function EXTERN_C (line 134) | EXTERN_C VOID MainExit()
    function EXTERN_C (line 150) | EXTERN_C BOOL WINAPI DllMain(_In_ void* /*DllHandle*/, _In_ unsigned R...
  function LogPrint (line 164) | void LogPrint(

FILE: Detours.TestForDriver/Main.cpp
  type Hook (line 15) | namespace Hook
    class DetourLockGuard (line 17) | class DetourLockGuard
      method DetourLockGuard (line 22) | explicit DetourLockGuard(volatile long& atom) noexcept
    function BOOLEAN (line 43) | BOOLEAN MmIsAddressValid(
    function VOID (line 64) | VOID CreateProcessCallback(
  type Detours::Test (line 117) | namespace Detours::Test
    function EXTERN_C (line 121) | EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_ST...
    function EXTERN_C (line 148) | EXTERN_C VOID DriverUnload(PDRIVER_OBJECT)

FILE: Detours/api_thunks.cpp
  type Detours::Thunks (line 26) | namespace Detours::Thunks
    function NTSTATUS (line 34) | NTSTATUS NTAPI ZwReadVirtualMemory(
    function NTSTATUS (line 115) | NTSTATUS NTAPI ZwWriteVirtualMemory(
    function VOID (line 202) | VOID WINAPI SetLastError(_In_ DWORD Win32Error)
    function DWORD (line 207) | DWORD WINAPI GetLastError(VOID)
    function HANDLE (line 218) | HANDLE WINAPI GetCurrentProcess(VOID)
    function HANDLE (line 223) | HANDLE WINAPI GetCurrentThread(VOID)
    function DWORD (line 228) | DWORD WINAPI GetCurrentProcessId(VOID)
    function DWORD (line 233) | DWORD WINAPI GetCurrentThreadId(VOID)
    function BOOL (line 238) | BOOL WINAPI IsWow64Process(
    function WINAPI (line 274) | WINAPI ReadProcessMemory(
    function WINAPI (line 307) | WINAPI WriteProcessMemory(
    function LPVOID (line 438) | LPVOID WINAPI VirtualAllocEx(
    function BOOL (line 469) | BOOL WINAPI VirtualFreeEx(
    function WINAPI (line 499) | WINAPI VirtualProtectEx(
    function SIZE_T (line 523) | SIZE_T WINAPI VirtualQueryEx(

FILE: Detours/api_thunks.h
  function namespace (line 3) | namespace Detours::Thunks

FILE: Detours/creatwth.cpp
  function BOOL (line 68) | static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess,
  function HMODULE (line 120) | static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess,
  function PBYTE (line 166) | static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbBase, DWOR...
  function DWORD (line 235) | static inline DWORD PadToDword(DWORD dw)
  function DWORD (line 240) | static inline DWORD PadToDwordPtr(DWORD dw)
  function HRESULT (line 245) | static inline HRESULT ReplaceOptionalSizeA(_Inout_z_count_(cchDest) LPST...
  function BOOL (line 267) | static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EX...
  function BOOL (line 386) | static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD mach...
  function BOOL (line 531) | BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
  function BOOL (line 599) | BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
  function BOOL (line 749) | BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName,
  function BOOL (line 807) | BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
  function BOOL (line 864) | BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
  function VOID (line 963) | VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
  function BOOL (line 1020) | BOOL WINAPI DetourIsHelperProcess(VOID)
  function BOOL (line 1045) | static
  function VOID (line 1150) | static
  function BOOL (line 1159) | BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid,
  function BOOL (line 1167) | BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
  function BOOL (line 1257) | BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid,
  function BOOL (line 1264) | BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
  function BOOL (line 1356) | BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationN...
  function BOOL (line 1417) | BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplication...
  function BOOL (line 1478) | BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName,
  function BOOL (line 1539) | BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationN...

FILE: Detours/detours.cpp
  type _DETOUR_ALIGN (line 43) | struct _DETOUR_ALIGN
  function detour_is_imported (line 60) | static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
  function ULONG_PTR (line 95) | inline ULONG_PTR detour_2gb_below(ULONG_PTR address)
  function ULONG_PTR (line 100) | inline ULONG_PTR detour_2gb_above(ULONG_PTR address)
  type _DETOUR_TRAMPOLINE (line 113) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 132) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  function PBYTE (line 140) | inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  function PBYTE (line 148) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 156) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 202) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 228) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 257) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 322) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 344) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  function PBYTE (line 352) | inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  function PBYTE (line 361) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 369) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 415) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 453) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 482) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 547) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 629) | inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 695) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 704) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 711) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 722) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 742) | inline PBYTE align4(PBYTE pValue)
  function ULONG (line 747) | inline ULONG fetch_thumb_opcode(PBYTE pbCode)
  function write_thumb_opcode (line 756) | inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode)
  function PBYTE (line 764) | PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  function PBYTE (line 789) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 797) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 834) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 848) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 866) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 881) | struct _DETOUR_TRAMPOLINE
  function ULONG (line 901) | inline ULONG fetch_opcode(PBYTE pbCode)
  function write_opcode (line 906) | inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
  function PBYTE (line 912) | PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  function PBYTE (line 935) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 943) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 979) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 995) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 1005) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type DETOUR_REGION (line 1020) | struct DETOUR_REGION
  function DWORD (line 1035) | static DWORD detour_writable_trampoline_regions()
  function detour_runnable_trampoline_regions (line 1047) | static void detour_runnable_trampoline_regions()
  function PBYTE (line 1059) | static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry)
  function PBYTE (line 1069) | static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry)
  function PVOID (line 1082) | static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
  function PVOID (line 1128) | static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
  function PDETOUR_TRAMPOLINE (line 1174) | static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
  function detour_free_trampoline (line 1275) | static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
  function BOOL (line 1285) | static BOOL detour_is_region_empty(PDETOUR_REGION pRegion)
  function detour_free_unused_trampoline_regions (line 1309) | static void detour_free_unused_trampoline_regions()
  type DetourThread (line 1330) | struct DetourThread
  type DetourOperation (line 1336) | struct DetourOperation
  function PVOID (line 1357) | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
  function BOOL (line 1365) | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore)
  function BOOL (line 1372) | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain)
  function PVOID (line 1379) | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLow...
  function PVOID (line 1386) | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpp...
  function LONG (line 1393) | LONG WINAPI DetourTransactionBegin()
  function LONG (line 1417) | LONG WINAPI DetourTransactionAbort()
  function LONG (line 1461) | LONG WINAPI DetourTransactionCommit()
  function BYTE (line 1466) | static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline,...
  function LONG (line 1476) | static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LON...
  function LONG (line 1486) | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
  function LONG (line 1755) | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread)
  function LONG (line 1798) | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
  function LONG (line 1804) | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
  function LONG (line 2158) | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
  function DWORD (line 2329) | static DWORD DetourPageProtectAdjustExecute(_In_  DWORD dwOldProtect,
  function WINAPI (line 2348) | WINAPI DetourVirtualProtectSameExecuteEx(_In_  HANDLE hProcess,
  function WINAPI (line 2373) | WINAPI DetourVirtualProtectSameExecute(_In_  PVOID pAddress,

FILE: Detours/detours.h
  type LONG (line 79) | typedef LONG LONG_PTR;
  type ULONG (line 80) | typedef ULONG ULONG_PTR;
  type GUID (line 274) | typedef struct  _GUID
  type DETOUR_TRAMPOLINE (line 336) | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE;
  type DETOUR_SECTION_HEADER (line 341) | typedef struct _DETOUR_SECTION_HEADER
  type DETOUR_SECTION_RECORD (line 366) | typedef struct _DETOUR_SECTION_RECORD
  type DETOUR_CLR_HEADER (line 373) | typedef struct _DETOUR_CLR_HEADER
  type DETOUR_EXE_RESTORE (line 387) | typedef struct _DETOUR_EXE_RESTORE
  type DETOUR_EXE_HELPER (line 410) | typedef struct _DETOUR_EXE_HELPER
  type VOID (line 489) | typedef VOID * PDETOUR_BINARY;
  type VOID (line 490) | typedef VOID * PDETOUR_LOADED_BINARY;
  type IMAGEHLP_MODULE (line 814) | typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64;
  type PIMAGEHLP_MODULE (line 815) | typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64;
  type IMAGEHLP_SYMBOL (line 816) | typedef IMAGEHLP_SYMBOL SYMBOL_INFO;
  type PIMAGEHLP_SYMBOL (line 817) | typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO;
  function LONG (line 819) | static inline
  type DETOUR_SYM_INFO (line 852) | typedef struct _DETOUR_SYM_INFO
  type DETOUR_IA64_BUNDLE (line 905) | struct DETOUR_IA64_BUNDLE

FILE: Detours/detoursx.cpp
  type _DETOUR_ALIGN (line 53) | struct _DETOUR_ALIGN
  function detour_memory_free (line 69) | static void  detour_memory_free(void* p)
  function PMDL (line 74) | static PMDL detour_remap_address(_In_ void* va, _In_ unsigned long size,...
  function detour_unmap_address (line 111) | static void detour_unmap_address(_In_ PMDL mdl)
  function detour_is_imported (line 128) | static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
  function ULONG_PTR (line 168) | inline ULONG_PTR detour_2gb_below(ULONG_PTR address)
  function ULONG_PTR (line 173) | inline ULONG_PTR detour_2gb_above(ULONG_PTR address)
  type _DETOUR_TRAMPOLINE (line 186) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 205) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  function PBYTE (line 213) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbFixedCode, P...
  function PBYTE (line 221) | inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  function PBYTE (line 229) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 237) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 283) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 309) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 338) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 403) | struct _DETOUR_TRAMPOLINE
  function PIMAGE_SECTION_HEADER (line 426) | static PIMAGE_SECTION_HEADER detour_va_to_section(PVOID base, PIMAGE_NT_...
  function PBYTE (line 441) | PBYTE detour_gen_codein(PBYTE pbCode, PVOID pDetour, PMDL* pMdl)
  function detour_del_codein (line 490) | void detour_del_codein(PMDL pMdl)
  function PBYTE (line 500) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  function PBYTE (line 508) | inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbFixedCode, P...
  function PBYTE (line 516) | inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  function PBYTE (line 525) | inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE pbFixedCode, PB...
  function PBYTE (line 534) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 542) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 588) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 597) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 626) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 691) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 773) | inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 839) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 848) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 855) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 866) | struct _DETOUR_TRAMPOLINE
  function PBYTE (line 886) | inline PBYTE align4(PBYTE pValue)
  function ULONG (line 891) | inline ULONG fetch_thumb_opcode(PBYTE pbCode)
  function write_thumb_opcode (line 900) | inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode)
  function PBYTE (line 908) | PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  function PBYTE (line 933) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 941) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 978) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 992) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 1010) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type _DETOUR_TRAMPOLINE (line 1025) | struct _DETOUR_TRAMPOLINE
  function ULONG (line 1045) | inline ULONG fetch_opcode(PBYTE pbCode)
  function write_opcode (line 1050) | inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
  function PBYTE (line 1056) | PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  function PBYTE (line 1079) | inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  function PBYTE (line 1087) | inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  function detour_find_jmp_bounds (line 1123) | inline void detour_find_jmp_bounds(PBYTE pbCode,
  function BOOL (line 1139) | inline BOOL detour_does_code_end_function(PBYTE pbCode)
  function ULONG (line 1149) | inline ULONG detour_is_code_filler(PBYTE pbCode)
  type DETOUR_REGION (line 1164) | struct DETOUR_REGION
  function DWORD (line 1180) | static DWORD detour_writable_trampoline_regions()
  function detour_runnable_trampoline_regions (line 1192) | static void detour_runnable_trampoline_regions()
  function PVOID (line 1224) | static PVOID detour_alloc_region_from_lo(PMDL pMdl, PBYTE /*pbLo*/, PBYT...
  function PVOID (line 1231) | static PVOID detour_alloc_region_from_hi(PMDL pMdl, PBYTE /*pbLo*/, PBYT...
  function PDETOUR_TRAMPOLINE (line 1236) | static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
  function detour_free_trampoline (line 1352) | static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
  function BOOL (line 1362) | static BOOL detour_is_region_empty(PDETOUR_REGION pRegion)
  function detour_free_unused_trampoline_regions (line 1386) | static void detour_free_unused_trampoline_regions()
  type DetourThread (line 1412) | struct DetourThread
  type DetourOperation (line 1418) | struct DetourOperation
  function PVOID (line 1439) | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
  function BOOL (line 1447) | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore)
  function BOOL (line 1454) | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain)
  function PVOID (line 1461) | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLow...
  function PVOID (line 1468) | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpp...
  function LONG (line 1475) | LONG WINAPI DetourTransactionBegin()
  function LONG (line 1499) | LONG WINAPI DetourTransactionAbort()
  function LONG (line 1534) | LONG WINAPI DetourTransactionCommit()
  function BYTE (line 1540) | static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline,...
  function LONG (line 1551) | static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LON...
  function LONG (line 1561) | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
  function LONG (line 1766) | LONG WINAPI DetourUpdateThread(_In_ HANDLE /*hThread*/)
  function LONG (line 1778) | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
  function LONG (line 1784) | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
  function LONG (line 2143) | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
  function DWORD (line 2315) | static DWORD DetourPageProtectAdjustExecute(_In_  DWORD dwOldProtect,
  function WINAPI (line 2334) | WINAPI DetourVirtualProtectSameExecuteEx(_In_  HANDLE hProcess,
  function WINAPI (line 2359) | WINAPI DetourVirtualProtectSameExecute(_In_  PVOID pAddress,

FILE: Detours/disasm.cpp
  class CDetourDis (line 180) | class CDetourDis
    type COPYENTRY (line 191) | struct COPYENTRY
    type COPYENTRY (line 211) | struct COPYENTRY
    type COPYENTRY (line 2320) | struct COPYENTRY {
    type Branch5 (line 2327) | struct Branch5
    type Branch5Target (line 2336) | struct Branch5Target
    type Branch8 (line 2344) | struct Branch8
    type Branch8Target (line 2351) | struct Branch8Target
    type Branch11 (line 2358) | struct Branch11
    type Branch11Target (line 2364) | struct Branch11Target
    type Branch20 (line 2371) | struct Branch20
    type Branch20Target (line 2384) | struct Branch20Target
    type Branch24 (line 2395) | struct Branch24
    type Branch24Target (line 2408) | struct Branch24Target
    type LiteralLoad8 (line 2419) | struct LiteralLoad8
    type LiteralLoad8Target (line 2426) | struct LiteralLoad8Target
    type LiteralLoad12 (line 2433) | struct LiteralLoad12
    type LiteralLoad12Target (line 2442) | struct LiteralLoad12Target
    type ImmediateRegisterLoad32 (line 2448) | struct ImmediateRegisterLoad32
    type ImmediateRegisterLoad16 (line 2456) | struct ImmediateRegisterLoad16
    type TableBranch (line 2463) | struct TableBranch
    type Shift (line 2472) | struct Shift
    type Add32 (line 2478) | struct Add32
    type LogicalShiftLeft32 (line 2491) | struct LogicalShiftLeft32
    type StoreImmediate12 (line 2503) | struct StoreImmediate12
    method ULONG (line 2549) | ULONG GetLongInstruction(BYTE* pSource)
    method BYTE (line 2554) | BYTE EmitLongInstruction(PUSHORT& pDstInst, ULONG instruction)
    method BYTE (line 2561) | BYTE EmitShortInstruction(PUSHORT& pDstInst, USHORT instruction)
    method PBYTE (line 2567) | PBYTE Align4(PBYTE pValue)
    method PBYTE (line 2572) | PBYTE CalculateTarget(PBYTE pSource, LONG delta)
    method LONG (line 2577) | LONG CalculateNewDelta(PBYTE pTarget, BYTE* pDest)
    method BYTE (line 2582) | BYTE    EmitAdd32(PUSHORT& pDstInst, BYTE op1Reg, BYTE op2Reg, BYTE ds...
    method BYTE (line 2591) | BYTE    EmitLogicalShiftLeft32(PUSHORT& pDstInst, BYTE srcReg, BYTE ds...
    method BYTE (line 2599) | BYTE    EmitStoreImmediate12(PUSHORT& pDstInst, BYTE srcReg, BYTE base...
    method DWORD (line 3666) | static DWORD Assemble(DWORD size, DWORD rd, DWORD rn, ULONG imm, DWORD...
    method DWORD (line 3677) | static DWORD AssembleAdd32(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method DWORD (line 3678) | static DWORD AssembleAdd64(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method LONG (line 3692) | inline LONG Imm() const { DWORD Imm = (s.Imm19 << 2) | s.Imm2; return ...
    method DWORD (line 3693) | static DWORD Assemble(DWORD type, DWORD rd, LONG delta)
    method DWORD (line 3703) | static DWORD AssembleAdr(DWORD rd, LONG delta) { return Assemble(0, rd...
    method DWORD (line 3704) | static DWORD AssembleAdrp(DWORD rd, LONG delta) { return Assemble(1, r...
    method LONG (line 3717) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3718) | static DWORD AssembleBcc(DWORD condition, LONG delta)
    method LONG (line 3738) | inline LONG Imm() const { return (LONG)(s.Imm26 << 6) >> 4; }
    method DWORD (line 3739) | static DWORD Assemble(DWORD link, LONG delta)
    method DWORD (line 3747) | static DWORD AssembleB(LONG delta) { return Assemble(0, delta); }
    method DWORD (line 3748) | static DWORD AssembleBl(LONG delta) { return Assemble(1, delta); }
    method DWORD (line 3760) | static DWORD AssembleBr(DWORD rn)
    method LONG (line 3781) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3782) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, LONG delta)
    method LONG (line 3806) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3807) | static DWORD Assemble(DWORD size, DWORD fpneon, DWORD rt, LONG delta)
    method DWORD (line 3833) | static DWORD Assemble(DWORD size, DWORD rt, DWORD rn, ULONG imm)
    method DWORD (line 3859) | static DWORD Assemble(DWORD size, DWORD type, DWORD rd, DWORD imm, DWO...
    method DWORD (line 3870) | static DWORD AssembleMovn32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3871) | static DWORD AssembleMovn64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3872) | static DWORD AssembleMovz32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3873) | static DWORD AssembleMovz64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3874) | static DWORD AssembleMovk32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3875) | static DWORD AssembleMovk64(DWORD rd, DWORD imm, DWORD shift) { return...
    method LONG (line 3890) | inline LONG Imm() const { return (LONG)(s.Imm14 << 18) >> 16; }
    method DWORD (line 3891) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, DWORD bit, LONG ...
    method ULONG (line 3916) | ULONG GetInstruction(BYTE* pSource)
    method BYTE (line 3921) | BYTE EmitInstruction(PULONG& pDstInst, ULONG instruction)
  function PVOID (line 333) | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst,
  function PBYTE (line 363) | PBYTE CDetourDis::CopyInstruction(PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 382) | PBYTE CDetourDis::CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function else (line 434) | else if (bFlags & RIP) {
  function PBYTE (line 468) | PBYTE CDetourDis::CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYT...
  function PBYTE (line 475) | PBYTE CDetourDis::CopyBytesSegment(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 481) | PBYTE CDetourDis::CopyBytesRax(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 489) | PBYTE CDetourDis::CopyBytesJump(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE ...
  function PBYTE (line 523) | PBYTE CDetourDis::CopyBytesJumpToAbsolute(REFCOPYENTRY pEntry, PBYTE pbD...
  function PBYTE (line 568) | PBYTE CDetourDis::AdjustTarget(PBYTE pbDst, PBYTE pbSrc, UINT cbOp,
  function PBYTE (line 648) | PBYTE CDetourDis::Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 658) | PBYTE CDetourDis::Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 665) | PBYTE CDetourDis::Copy0F78(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 683) | PBYTE CDetourDis::Copy0F00(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 695) | PBYTE CDetourDis::Copy0FB8(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 705) | PBYTE CDetourDis::Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 711) | PBYTE CDetourDis::Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 717) | PBYTE CDetourDis::CopyF2(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 723) | PBYTE CDetourDis::CopyF3(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 729) | PBYTE CDetourDis::CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 749) | PBYTE CDetourDis::CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 769) | PBYTE CDetourDis::CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 820) | PBYTE CDetourDis::CopyVexCommon(BYTE m, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 847) | PBYTE CDetourDis::CopyVex3(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function PBYTE (line 892) | PBYTE CDetourDis::CopyVex2(REFCOPYENTRY, PBYTE pbDst, PBYTE pbSrc)
  function BOOL (line 913) | BOOL CDetourDis::SetCodeModule(PBYTE pbBeg, PBYTE pbEnd, BOOL fLimitRefe...
  function BOOL (line 1590) | BOOL CDetourDis::SanityCheckSystem()
  function BYTE (line 1678) | BYTE DETOUR_IA64_BUNDLE::GetTemplate() const
  function BYTE (line 1683) | BYTE DETOUR_IA64_BUNDLE::GetInst0() const
  function BYTE (line 1688) | BYTE DETOUR_IA64_BUNDLE::GetInst1() const
  function BYTE (line 1693) | BYTE DETOUR_IA64_BUNDLE::GetInst2() const
  function BYTE (line 1698) | BYTE DETOUR_IA64_BUNDLE::GetUnit(BYTE slot) const
  function BYTE (line 1709) | BYTE DETOUR_IA64_BUNDLE::GetUnit0() const
  function BYTE (line 1714) | BYTE DETOUR_IA64_BUNDLE::GetUnit1() const
  function BYTE (line 1719) | BYTE DETOUR_IA64_BUNDLE::GetUnit2() const
  function UINT64 (line 1724) | UINT64 DETOUR_IA64_BUNDLE::GetData0() const
  function UINT64 (line 1729) | UINT64 DETOUR_IA64_BUNDLE::GetData1() const
  function UINT64 (line 1735) | UINT64 DETOUR_IA64_BUNDLE::GetData2() const
  function VOID (line 1740) | VOID DETOUR_IA64_BUNDLE::SetInst(BYTE slot, BYTE nInst)
  function VOID (line 1751) | VOID DETOUR_IA64_BUNDLE::SetInst0(BYTE nInst)
  function VOID (line 1756) | VOID DETOUR_IA64_BUNDLE::SetInst1(BYTE nInst)
  function VOID (line 1761) | VOID DETOUR_IA64_BUNDLE::SetInst2(BYTE nInst)
  function VOID (line 1766) | VOID DETOUR_IA64_BUNDLE::SetData(BYTE slot, UINT64 nData)
  function VOID (line 1777) | VOID DETOUR_IA64_BUNDLE::SetData0(UINT64 nData)
  function VOID (line 1782) | VOID DETOUR_IA64_BUNDLE::SetData1(UINT64 nData)
  function VOID (line 1788) | VOID DETOUR_IA64_BUNDLE::SetData2(UINT64 nData)
  function UINT64 (line 1793) | UINT64 DETOUR_IA64_BUNDLE::GetInstruction(BYTE slot) const
  function UINT64 (line 1804) | UINT64 DETOUR_IA64_BUNDLE::GetInstruction0() const
  function UINT64 (line 1810) | UINT64 DETOUR_IA64_BUNDLE::GetInstruction1() const
  function UINT64 (line 1818) | UINT64 DETOUR_IA64_BUNDLE::GetInstruction2() const
  function UINT64 (line 1855) | UINT64 DETOUR_IA64_BUNDLE::SignExtend(UINT64 Value, UINT64 Offset)
  function UINT64 (line 1864) | UINT64 DETOUR_IA64_BUNDLE::GetBits(UINT64 Value, UINT64 Offset, UINT64 C...
  function UINT64 (line 1870) | UINT64 DETOUR_IA64_BUNDLE::SetBits(UINT64 Value, UINT64 Offset, UINT64 C...
  function UINT64 (line 1877) | UINT64 DETOUR_IA64_BUNDLE::GetOpcode(UINT64 instruction)
  function UINT64 (line 1884) | UINT64 DETOUR_IA64_BUNDLE::GetX(UINT64 instruction)
  function UINT64 (line 1891) | UINT64 DETOUR_IA64_BUNDLE::GetX3(UINT64 instruction)
  function UINT64 (line 1898) | UINT64 DETOUR_IA64_BUNDLE::GetX6(UINT64 instruction)
  function UINT64 (line 1905) | UINT64 DETOUR_IA64_BUNDLE::GetImm7a(UINT64 instruction)
  function UINT64 (line 1911) | UINT64 DETOUR_IA64_BUNDLE::SetImm7a(UINT64 instruction, UINT64 imm7a)
  function UINT64 (line 1917) | UINT64 DETOUR_IA64_BUNDLE::GetImm13c(UINT64 instruction)
  function UINT64 (line 1923) | UINT64 DETOUR_IA64_BUNDLE::SetImm13c(UINT64 instruction, UINT64 imm13c)
  function UINT64 (line 1929) | UINT64 DETOUR_IA64_BUNDLE::GetSignBit(UINT64 instruction)
  function UINT64 (line 1935) | UINT64 DETOUR_IA64_BUNDLE::SetSignBit(UINT64 instruction, UINT64 signBit)
  function UINT64 (line 1941) | UINT64 DETOUR_IA64_BUNDLE::GetImm20a(UINT64 instruction)
  function UINT64 (line 1947) | UINT64 DETOUR_IA64_BUNDLE::SetImm20a(UINT64 instruction, UINT64 imm20a)
  function UINT64 (line 1953) | UINT64 DETOUR_IA64_BUNDLE::GetImm20b(UINT64 instruction)
  function UINT64 (line 1959) | UINT64 DETOUR_IA64_BUNDLE::SetImm20b(UINT64 instruction, UINT64 imm20b)
  function UINT (line 2067) | UINT DETOUR_IA64_BUNDLE::RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst,
  function BOOL (line 2085) | BOOL DETOUR_IA64_BUNDLE::IsBrl() const
  function VOID (line 2095) | VOID DETOUR_IA64_BUNDLE::SetBrl()
  function UINT64 (line 2102) | UINT64 DETOUR_IA64_BUNDLE::GetBrlImm() const
  function VOID (line 2116) | VOID DETOUR_IA64_BUNDLE::SetBrlImm(UINT64 imm)
  function UINT64 (line 2132) | UINT64 DETOUR_IA64_BUNDLE::GetBrlTarget() const
  function VOID (line 2137) | VOID DETOUR_IA64_BUNDLE::SetBrl(UINT64 target)
  function VOID (line 2144) | VOID DETOUR_IA64_BUNDLE::SetBrlTarget(UINT64 target)
  function BOOL (line 2150) | BOOL DETOUR_IA64_BUNDLE::IsMovlGp() const
  function UINT64 (line 2159) | UINT64 DETOUR_IA64_BUNDLE::GetMovlGp() const
  function VOID (line 2181) | VOID DETOUR_IA64_BUNDLE::SetMovlGp(UINT64 gp)
  function UINT (line 2206) | UINT DETOUR_IA64_BUNDLE::Copy(_Out_ DETOUR_IA64_BUNDLE *pDst,
  function BOOL (line 2226) | BOOL DETOUR_IA64_BUNDLE::SetNop(BYTE slot)
  function BOOL (line 2244) | BOOL DETOUR_IA64_BUNDLE::SetNop0()
  function BOOL (line 2249) | BOOL DETOUR_IA64_BUNDLE::SetNop1()
  function BOOL (line 2254) | BOOL DETOUR_IA64_BUNDLE::SetNop2()
  function VOID (line 2259) | VOID DETOUR_IA64_BUNDLE::SetStop()
  function PVOID (line 2266) | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst,
  class CDetourDis (line 2306) | class CDetourDis
    type COPYENTRY (line 191) | struct COPYENTRY
    type COPYENTRY (line 211) | struct COPYENTRY
    type COPYENTRY (line 2320) | struct COPYENTRY {
    type Branch5 (line 2327) | struct Branch5
    type Branch5Target (line 2336) | struct Branch5Target
    type Branch8 (line 2344) | struct Branch8
    type Branch8Target (line 2351) | struct Branch8Target
    type Branch11 (line 2358) | struct Branch11
    type Branch11Target (line 2364) | struct Branch11Target
    type Branch20 (line 2371) | struct Branch20
    type Branch20Target (line 2384) | struct Branch20Target
    type Branch24 (line 2395) | struct Branch24
    type Branch24Target (line 2408) | struct Branch24Target
    type LiteralLoad8 (line 2419) | struct LiteralLoad8
    type LiteralLoad8Target (line 2426) | struct LiteralLoad8Target
    type LiteralLoad12 (line 2433) | struct LiteralLoad12
    type LiteralLoad12Target (line 2442) | struct LiteralLoad12Target
    type ImmediateRegisterLoad32 (line 2448) | struct ImmediateRegisterLoad32
    type ImmediateRegisterLoad16 (line 2456) | struct ImmediateRegisterLoad16
    type TableBranch (line 2463) | struct TableBranch
    type Shift (line 2472) | struct Shift
    type Add32 (line 2478) | struct Add32
    type LogicalShiftLeft32 (line 2491) | struct LogicalShiftLeft32
    type StoreImmediate12 (line 2503) | struct StoreImmediate12
    method ULONG (line 2549) | ULONG GetLongInstruction(BYTE* pSource)
    method BYTE (line 2554) | BYTE EmitLongInstruction(PUSHORT& pDstInst, ULONG instruction)
    method BYTE (line 2561) | BYTE EmitShortInstruction(PUSHORT& pDstInst, USHORT instruction)
    method PBYTE (line 2567) | PBYTE Align4(PBYTE pValue)
    method PBYTE (line 2572) | PBYTE CalculateTarget(PBYTE pSource, LONG delta)
    method LONG (line 2577) | LONG CalculateNewDelta(PBYTE pTarget, BYTE* pDest)
    method BYTE (line 2582) | BYTE    EmitAdd32(PUSHORT& pDstInst, BYTE op1Reg, BYTE op2Reg, BYTE ds...
    method BYTE (line 2591) | BYTE    EmitLogicalShiftLeft32(PUSHORT& pDstInst, BYTE srcReg, BYTE ds...
    method BYTE (line 2599) | BYTE    EmitStoreImmediate12(PUSHORT& pDstInst, BYTE srcReg, BYTE base...
    method DWORD (line 3666) | static DWORD Assemble(DWORD size, DWORD rd, DWORD rn, ULONG imm, DWORD...
    method DWORD (line 3677) | static DWORD AssembleAdd32(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method DWORD (line 3678) | static DWORD AssembleAdd64(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method LONG (line 3692) | inline LONG Imm() const { DWORD Imm = (s.Imm19 << 2) | s.Imm2; return ...
    method DWORD (line 3693) | static DWORD Assemble(DWORD type, DWORD rd, LONG delta)
    method DWORD (line 3703) | static DWORD AssembleAdr(DWORD rd, LONG delta) { return Assemble(0, rd...
    method DWORD (line 3704) | static DWORD AssembleAdrp(DWORD rd, LONG delta) { return Assemble(1, r...
    method LONG (line 3717) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3718) | static DWORD AssembleBcc(DWORD condition, LONG delta)
    method LONG (line 3738) | inline LONG Imm() const { return (LONG)(s.Imm26 << 6) >> 4; }
    method DWORD (line 3739) | static DWORD Assemble(DWORD link, LONG delta)
    method DWORD (line 3747) | static DWORD AssembleB(LONG delta) { return Assemble(0, delta); }
    method DWORD (line 3748) | static DWORD AssembleBl(LONG delta) { return Assemble(1, delta); }
    method DWORD (line 3760) | static DWORD AssembleBr(DWORD rn)
    method LONG (line 3781) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3782) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, LONG delta)
    method LONG (line 3806) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3807) | static DWORD Assemble(DWORD size, DWORD fpneon, DWORD rt, LONG delta)
    method DWORD (line 3833) | static DWORD Assemble(DWORD size, DWORD rt, DWORD rn, ULONG imm)
    method DWORD (line 3859) | static DWORD Assemble(DWORD size, DWORD type, DWORD rd, DWORD imm, DWO...
    method DWORD (line 3870) | static DWORD AssembleMovn32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3871) | static DWORD AssembleMovn64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3872) | static DWORD AssembleMovz32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3873) | static DWORD AssembleMovz64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3874) | static DWORD AssembleMovk32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3875) | static DWORD AssembleMovk64(DWORD rd, DWORD imm, DWORD shift) { return...
    method LONG (line 3890) | inline LONG Imm() const { return (LONG)(s.Imm14 << 18) >> 16; }
    method DWORD (line 3891) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, DWORD bit, LONG ...
    method ULONG (line 3916) | ULONG GetInstruction(BYTE* pSource)
    method BYTE (line 3921) | BYTE EmitInstruction(PULONG& pDstInst, ULONG instruction)
  function LONG (line 2615) | LONG CDetourDis::DecodeBranch5(ULONG opcode)
  function USHORT (line 2628) | USHORT CDetourDis::EncodeBranch5(ULONG originalOpCode, LONG delta)
  function LONG (line 2644) | LONG CDetourDis::DecodeBranch8(ULONG opcode)
  function USHORT (line 2656) | USHORT CDetourDis::EncodeBranch8(ULONG originalOpCode, LONG delta)
  function LONG (line 2671) | LONG CDetourDis::DecodeBranch11(ULONG opcode)
  function USHORT (line 2683) | USHORT CDetourDis::EncodeBranch11(ULONG originalOpCode, LONG delta)
  function BYTE (line 2698) | BYTE CDetourDis::EmitBranch11(PUSHORT& pDest, LONG relativeAddress)
  function LONG (line 2707) | LONG CDetourDis::DecodeBranch20(ULONG opcode)
  function ULONG (line 2727) | ULONG CDetourDis::EncodeBranch20(ULONG originalOpCode, LONG delta)
  function LONG (line 2746) | LONG CDetourDis::DecodeBranch24(ULONG opcode, BOOL& fLink)
  function ULONG (line 2767) | ULONG CDetourDis::EncodeBranch24(ULONG originalOpCode, LONG delta, BOOL ...
  function LONG (line 2787) | LONG CDetourDis::DecodeLiteralLoad8(ULONG instruction)
  function BYTE (line 2798) | BYTE CDetourDis::EmitLiteralLoad8(PUSHORT& pDest, BYTE targetRegister, P...
  function LONG (line 2811) | LONG CDetourDis::DecodeLiteralLoad12(ULONG instruction)
  function BYTE (line 2822) | BYTE CDetourDis::EmitLiteralLoad12(PUSHORT& pDest, BYTE targetRegister, ...
  function BYTE (line 2836) | BYTE CDetourDis::EmitImmediateRegisterLoad32(PUSHORT& pDest, BYTE reg)
  function BYTE (line 2842) | BYTE CDetourDis::EmitImmediateRegisterLoad16(PUSHORT& pDest, BYTE reg)
  function BYTE (line 2848) | BYTE CDetourDis::EmitLongLiteralLoad(PUSHORT& pDest, BYTE targetRegister...
  function BYTE (line 2870) | BYTE CDetourDis::EmitLongBranch(PUSHORT& pDest, PVOID pTarget)
  function BYTE (line 2877) | BYTE CDetourDis::PureCopy16(BYTE* pSource, BYTE* pDest)
  function BYTE (line 2883) | BYTE CDetourDis::PureCopy32(BYTE* pSource, BYTE* pDest)
  function USHORT (line 2889) | USHORT CDetourDis::CalculateExtra(BYTE sourceLength, BYTE* pDestStart, B...
  function BYTE (line 2895) | BYTE CDetourDis::CopyMiscellaneous16(BYTE* pSource, BYTE* pDest)
  function BYTE (line 2956) | BYTE CDetourDis::CopyConditionalBranchOrOther16(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3014) | BYTE CDetourDis::CopyUnConditionalBranch16(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3058) | BYTE CDetourDis::CopyLiteralLoad16(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3078) | BYTE CDetourDis::CopyBranchExchangeOrDataProcessing16(BYTE* pSource, BYT...
  function BYTE (line 3172) | BYTE CDetourDis::CopyBranch24(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3198) | BYTE CDetourDis::CopyBranchOrMiscellaneous32(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3298) | BYTE CDetourDis::CopyLiteralLoad32(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3315) | BYTE CDetourDis::CopyLoadAndStoreSingle(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3355) | BYTE CDetourDis::CopyLoadAndStoreMultipleAndSRS(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3361) | BYTE CDetourDis::CopyTableBranch(BYTE* pSource, BYTE* pDest)
  function BYTE (line 3458) | BYTE CDetourDis::BeginCopy32(BYTE* pSource, BYTE* pDest)
  function PBYTE (line 3555) | PBYTE CDetourDis::CopyInstruction(PBYTE pDst,
  function PVOID (line 3591) | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst,
  class CDetourDis (line 3641) | class CDetourDis
    type COPYENTRY (line 191) | struct COPYENTRY
    type COPYENTRY (line 211) | struct COPYENTRY
    type COPYENTRY (line 2320) | struct COPYENTRY {
    type Branch5 (line 2327) | struct Branch5
    type Branch5Target (line 2336) | struct Branch5Target
    type Branch8 (line 2344) | struct Branch8
    type Branch8Target (line 2351) | struct Branch8Target
    type Branch11 (line 2358) | struct Branch11
    type Branch11Target (line 2364) | struct Branch11Target
    type Branch20 (line 2371) | struct Branch20
    type Branch20Target (line 2384) | struct Branch20Target
    type Branch24 (line 2395) | struct Branch24
    type Branch24Target (line 2408) | struct Branch24Target
    type LiteralLoad8 (line 2419) | struct LiteralLoad8
    type LiteralLoad8Target (line 2426) | struct LiteralLoad8Target
    type LiteralLoad12 (line 2433) | struct LiteralLoad12
    type LiteralLoad12Target (line 2442) | struct LiteralLoad12Target
    type ImmediateRegisterLoad32 (line 2448) | struct ImmediateRegisterLoad32
    type ImmediateRegisterLoad16 (line 2456) | struct ImmediateRegisterLoad16
    type TableBranch (line 2463) | struct TableBranch
    type Shift (line 2472) | struct Shift
    type Add32 (line 2478) | struct Add32
    type LogicalShiftLeft32 (line 2491) | struct LogicalShiftLeft32
    type StoreImmediate12 (line 2503) | struct StoreImmediate12
    method ULONG (line 2549) | ULONG GetLongInstruction(BYTE* pSource)
    method BYTE (line 2554) | BYTE EmitLongInstruction(PUSHORT& pDstInst, ULONG instruction)
    method BYTE (line 2561) | BYTE EmitShortInstruction(PUSHORT& pDstInst, USHORT instruction)
    method PBYTE (line 2567) | PBYTE Align4(PBYTE pValue)
    method PBYTE (line 2572) | PBYTE CalculateTarget(PBYTE pSource, LONG delta)
    method LONG (line 2577) | LONG CalculateNewDelta(PBYTE pTarget, BYTE* pDest)
    method BYTE (line 2582) | BYTE    EmitAdd32(PUSHORT& pDstInst, BYTE op1Reg, BYTE op2Reg, BYTE ds...
    method BYTE (line 2591) | BYTE    EmitLogicalShiftLeft32(PUSHORT& pDstInst, BYTE srcReg, BYTE ds...
    method BYTE (line 2599) | BYTE    EmitStoreImmediate12(PUSHORT& pDstInst, BYTE srcReg, BYTE base...
    method DWORD (line 3666) | static DWORD Assemble(DWORD size, DWORD rd, DWORD rn, ULONG imm, DWORD...
    method DWORD (line 3677) | static DWORD AssembleAdd32(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method DWORD (line 3678) | static DWORD AssembleAdd64(DWORD rd, DWORD rn, ULONG imm, DWORD shift)...
    method LONG (line 3692) | inline LONG Imm() const { DWORD Imm = (s.Imm19 << 2) | s.Imm2; return ...
    method DWORD (line 3693) | static DWORD Assemble(DWORD type, DWORD rd, LONG delta)
    method DWORD (line 3703) | static DWORD AssembleAdr(DWORD rd, LONG delta) { return Assemble(0, rd...
    method DWORD (line 3704) | static DWORD AssembleAdrp(DWORD rd, LONG delta) { return Assemble(1, r...
    method LONG (line 3717) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3718) | static DWORD AssembleBcc(DWORD condition, LONG delta)
    method LONG (line 3738) | inline LONG Imm() const { return (LONG)(s.Imm26 << 6) >> 4; }
    method DWORD (line 3739) | static DWORD Assemble(DWORD link, LONG delta)
    method DWORD (line 3747) | static DWORD AssembleB(LONG delta) { return Assemble(0, delta); }
    method DWORD (line 3748) | static DWORD AssembleBl(LONG delta) { return Assemble(1, delta); }
    method DWORD (line 3760) | static DWORD AssembleBr(DWORD rn)
    method LONG (line 3781) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3782) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, LONG delta)
    method LONG (line 3806) | inline LONG Imm() const { return (LONG)(s.Imm19 << 13) >> 11; }
    method DWORD (line 3807) | static DWORD Assemble(DWORD size, DWORD fpneon, DWORD rt, LONG delta)
    method DWORD (line 3833) | static DWORD Assemble(DWORD size, DWORD rt, DWORD rn, ULONG imm)
    method DWORD (line 3859) | static DWORD Assemble(DWORD size, DWORD type, DWORD rd, DWORD imm, DWO...
    method DWORD (line 3870) | static DWORD AssembleMovn32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3871) | static DWORD AssembleMovn64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3872) | static DWORD AssembleMovz32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3873) | static DWORD AssembleMovz64(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3874) | static DWORD AssembleMovk32(DWORD rd, DWORD imm, DWORD shift) { return...
    method DWORD (line 3875) | static DWORD AssembleMovk64(DWORD rd, DWORD imm, DWORD shift) { return...
    method LONG (line 3890) | inline LONG Imm() const { return (LONG)(s.Imm14 << 18) >> 16; }
    method DWORD (line 3891) | static DWORD Assemble(DWORD size, DWORD nz, DWORD rt, DWORD bit, LONG ...
    method ULONG (line 3916) | ULONG GetInstruction(BYTE* pSource)
    method BYTE (line 3921) | BYTE EmitInstruction(PULONG& pDstInst, ULONG instruction)
  function BYTE (line 3932) | BYTE CDetourDis::PureCopy32(BYTE* pSource, BYTE* pDest)
  function PBYTE (line 3945) | PBYTE CDetourDis::CopyInstruction(PBYTE pDst,
  function BYTE (line 3984) | BYTE CDetourDis::EmitMovImmediate(PULONG& pDstInst, BYTE rd, UINT64 imme...
  function BYTE (line 4035) | BYTE CDetourDis::CopyAdr(BYTE* pSource, BYTE* pDest, ULONG instruction)
  function BYTE (line 4089) | BYTE CDetourDis::CopyBcc(BYTE* pSource, BYTE* pDest, ULONG instruction)
  function BYTE (line 4123) | BYTE CDetourDis::CopyB(BYTE* pSource, BYTE* pDest, ULONG instruction)
  function BYTE (line 4148) | BYTE CDetourDis::CopyCbz(BYTE* pSource, BYTE* pDest, ULONG instruction)
  function BYTE (line 4182) | BYTE CDetourDis::CopyTbz(BYTE* pSource, BYTE* pDest, ULONG instruction)
  function BYTE (line 4216) | BYTE CDetourDis::CopyLdrLiteral(BYTE* pSource, BYTE* pDest, ULONG instru...
  function PVOID (line 4254) | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst,
  function BOOL (line 4272) | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule,

FILE: Detours/image.cpp
  type Detour (line 48) | namespace Detour
    function _Out_ (line 61) | _Out_ size_t* pcch)
    function _Must_inspect_result_ (line 87) | _Must_inspect_result_
    function _Must_inspect_result_ (line 117) | _Must_inspect_result_
    class CImageData (line 145) | class CImageData
      method BOOL (line 160) | BOOL                    IsEmpty()           { return m_cbData == 0; }
    class CImageImportFile (line 173) | class CImageImportFile
    class CImageImportName (line 198) | class CImageImportName
    class CImage (line 215) | class CImage
    function DWORD (line 319) | static inline DWORD Max(DWORD a, DWORD b)
    function DWORD (line 324) | static inline DWORD Align(DWORD a, DWORD size)
    function DWORD (line 330) | static inline DWORD QuadAlign(DWORD a)
    function LPCSTR (line 335) | static LPCSTR DuplicateString(_In_ LPCSTR pszIn)
    function VOID (line 363) | static VOID ReleaseString(_In_opt_ LPCSTR psz)
    function BOOL (line 454) | BOOL CImageData::SizeTo(DWORD cbData)
    function BOOL (line 483) | BOOL CImageData::Purge()
    function BOOL (line 492) | BOOL CImageData::IsValid()
    function PBYTE (line 516) | PBYTE CImageData::Enumerate(GUID *pGuid, DWORD *pcbData, DWORD *pnIter...
    function PBYTE (line 545) | PBYTE CImageData::Find(REFGUID rguid, DWORD *pcbData)
    function BOOL (line 584) | BOOL CImageData::Delete(REFGUID rguid)
    function PBYTE (line 612) | PBYTE CImageData::Set(REFGUID rguid, PBYTE pbData, DWORD cbData)
    class CImageThunks (line 649) | class CImageThunks
      method CImageThunks (line 659) | CImageThunks(CImage *pImage, DWORD nThunksMax, DWORD *pnAddr)
      method PIMAGE_THUNK_DATA (line 670) | PIMAGE_THUNK_DATA Current(DWORD *pnVirtAddr)
      method PIMAGE_THUNK_DATA (line 680) | PIMAGE_THUNK_DATA Allocate(ULONG_PTR nData, DWORD *pnVirtAddr)
      method DWORD (line 694) | DWORD   Size()
    class CImageChars (line 702) | class CImageChars
      method CImageChars (line 712) | CImageChars(CImage *pImage, _In_ DWORD nCharsMax, _Out_ DWORD *pnAddr)
      method LPCSTR (line 721) | LPCSTR Allocate(_In_ LPCSTR pszString, _Out_ DWORD *pnVirtAddr)
      method LPCSTR (line 747) | LPCSTR Allocate(_In_ LPCSTR pszString, _In_ DWORD nHint, _Out_ DWORD...
      method DWORD (line 774) | DWORD Size()
    function CImage (line 782) | CImage * CImage::IsValid(PDETOUR_BINARY pBinary)
    function BOOL (line 822) | BOOL CImage::Close()
    function PBYTE (line 855) | PBYTE CImage::DataEnum(GUID *pGuid, DWORD *pcbData, DWORD *pnIterator)
    function PBYTE (line 863) | PBYTE CImage::DataFind(REFGUID rguid, DWORD *pcbData)
    function PBYTE (line 871) | PBYTE CImage::DataSet(REFGUID rguid, PBYTE pbData, DWORD cbData)
    function BOOL (line 879) | BOOL CImage::DataDelete(REFGUID rguid)
    function BOOL (line 887) | BOOL CImage::DataPurge()
    function BOOL (line 897) | BOOL CImage::SizeOutputBuffer(DWORD cbData)
    function PBYTE (line 926) | PBYTE CImage::AllocateOutput(DWORD cbData, DWORD *pnVirtAddr)
    function DWORD (line 947) | DWORD CImage::FileAlign(DWORD nAddr)
    function DWORD (line 952) | DWORD CImage::SectionAlign(DWORD nAddr)
    function PVOID (line 959) | PVOID CImage::RvaToVa(ULONG_PTR nRva)
    function DWORD (line 978) | DWORD CImage::RvaToFileOffset(DWORD nRva)
    function BOOL (line 995) | BOOL CImage::WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOf...
    function BOOL (line 1006) | BOOL CImage::CopyFileData(HANDLE hFile, DWORD nOldPos, DWORD cbData)
    function BOOL (line 1012) | BOOL CImage::ZeroFileData(HANDLE hFile, DWORD cbData)
    function BOOL (line 1037) | BOOL CImage::AlignFileData(HANDLE hFile)
    function BOOL (line 1055) | BOOL CImage::Read(HANDLE hFile)
    function BOOL (line 1366) | static inline BOOL strneq(_In_ LPCSTR pszOne, _In_ LPCSTR pszTwo)
    function BOOL (line 1377) | BOOL CImage::CheckImportsNeeded(DWORD *pnTables, DWORD *pnThunks, DWOR...
    function CImageImportFile (line 1431) | CImageImportFile * CImage::NewByway(_In_ LPCSTR pszName)
    function BOOL (line 1464) | BOOL CImage::EditImports(PVOID pContext,
    function BOOL (line 1630) | BOOL CImage::Write(HANDLE hFile)
  function PDETOUR_BINARY (line 2069) | PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile)
  function BOOL (line 2086) | BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pdi,
  function WINAPI (line 2100) | WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary,
  function WINAPI (line 2116) | WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary,
  function PVOID (line 2128) | PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary,
  function BOOL (line 2141) | BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary,
  function BOOL (line 2152) | BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary)
  function BOOL (line 2164) | static BOOL CALLBACK ResetBywayCallback(_In_opt_ PVOID pContext,
  function BOOL (line 2175) | static BOOL CALLBACK ResetFileCallback(_In_opt_ PVOID pContext,
  function BOOL (line 2187) | static BOOL CALLBACK ResetSymbolCallback(_In_opt_ PVOID pContext,
  function BOOL (line 2204) | BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary)
  function BOOL (line 2220) | BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary,
  function BOOL (line 2239) | BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary)

FILE: Detours/modules.cpp
  function PVOID (line 161) | PVOID WINAPI DetourFindFunction(_In_ PCSTR pszModule,
  function HMODULE (line 263) | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast)
  function PVOID (line 310) | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule)
  function ULONG (line 383) | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule)
  function HMODULE (line 418) | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr)
  function PBYTE (line 466) | static inline PBYTE RvaAdjust(_Pre_notnull_ PIMAGE_DOS_HEADER pDosHeader...
  function BOOL (line 474) | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule,
  function BOOL (line 551) | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule,
  type _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT (line 653) | struct _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT
  function BOOL (line 662) | static
  function BOOL (line 675) | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
  function PDETOUR_LOADED_BINARY (line 688) | static PDETOUR_LOADED_BINARY WINAPI GetPayloadSectionFromModule(HMODULE ...
  function DWORD (line 752) | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule)
  function WINAPI (line 781) | WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
  function WINAPI (line 845) | WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
  function BOOL (line 860) | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
  function BOOL (line 909) | BOOL WINAPI DetourRestoreAfterWith()

FILE: Detours/uimports.cpp
  function detour_memory_free (line 27) | static void  detour_memory_free(void* p)
  function BOOL (line 37) | static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (607K chars).
[
  {
    "path": ".gitignore",
    "chars": 6027,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "BuildAllTargets.cmd",
    "chars": 334,
    "preview": "@setlocal\n@echo off\n\nrem Change to the current folder.\ncd \"%~dp0\"\n\nrem Remove the output folder for a fresh compile.\nrd "
  },
  {
    "path": "BuildAllTargets.proj",
    "chars": 2741,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project \n  DefaultTargets=\"Restore;Build\"\n  xmlns=\"http://schemas.microsoft.com"
  },
  {
    "path": "Detours/api_thunks.cpp",
    "chars": 12776,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Detours Disassembler (disasm.cpp o"
  },
  {
    "path": "Detours/api_thunks.h",
    "chars": 2581,
    "preview": "#pragma once\n\nnamespace Detours::Thunks\n{\n    VOID WINAPI SetLastError(_In_ DWORD Win32Error);\n    DWORD WINAPI GetLastE"
  },
  {
    "path": "Detours/creatwth.cpp",
    "chars": 56510,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Create a process with a DLL (creat"
  },
  {
    "path": "Detours/detours.cpp",
    "chars": 80427,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Core Detours Functionality (detour"
  },
  {
    "path": "Detours/detours.h",
    "chars": 38234,
    "preview": "/////////////////////////////////////////////////////////////////////////////\n//\n//  Core Detours Functionality (detours"
  },
  {
    "path": "Detours/detoursx.cpp",
    "chars": 80281,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Core Detours Functionality (detour"
  },
  {
    "path": "Detours/detver.h",
    "chars": 720,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Common version parameters.\n//\n//  "
  },
  {
    "path": "Detours/disasm.cpp",
    "chars": 164429,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Detours Disassembler (disasm.cpp o"
  },
  {
    "path": "Detours/disolarm.cpp",
    "chars": 58,
    "preview": "#define DETOURS_ARM_OFFLINE_LIBRARY\n#include \"disasm.cpp\"\n"
  },
  {
    "path": "Detours/disolarm64.cpp",
    "chars": 60,
    "preview": "#define DETOURS_ARM64_OFFLINE_LIBRARY\n#include \"disasm.cpp\"\n"
  },
  {
    "path": "Detours/disolia64.cpp",
    "chars": 59,
    "preview": "#define DETOURS_IA64_OFFLINE_LIBRARY\n#include \"disasm.cpp\"\n"
  },
  {
    "path": "Detours/disolx64.cpp",
    "chars": 58,
    "preview": "#define DETOURS_X64_OFFLINE_LIBRARY\n#include \"disasm.cpp\"\n"
  },
  {
    "path": "Detours/disolx86.cpp",
    "chars": 58,
    "preview": "#define DETOURS_X86_OFFLINE_LIBRARY\n#include \"disasm.cpp\"\n"
  },
  {
    "path": "Detours/image.cpp",
    "chars": 66715,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Image manipulation functions (imag"
  },
  {
    "path": "Detours/modules.cpp",
    "chars": 32170,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Module Enumeration Functions (modu"
  },
  {
    "path": "Detours/uimports.cpp",
    "chars": 10257,
    "preview": "//////////////////////////////////////////////////////////////////////////////\n//\n//  Add DLLs to a module import table "
  },
  {
    "path": "Detours.StaticLibrary/Detours.StaticLibrary.vcxproj",
    "chars": 2973,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Detours.StaticLibraryForDriver/Detours.StaticLibraryForDriver.vcxproj",
    "chars": 2950,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Detours.Test/Detours.Test.vcxproj",
    "chars": 1993,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Detours.Test/Main.cpp",
    "chars": 5003,
    "preview": "#include <Veil.h>\n#include <detours.h>\n\nvoid LogPrint(\n    _In_z_ _Printf_format_string_ PCSTR Format,\n    ...);\n#define"
  },
  {
    "path": "Detours.Test/Module.def",
    "chars": 50,
    "preview": "EXPORTS\n    DetourFinishHelperProcess  @1   NONAME"
  },
  {
    "path": "Detours.TestForDriver/Detours.TestForDriver.inf",
    "chars": 4095,
    "preview": ";-------------------------------------------------------------------------\n; Detours.TestForDriver.INF -- NT Legacy Driv"
  },
  {
    "path": "Detours.TestForDriver/Detours.TestForDriver.vcxproj",
    "chars": 2050,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Detours.TestForDriver/Main.cpp",
    "chars": 4773,
    "preview": "// unnecessary, fix ReSharper's code analysis.\n#pragma warning(suppress: 4117)\n#define _KERNEL_MODE 1\n\n#include <Veil.h>"
  },
  {
    "path": "DetoursX.slnx",
    "chars": 925,
    "preview": "<Solution>\n  <Configurations>\n    <Platform Name=\"ARM64\" />\n    <Platform Name=\"x64\" />\n    <Platform Name=\"x86\" />\n  </"
  },
  {
    "path": "Directory.Build.props",
    "chars": 1245,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- \nThis file allow for customizing your build process.\nSee: https://learn.mic"
  },
  {
    "path": "Directory.Build.targets",
    "chars": 396,
    "preview": "<!-- \nThis file allow for customizing your build process.\nSee: https://learn.microsoft.com/visualstudio/msbuild/customiz"
  },
  {
    "path": "Directory.Packages.Cpp.props",
    "chars": 841,
    "preview": "<!--\n  This enabled central package management. \n  This allows for controling all NuGet packages within the Directory.Pa"
  },
  {
    "path": "InitializeVisualStudioEnvironment.cmd",
    "chars": 796,
    "preview": "@rem \n@rem PROJECT:   Mouri Internal Library Essentials\n@rem FILE:      InitializeVisualStudioEnvironment.cmd\n@rem PURPO"
  },
  {
    "path": "LICENSE",
    "chars": 1099,
    "preview": "# Copyright (c) Microsoft Corporation\n\nAll rights reserved.\n\n# MIT License\n\nPermission is hereby granted, free of charge"
  },
  {
    "path": "README.md",
    "chars": 1119,
    "preview": "# [DetoursX](https://github.com/mirokaku/DetoursX)\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](http"
  },
  {
    "path": "README.zh-CN.md",
    "chars": 1285,
    "preview": "# [DetoursX](https://github.com/mirokaku/DetoursX)\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](http"
  },
  {
    "path": "global.json",
    "chars": 73,
    "preview": "{\n  \"msbuild-sdks\": {\n    \"Mile.Project.Configurations\": \"1.0.1622\"\n  }\n}"
  }
]

About this extraction

This page contains the full source code of the MiroKaku/DetoursX GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (572.4 KB), approximately 161.2k tokens, and a symbol index with 519 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!