Full Code of CCob/SylantStrike for AI

master 11f613c4fe00 cached
32 files
198.7 KB
51.6k tokens
250 symbols
1 requests
Download .txt
Showing preview only (209K chars total). Download the full file or copy to clipboard to get everything.
Repository: CCob/SylantStrike
Branch: master
Commit: 11f613c4fe00
Files: 32
Total size: 198.7 KB

Directory structure:
gitextract_uwm5figu/

├── .gitattributes
├── .gitignore
├── README.md
├── SylantStrike/
│   ├── SylantStrike.cpp
│   ├── SylantStrike.h
│   ├── SylantStrike.vcxproj
│   ├── SylantStrike.vcxproj.filters
│   ├── cpp.hint
│   ├── dllmain.cpp
│   ├── framework.h
│   ├── minhook/
│   │   ├── include/
│   │   │   └── MinHook.h
│   │   └── src/
│   │       ├── buffer.c
│   │       ├── buffer.h
│   │       ├── hde/
│   │       │   ├── hde32.c
│   │       │   ├── hde32.h
│   │       │   ├── hde64.c
│   │       │   ├── hde64.h
│   │       │   ├── pstdint.h
│   │       │   ├── table32.h
│   │       │   └── table64.h
│   │       ├── hook.c
│   │       ├── trampoline.c
│   │       └── trampoline.h
│   ├── pch.cpp
│   └── pch.h
├── SylantStrike.sln
└── SylantStrikeInject/
    ├── App.config
    ├── BasicInject.cs
    ├── Options.cs
    ├── Program.cs
    ├── Properties/
    │   └── AssemblyInfo.cs
    └── SylantStrikeInject.csproj

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

================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following 
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
# 
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the 
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain


================================================
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

# 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/

# Visual Studio 2015/2017 cache/options directory
.vs/
# 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

# 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

# JustCode is a .NET coding add-in
.JustCode

# 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
# 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

# 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
*- Backup*.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/

# JetBrains Rider
.idea/
*.sln.iml

# 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

================================================
FILE: README.md
================================================
### SylantStrike - a simple EDR written as part of a two part blog series on creating and bypassing an EDR

Original blog post with description at https://ethicalchaos.dev/2020/05/27/lets-create-an-edr-and-bypass-it-part-1/


================================================
FILE: SylantStrike/SylantStrike.cpp
================================================
// SylantStrike.cpp : Hooked API implementations
//

#include "pch.h"
#include "framework.h"
#include "SylantStrike.h"

//Pointer to the trampoline function used to call the original API
pNtProtectVirtualMemory pOriginalNtProtectVirtualMemory = nullptr;

DWORD NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection) {

	//Check to see if the calling application is requesting RWX
	if ((NewAccessProtection & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE) {
		//It was, so notify the user of naughtly behaviour and terminate the running program
		MessageBox(nullptr, TEXT("You've been a naughty little hax0r, terminating program"), TEXT("Hax0r Detected"), MB_OK);
		TerminateProcess(GetCurrentProcess(), 0xdead1337);
		//Unreachable code
		return 0;
	}

	//No it wasn't, so just call the original function as normal
	return pOriginalNtProtectVirtualMemory(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection);
}


================================================
FILE: SylantStrike/SylantStrike.h
================================================
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the CYLANTSTRIKE_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// CYLANTSTRIKE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef CYLANTSTRIKE_EXPORTS
#define CYLANTSTRIKE_API __declspec(dllexport)
#else
#define CYLANTSTRIKE_API __declspec(dllimport)
#endif

typedef DWORD (NTAPI *pNtProtectVirtualMemory)(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection);

extern pNtProtectVirtualMemory pOriginalNtProtectVirtualMemory;


DWORD NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection);





================================================
FILE: SylantStrike/SylantStrike.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{1ddd15aa-d837-4143-a272-0e08f9ed6c40}</ProjectGuid>
    <RootNamespace>CylantStrike</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
    <ProjectName>SylantStrike</ProjectName>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <SpectreMitigation>false</SpectreMitigation>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
    <TargetName>SylantStrike</TargetName>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
    <TargetName>SylantStrike</TargetName>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <TargetName>SylantStrike</TargetName>
    <IgnoreImportLibrary>true</IgnoreImportLibrary>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <TargetName>SylantStrike</TargetName>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <None Include="cpp.hint" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="SylantStrike.h" />
    <ClInclude Include="framework.h" />
    <ClInclude Include="minhook\include\MinHook.h" />
    <ClInclude Include="minhook\src\buffer.h" />
    <ClInclude Include="minhook\src\hde\hde32.h" />
    <ClInclude Include="minhook\src\hde\hde64.h" />
    <ClInclude Include="minhook\src\hde\pstdint.h" />
    <ClInclude Include="minhook\src\hde\table32.h" />
    <ClInclude Include="minhook\src\hde\table64.h" />
    <ClInclude Include="minhook\src\trampoline.h" />
    <ClInclude Include="pch.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="SylantStrike.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="dllmain.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="minhook\src\buffer.c">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="minhook\src\hde\hde32.c">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="minhook\src\hde\hde64.c">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="minhook\src\hook.c">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="minhook\src\trampoline.c">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="pch.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
    </ClCompile>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: SylantStrike/SylantStrike.vcxproj.filters
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <None Include="cpp.hint" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="framework.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="pch.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\buffer.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\trampoline.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\include\MinHook.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\hde\hde32.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\hde\hde64.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\hde\pstdint.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\hde\table32.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="minhook\src\hde\table64.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="SylantStrike.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="dllmain.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="pch.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="minhook\src\buffer.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="minhook\src\hook.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="minhook\src\trampoline.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="minhook\src\hde\hde32.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="minhook\src\hde\hde64.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="SylantStrike.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
</Project>

================================================
FILE: SylantStrike/cpp.hint
================================================
#define CYLANTSTRIKE_API __declspec(dllexport)
#define CYLANTSTRIKE_API __declspec(dllimport)


================================================
FILE: SylantStrike/dllmain.cpp
================================================
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"

#include "minhook/include/MinHook.h"
#include "SylantStrike.h"

DWORD WINAPI InitHooksThread(LPVOID param) {

    //MinHook itself requires initialisation, lets do this
    //before we hook specific API calls.
    if (MH_Initialize() != MH_OK) {
        OutputDebugString(TEXT("Failed to initalize MinHook library\n"));
        return -1;
    }

    //Now that we have initialised MinHook, lets prepare to hook NtProtectVirtualMemory from ntdll.dll
    MH_STATUS status = MH_CreateHookApi(TEXT("ntdll"), "NtProtectVirtualMemory", NtProtectVirtualMemory, 
                                           reinterpret_cast<LPVOID*>(&pOriginalNtProtectVirtualMemory));  

    //Enable our hooks so they become active
    status = MH_EnableHook(MH_ALL_HOOKS);

    return status;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: {
        //We are not interested in callbacks when a thread is created
        DisableThreadLibraryCalls(hModule);

        //We need to create a thread when initialising our hooks since
        //DllMain is prone to lockups if executing code inline.
        HANDLE hThread = CreateThread(nullptr, 0, InitHooksThread, nullptr, 0, nullptr);
        if (hThread != nullptr) {
            CloseHandle(hThread);
        }
        break;
    }
    case DLL_PROCESS_DETACH:

        break;
    }
    return TRUE;
}



================================================
FILE: SylantStrike/framework.h
================================================
#pragma once

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>


================================================
FILE: SylantStrike/minhook/include/MinHook.h
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
    #error MinHook supports only x86 and x64 systems.
#endif

#include <windows.h>

// MinHook Error Codes.
typedef enum MH_STATUS
{
    // Unknown error. Should not be returned.
    MH_UNKNOWN = -1,

    // Successful.
    MH_OK = 0,

    // MinHook is already initialized.
    MH_ERROR_ALREADY_INITIALIZED,

    // MinHook is not initialized yet, or already uninitialized.
    MH_ERROR_NOT_INITIALIZED,

    // The hook for the specified target function is already created.
    MH_ERROR_ALREADY_CREATED,

    // The hook for the specified target function is not created yet.
    MH_ERROR_NOT_CREATED,

    // The hook for the specified target function is already enabled.
    MH_ERROR_ENABLED,

    // The hook for the specified target function is not enabled yet, or already
    // disabled.
    MH_ERROR_DISABLED,

    // The specified pointer is invalid. It points the address of non-allocated
    // and/or non-executable region.
    MH_ERROR_NOT_EXECUTABLE,

    // The specified target function cannot be hooked.
    MH_ERROR_UNSUPPORTED_FUNCTION,

    // Failed to allocate memory.
    MH_ERROR_MEMORY_ALLOC,

    // Failed to change the memory protection.
    MH_ERROR_MEMORY_PROTECT,

    // The specified module is not loaded.
    MH_ERROR_MODULE_NOT_FOUND,

    // The specified function is not found.
    MH_ERROR_FUNCTION_NOT_FOUND
}
MH_STATUS;

// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
// MH_QueueEnableHook or MH_QueueDisableHook.
#define MH_ALL_HOOKS NULL

#ifdef __cplusplus
extern "C" {
#endif

    // Initialize the MinHook library. You must call this function EXACTLY ONCE
    // at the beginning of your program.
    MH_STATUS WINAPI MH_Initialize(VOID);

    // Uninitialize the MinHook library. You must call this function EXACTLY
    // ONCE at the end of your program.
    MH_STATUS WINAPI MH_Uninitialize(VOID);

    // Creates a Hook for the specified target function, in disabled state.
    // Parameters:
    //   pTarget    [in]  A pointer to the target function, which will be
    //                    overridden by the detour function.
    //   pDetour    [in]  A pointer to the detour function, which will override
    //                    the target function.
    //   ppOriginal [out] A pointer to the trampoline function, which will be
    //                    used to call the original target function.
    //                    This parameter can be NULL.
    MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);

    // Creates a Hook for the specified API function, in disabled state.
    // Parameters:
    //   pszModule  [in]  A pointer to the loaded module name which contains the
    //                    target function.
    //   pszTarget  [in]  A pointer to the target function name, which will be
    //                    overridden by the detour function.
    //   pDetour    [in]  A pointer to the detour function, which will override
    //                    the target function.
    //   ppOriginal [out] A pointer to the trampoline function, which will be
    //                    used to call the original target function.
    //                    This parameter can be NULL.
    MH_STATUS WINAPI MH_CreateHookApi(
        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);

    // Creates a Hook for the specified API function, in disabled state.
    // Parameters:
    //   pszModule  [in]  A pointer to the loaded module name which contains the
    //                    target function.
    //   pszTarget  [in]  A pointer to the target function name, which will be
    //                    overridden by the detour function.
    //   pDetour    [in]  A pointer to the detour function, which will override
    //                    the target function.
    //   ppOriginal [out] A pointer to the trampoline function, which will be
    //                    used to call the original target function.
    //                    This parameter can be NULL.
    //   ppTarget   [out] A pointer to the target function, which will be used
    //                    with other functions.
    //                    This parameter can be NULL.
    MH_STATUS WINAPI MH_CreateHookApiEx(
        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);

    // Removes an already created hook.
    // Parameters:
    //   pTarget [in] A pointer to the target function.
    MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);

    // Enables an already created hook.
    // Parameters:
    //   pTarget [in] A pointer to the target function.
    //                If this parameter is MH_ALL_HOOKS, all created hooks are
    //                enabled in one go.
    MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);

    // Disables an already created hook.
    // Parameters:
    //   pTarget [in] A pointer to the target function.
    //                If this parameter is MH_ALL_HOOKS, all created hooks are
    //                disabled in one go.
    MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);

    // Queues to enable an already created hook.
    // Parameters:
    //   pTarget [in] A pointer to the target function.
    //                If this parameter is MH_ALL_HOOKS, all created hooks are
    //                queued to be enabled.
    MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);

    // Queues to disable an already created hook.
    // Parameters:
    //   pTarget [in] A pointer to the target function.
    //                If this parameter is MH_ALL_HOOKS, all created hooks are
    //                queued to be disabled.
    MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);

    // Applies all queued changes in one go.
    MH_STATUS WINAPI MH_ApplyQueued(VOID);

    // Translates the MH_STATUS to its name as a string.
    const char * WINAPI MH_StatusToString(MH_STATUS status);

#ifdef __cplusplus
}
#endif



================================================
FILE: SylantStrike/minhook/src/buffer.c
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <windows.h>
#include "buffer.h"

// Size of each memory block. (= page size of VirtualAlloc)
#define MEMORY_BLOCK_SIZE 0x1000

// Max range for seeking a memory block. (= 1024MB)
#define MAX_MEMORY_RANGE 0x40000000

// Memory protection flags to check the executable address.
#define PAGE_EXECUTE_FLAGS \
    (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)

// Memory slot.
typedef struct _MEMORY_SLOT
{
    union
    {
        struct _MEMORY_SLOT *pNext;
        UINT8 buffer[MEMORY_SLOT_SIZE];
    };
} MEMORY_SLOT, *PMEMORY_SLOT;

// Memory block info. Placed at the head of each block.
typedef struct _MEMORY_BLOCK
{
    struct _MEMORY_BLOCK *pNext;
    PMEMORY_SLOT pFree;         // First element of the free slot list.
    UINT usedCount;
} MEMORY_BLOCK, *PMEMORY_BLOCK;

//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------

// First element of the memory block list.
PMEMORY_BLOCK g_pMemoryBlocks;

//-------------------------------------------------------------------------
VOID InitializeBuffer(VOID)
{
    // Nothing to do for now.
}

//-------------------------------------------------------------------------
VOID UninitializeBuffer(VOID)
{
    PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
    g_pMemoryBlocks = NULL;

    while (pBlock)
    {
        PMEMORY_BLOCK pNext = pBlock->pNext;
        VirtualFree(pBlock, 0, MEM_RELEASE);
        pBlock = pNext;
    }
}

//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
{
    ULONG_PTR tryAddr = (ULONG_PTR)pAddress;

    // Round down to the allocation granularity.
    tryAddr -= tryAddr % dwAllocationGranularity;

    // Start from the previous allocation granularity multiply.
    tryAddr -= dwAllocationGranularity;

    while (tryAddr >= (ULONG_PTR)pMinAddr)
    {
        MEMORY_BASIC_INFORMATION mbi;
        if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
            break;

        if (mbi.State == MEM_FREE)
            return (LPVOID)tryAddr;

        if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
            break;

        tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
    }

    return NULL;
}
#endif

//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
{
    ULONG_PTR tryAddr = (ULONG_PTR)pAddress;

    // Round down to the allocation granularity.
    tryAddr -= tryAddr % dwAllocationGranularity;

    // Start from the next allocation granularity multiply.
    tryAddr += dwAllocationGranularity;

    while (tryAddr <= (ULONG_PTR)pMaxAddr)
    {
        MEMORY_BASIC_INFORMATION mbi;
        if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
            break;

        if (mbi.State == MEM_FREE)
            return (LPVOID)tryAddr;

        tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;

        // Round up to the next allocation granularity.
        tryAddr += dwAllocationGranularity - 1;
        tryAddr -= tryAddr % dwAllocationGranularity;
    }

    return NULL;
}
#endif

//-------------------------------------------------------------------------
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
{
    PMEMORY_BLOCK pBlock;
#if defined(_M_X64) || defined(__x86_64__)
    ULONG_PTR minAddr;
    ULONG_PTR maxAddr;

    SYSTEM_INFO si;
    GetSystemInfo(&si);
    minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
    maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;

    // pOrigin ± 512MB
    if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
        minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;

    if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
        maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;

    // Make room for MEMORY_BLOCK_SIZE bytes.
    maxAddr -= MEMORY_BLOCK_SIZE - 1;
#endif

    // Look the registered blocks for a reachable one.
    for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
    {
#if defined(_M_X64) || defined(__x86_64__)
        // Ignore the blocks too far.
        if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
            continue;
#endif
        // The block has at least one unused slot.
        if (pBlock->pFree != NULL)
            return pBlock;
    }

#if defined(_M_X64) || defined(__x86_64__)
    // Alloc a new block above if not found.
    {
        LPVOID pAlloc = pOrigin;
        while ((ULONG_PTR)pAlloc >= minAddr)
        {
            pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
            if (pAlloc == NULL)
                break;

            pBlock = (PMEMORY_BLOCK)VirtualAlloc(
                pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (pBlock != NULL)
                break;
        }
    }

    // Alloc a new block below if not found.
    if (pBlock == NULL)
    {
        LPVOID pAlloc = pOrigin;
        while ((ULONG_PTR)pAlloc <= maxAddr)
        {
            pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
            if (pAlloc == NULL)
                break;

            pBlock = (PMEMORY_BLOCK)VirtualAlloc(
                pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (pBlock != NULL)
                break;
        }
    }
#else
    // In x86 mode, a memory block can be placed anywhere.
    pBlock = (PMEMORY_BLOCK)VirtualAlloc(
        NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
#endif

    if (pBlock != NULL)
    {
        // Build a linked list of all the slots.
        PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
        pBlock->pFree = NULL;
        pBlock->usedCount = 0;
        do
        {
            pSlot->pNext = pBlock->pFree;
            pBlock->pFree = pSlot;
            pSlot++;
        } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);

        pBlock->pNext = g_pMemoryBlocks;
        g_pMemoryBlocks = pBlock;
    }

    return pBlock;
}

//-------------------------------------------------------------------------
LPVOID AllocateBuffer(LPVOID pOrigin)
{
    PMEMORY_SLOT  pSlot;
    PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
    if (pBlock == NULL)
        return NULL;

    // Remove an unused slot from the list.
    pSlot = pBlock->pFree;
    pBlock->pFree = pSlot->pNext;
    pBlock->usedCount++;
#ifdef _DEBUG
    // Fill the slot with INT3 for debugging.
    memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
#endif
    return pSlot;
}

//-------------------------------------------------------------------------
VOID FreeBuffer(LPVOID pBuffer)
{
    PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
    PMEMORY_BLOCK pPrev = NULL;
    ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;

    while (pBlock != NULL)
    {
        if ((ULONG_PTR)pBlock == pTargetBlock)
        {
            PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
#ifdef _DEBUG
            // Clear the released slot for debugging.
            memset(pSlot, 0x00, sizeof(*pSlot));
#endif
            // Restore the released slot to the list.
            pSlot->pNext = pBlock->pFree;
            pBlock->pFree = pSlot;
            pBlock->usedCount--;

            // Free if unused.
            if (pBlock->usedCount == 0)
            {
                if (pPrev)
                    pPrev->pNext = pBlock->pNext;
                else
                    g_pMemoryBlocks = pBlock->pNext;

                VirtualFree(pBlock, 0, MEM_RELEASE);
            }

            break;
        }

        pPrev = pBlock;
        pBlock = pBlock->pNext;
    }
}

//-------------------------------------------------------------------------
BOOL IsExecutableAddress(LPVOID pAddress)
{
    MEMORY_BASIC_INFORMATION mi;
    VirtualQuery(pAddress, &mi, sizeof(mi));

    return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
}


================================================
FILE: SylantStrike/minhook/src/buffer.h
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

// Size of each memory slot.
#if defined(_M_X64) || defined(__x86_64__)
    #define MEMORY_SLOT_SIZE 64
#else
    #define MEMORY_SLOT_SIZE 32
#endif

VOID   InitializeBuffer(VOID);
VOID   UninitializeBuffer(VOID);
LPVOID AllocateBuffer(LPVOID pOrigin);
VOID   FreeBuffer(LPVOID pBuffer);
BOOL   IsExecutableAddress(LPVOID pAddress);


================================================
FILE: SylantStrike/minhook/src/hde/hde32.c
================================================
/*
 * Hacker Disassembler Engine 32 C
 * Copyright (c) 2008-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 */

#if defined(_M_IX86) || defined(__i386__)

#include "hde32.h"
#include "table32.h"

unsigned int hde32_disasm(const void *code, hde32s *hs)
{
    uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
    uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;

    // Avoid using memset to reduce the footprint.
#ifndef _MSC_VER
    memset((LPBYTE)hs, 0, sizeof(hde32s));
#else
    __stosb((LPBYTE)hs, 0, sizeof(hde32s));
#endif

    for (x = 16; x; x--)
        switch (c = *p++) {
            case 0xf3:
                hs->p_rep = c;
                pref |= PRE_F3;
                break;
            case 0xf2:
                hs->p_rep = c;
                pref |= PRE_F2;
                break;
            case 0xf0:
                hs->p_lock = c;
                pref |= PRE_LOCK;
                break;
            case 0x26: case 0x2e: case 0x36:
            case 0x3e: case 0x64: case 0x65:
                hs->p_seg = c;
                pref |= PRE_SEG;
                break;
            case 0x66:
                hs->p_66 = c;
                pref |= PRE_66;
                break;
            case 0x67:
                hs->p_67 = c;
                pref |= PRE_67;
                break;
            default:
                goto pref_done;
        }
  pref_done:

    hs->flags = (uint32_t)pref << 23;

    if (!pref)
        pref |= PRE_NONE;

    if ((hs->opcode = c) == 0x0f) {
        hs->opcode2 = c = *p++;
        ht += DELTA_OPCODES;
    } else if (c >= 0xa0 && c <= 0xa3) {
        if (pref & PRE_67)
            pref |= PRE_66;
        else
            pref &= ~PRE_66;
    }

    opcode = c;
    cflags = ht[ht[opcode / 4] + (opcode % 4)];

    if (cflags == C_ERROR) {
        hs->flags |= F_ERROR | F_ERROR_OPCODE;
        cflags = 0;
        if ((opcode & -3) == 0x24)
            cflags++;
    }

    x = 0;
    if (cflags & C_GROUP) {
        uint16_t t;
        t = *(uint16_t *)(ht + (cflags & 0x7f));
        cflags = (uint8_t)t;
        x = (uint8_t)(t >> 8);
    }

    if (hs->opcode2) {
        ht = hde32_table + DELTA_PREFIXES;
        if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
            hs->flags |= F_ERROR | F_ERROR_OPCODE;
    }

    if (cflags & C_MODRM) {
        hs->flags |= F_MODRM;
        hs->modrm = c = *p++;
        hs->modrm_mod = m_mod = c >> 6;
        hs->modrm_rm = m_rm = c & 7;
        hs->modrm_reg = m_reg = (c & 0x3f) >> 3;

        if (x && ((x << m_reg) & 0x80))
            hs->flags |= F_ERROR | F_ERROR_OPCODE;

        if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
            uint8_t t = opcode - 0xd9;
            if (m_mod == 3) {
                ht = hde32_table + DELTA_FPU_MODRM + t*8;
                t = ht[m_reg] << m_rm;
            } else {
                ht = hde32_table + DELTA_FPU_REG;
                t = ht[t] << m_reg;
            }
            if (t & 0x80)
                hs->flags |= F_ERROR | F_ERROR_OPCODE;
        }

        if (pref & PRE_LOCK) {
            if (m_mod == 3) {
                hs->flags |= F_ERROR | F_ERROR_LOCK;
            } else {
                uint8_t *table_end, op = opcode;
                if (hs->opcode2) {
                    ht = hde32_table + DELTA_OP2_LOCK_OK;
                    table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
                } else {
                    ht = hde32_table + DELTA_OP_LOCK_OK;
                    table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
                    op &= -2;
                }
                for (; ht != table_end; ht++)
                    if (*ht++ == op) {
                        if (!((*ht << m_reg) & 0x80))
                            goto no_lock_error;
                        else
                            break;
                    }
                hs->flags |= F_ERROR | F_ERROR_LOCK;
              no_lock_error:
                ;
            }
        }

        if (hs->opcode2) {
            switch (opcode) {
                case 0x20: case 0x22:
                    m_mod = 3;
                    if (m_reg > 4 || m_reg == 1)
                        goto error_operand;
                    else
                        goto no_error_operand;
                case 0x21: case 0x23:
                    m_mod = 3;
                    if (m_reg == 4 || m_reg == 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
            }
        } else {
            switch (opcode) {
                case 0x8c:
                    if (m_reg > 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
                case 0x8e:
                    if (m_reg == 1 || m_reg > 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
            }
        }

        if (m_mod == 3) {
            uint8_t *table_end;
            if (hs->opcode2) {
                ht = hde32_table + DELTA_OP2_ONLY_MEM;
                table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
            } else {
                ht = hde32_table + DELTA_OP_ONLY_MEM;
                table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
            }
            for (; ht != table_end; ht += 2)
                if (*ht++ == opcode) {
                    if (*ht++ & pref && !((*ht << m_reg) & 0x80))
                        goto error_operand;
                    else
                        break;
                }
            goto no_error_operand;
        } else if (hs->opcode2) {
            switch (opcode) {
                case 0x50: case 0xd7: case 0xf7:
                    if (pref & (PRE_NONE | PRE_66))
                        goto error_operand;
                    break;
                case 0xd6:
                    if (pref & (PRE_F2 | PRE_F3))
                        goto error_operand;
                    break;
                case 0xc5:
                    goto error_operand;
            }
            goto no_error_operand;
        } else
            goto no_error_operand;

      error_operand:
        hs->flags |= F_ERROR | F_ERROR_OPERAND;
      no_error_operand:

        c = *p++;
        if (m_reg <= 1) {
            if (opcode == 0xf6)
                cflags |= C_IMM8;
            else if (opcode == 0xf7)
                cflags |= C_IMM_P66;
        }

        switch (m_mod) {
            case 0:
                if (pref & PRE_67) {
                    if (m_rm == 6)
                        disp_size = 2;
                } else
                    if (m_rm == 5)
                        disp_size = 4;
                break;
            case 1:
                disp_size = 1;
                break;
            case 2:
                disp_size = 2;
                if (!(pref & PRE_67))
                    disp_size <<= 1;
        }

        if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
            hs->flags |= F_SIB;
            p++;
            hs->sib = c;
            hs->sib_scale = c >> 6;
            hs->sib_index = (c & 0x3f) >> 3;
            if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
                disp_size = 4;
        }

        p--;
        switch (disp_size) {
            case 1:
                hs->flags |= F_DISP8;
                hs->disp.disp8 = *p;
                break;
            case 2:
                hs->flags |= F_DISP16;
                hs->disp.disp16 = *(uint16_t *)p;
                break;
            case 4:
                hs->flags |= F_DISP32;
                hs->disp.disp32 = *(uint32_t *)p;
        }
        p += disp_size;
    } else if (pref & PRE_LOCK)
        hs->flags |= F_ERROR | F_ERROR_LOCK;

    if (cflags & C_IMM_P66) {
        if (cflags & C_REL32) {
            if (pref & PRE_66) {
                hs->flags |= F_IMM16 | F_RELATIVE;
                hs->imm.imm16 = *(uint16_t *)p;
                p += 2;
                goto disasm_done;
            }
            goto rel32_ok;
        }
        if (pref & PRE_66) {
            hs->flags |= F_IMM16;
            hs->imm.imm16 = *(uint16_t *)p;
            p += 2;
        } else {
            hs->flags |= F_IMM32;
            hs->imm.imm32 = *(uint32_t *)p;
            p += 4;
        }
    }

    if (cflags & C_IMM16) {
        if (hs->flags & F_IMM32) {
            hs->flags |= F_IMM16;
            hs->disp.disp16 = *(uint16_t *)p;
        } else if (hs->flags & F_IMM16) {
            hs->flags |= F_2IMM16;
            hs->disp.disp16 = *(uint16_t *)p;
        } else {
            hs->flags |= F_IMM16;
            hs->imm.imm16 = *(uint16_t *)p;
        }
        p += 2;
    }
    if (cflags & C_IMM8) {
        hs->flags |= F_IMM8;
        hs->imm.imm8 = *p++;
    }

    if (cflags & C_REL32) {
      rel32_ok:
        hs->flags |= F_IMM32 | F_RELATIVE;
        hs->imm.imm32 = *(uint32_t *)p;
        p += 4;
    } else if (cflags & C_REL8) {
        hs->flags |= F_IMM8 | F_RELATIVE;
        hs->imm.imm8 = *p++;
    }

  disasm_done:

    if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
        hs->flags |= F_ERROR | F_ERROR_LENGTH;
        hs->len = 15;
    }

    return (unsigned int)hs->len;
}

#endif // defined(_M_IX86) || defined(__i386__)


================================================
FILE: SylantStrike/minhook/src/hde/hde32.h
================================================
/*
 * Hacker Disassembler Engine 32
 * Copyright (c) 2006-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 * hde32.h: C/C++ header file
 *
 */

#ifndef _HDE32_H_
#define _HDE32_H_

/* stdint.h - C99 standard header
 * http://en.wikipedia.org/wiki/stdint.h
 *
 * if your compiler doesn't contain "stdint.h" header (for
 * example, Microsoft Visual C++), you can download file:
 *   http://www.azillionmonkeys.com/qed/pstdint.h
 * and change next line to:
 *   #include "pstdint.h"
 */
#include "pstdint.h"

#define F_MODRM         0x00000001
#define F_SIB           0x00000002
#define F_IMM8          0x00000004
#define F_IMM16         0x00000008
#define F_IMM32         0x00000010
#define F_DISP8         0x00000020
#define F_DISP16        0x00000040
#define F_DISP32        0x00000080
#define F_RELATIVE      0x00000100
#define F_2IMM16        0x00000800
#define F_ERROR         0x00001000
#define F_ERROR_OPCODE  0x00002000
#define F_ERROR_LENGTH  0x00004000
#define F_ERROR_LOCK    0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ  0x01000000
#define F_PREFIX_REPX   0x02000000
#define F_PREFIX_REP    0x03000000
#define F_PREFIX_66     0x04000000
#define F_PREFIX_67     0x08000000
#define F_PREFIX_LOCK   0x10000000
#define F_PREFIX_SEG    0x20000000
#define F_PREFIX_ANY    0x3f000000

#define PREFIX_SEGMENT_CS   0x2e
#define PREFIX_SEGMENT_SS   0x36
#define PREFIX_SEGMENT_DS   0x3e
#define PREFIX_SEGMENT_ES   0x26
#define PREFIX_SEGMENT_FS   0x64
#define PREFIX_SEGMENT_GS   0x65
#define PREFIX_LOCK         0xf0
#define PREFIX_REPNZ        0xf2
#define PREFIX_REPX         0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67

#pragma pack(push,1)

typedef struct {
    uint8_t len;
    uint8_t p_rep;
    uint8_t p_lock;
    uint8_t p_seg;
    uint8_t p_66;
    uint8_t p_67;
    uint8_t opcode;
    uint8_t opcode2;
    uint8_t modrm;
    uint8_t modrm_mod;
    uint8_t modrm_reg;
    uint8_t modrm_rm;
    uint8_t sib;
    uint8_t sib_scale;
    uint8_t sib_index;
    uint8_t sib_base;
    union {
        uint8_t imm8;
        uint16_t imm16;
        uint32_t imm32;
    } imm;
    union {
        uint8_t disp8;
        uint16_t disp16;
        uint32_t disp32;
    } disp;
    uint32_t flags;
} hde32s;

#pragma pack(pop)

#ifdef __cplusplus
extern "C" {
#endif

/* __cdecl */
unsigned int hde32_disasm(const void *code, hde32s *hs);

#ifdef __cplusplus
}
#endif

#endif /* _HDE32_H_ */


================================================
FILE: SylantStrike/minhook/src/hde/hde64.c
================================================
/*
 * Hacker Disassembler Engine 64 C
 * Copyright (c) 2008-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 */

#if defined(_M_X64) || defined(__x86_64__)

#include "hde64.h"
#include "table64.h"

unsigned int hde64_disasm(const void *code, hde64s *hs)
{
    uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
    uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
    uint8_t op64 = 0;

    // Avoid using memset to reduce the footprint.
#ifndef _MSC_VER
    memset((LPBYTE)hs, 0, sizeof(hde64s));
#else
    __stosb((LPBYTE)hs, 0, sizeof(hde64s));
#endif

    for (x = 16; x; x--)
        switch (c = *p++) {
            case 0xf3:
                hs->p_rep = c;
                pref |= PRE_F3;
                break;
            case 0xf2:
                hs->p_rep = c;
                pref |= PRE_F2;
                break;
            case 0xf0:
                hs->p_lock = c;
                pref |= PRE_LOCK;
                break;
            case 0x26: case 0x2e: case 0x36:
            case 0x3e: case 0x64: case 0x65:
                hs->p_seg = c;
                pref |= PRE_SEG;
                break;
            case 0x66:
                hs->p_66 = c;
                pref |= PRE_66;
                break;
            case 0x67:
                hs->p_67 = c;
                pref |= PRE_67;
                break;
            default:
                goto pref_done;
        }
  pref_done:

    hs->flags = (uint32_t)pref << 23;

    if (!pref)
        pref |= PRE_NONE;

    if ((c & 0xf0) == 0x40) {
        hs->flags |= F_PREFIX_REX;
        if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
            op64++;
        hs->rex_r = (c & 7) >> 2;
        hs->rex_x = (c & 3) >> 1;
        hs->rex_b = c & 1;
        if (((c = *p++) & 0xf0) == 0x40) {
            opcode = c;
            goto error_opcode;
        }
    }

    if ((hs->opcode = c) == 0x0f) {
        hs->opcode2 = c = *p++;
        ht += DELTA_OPCODES;
    } else if (c >= 0xa0 && c <= 0xa3) {
        op64++;
        if (pref & PRE_67)
            pref |= PRE_66;
        else
            pref &= ~PRE_66;
    }

    opcode = c;
    cflags = ht[ht[opcode / 4] + (opcode % 4)];

    if (cflags == C_ERROR) {
      error_opcode:
        hs->flags |= F_ERROR | F_ERROR_OPCODE;
        cflags = 0;
        if ((opcode & -3) == 0x24)
            cflags++;
    }

    x = 0;
    if (cflags & C_GROUP) {
        uint16_t t;
        t = *(uint16_t *)(ht + (cflags & 0x7f));
        cflags = (uint8_t)t;
        x = (uint8_t)(t >> 8);
    }

    if (hs->opcode2) {
        ht = hde64_table + DELTA_PREFIXES;
        if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
            hs->flags |= F_ERROR | F_ERROR_OPCODE;
    }

    if (cflags & C_MODRM) {
        hs->flags |= F_MODRM;
        hs->modrm = c = *p++;
        hs->modrm_mod = m_mod = c >> 6;
        hs->modrm_rm = m_rm = c & 7;
        hs->modrm_reg = m_reg = (c & 0x3f) >> 3;

        if (x && ((x << m_reg) & 0x80))
            hs->flags |= F_ERROR | F_ERROR_OPCODE;

        if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
            uint8_t t = opcode - 0xd9;
            if (m_mod == 3) {
                ht = hde64_table + DELTA_FPU_MODRM + t*8;
                t = ht[m_reg] << m_rm;
            } else {
                ht = hde64_table + DELTA_FPU_REG;
                t = ht[t] << m_reg;
            }
            if (t & 0x80)
                hs->flags |= F_ERROR | F_ERROR_OPCODE;
        }

        if (pref & PRE_LOCK) {
            if (m_mod == 3) {
                hs->flags |= F_ERROR | F_ERROR_LOCK;
            } else {
                uint8_t *table_end, op = opcode;
                if (hs->opcode2) {
                    ht = hde64_table + DELTA_OP2_LOCK_OK;
                    table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
                } else {
                    ht = hde64_table + DELTA_OP_LOCK_OK;
                    table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
                    op &= -2;
                }
                for (; ht != table_end; ht++)
                    if (*ht++ == op) {
                        if (!((*ht << m_reg) & 0x80))
                            goto no_lock_error;
                        else
                            break;
                    }
                hs->flags |= F_ERROR | F_ERROR_LOCK;
              no_lock_error:
                ;
            }
        }

        if (hs->opcode2) {
            switch (opcode) {
                case 0x20: case 0x22:
                    m_mod = 3;
                    if (m_reg > 4 || m_reg == 1)
                        goto error_operand;
                    else
                        goto no_error_operand;
                case 0x21: case 0x23:
                    m_mod = 3;
                    if (m_reg == 4 || m_reg == 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
            }
        } else {
            switch (opcode) {
                case 0x8c:
                    if (m_reg > 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
                case 0x8e:
                    if (m_reg == 1 || m_reg > 5)
                        goto error_operand;
                    else
                        goto no_error_operand;
            }
        }

        if (m_mod == 3) {
            uint8_t *table_end;
            if (hs->opcode2) {
                ht = hde64_table + DELTA_OP2_ONLY_MEM;
                table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
            } else {
                ht = hde64_table + DELTA_OP_ONLY_MEM;
                table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
            }
            for (; ht != table_end; ht += 2)
                if (*ht++ == opcode) {
                    if (*ht++ & pref && !((*ht << m_reg) & 0x80))
                        goto error_operand;
                    else
                        break;
                }
            goto no_error_operand;
        } else if (hs->opcode2) {
            switch (opcode) {
                case 0x50: case 0xd7: case 0xf7:
                    if (pref & (PRE_NONE | PRE_66))
                        goto error_operand;
                    break;
                case 0xd6:
                    if (pref & (PRE_F2 | PRE_F3))
                        goto error_operand;
                    break;
                case 0xc5:
                    goto error_operand;
            }
            goto no_error_operand;
        } else
            goto no_error_operand;

      error_operand:
        hs->flags |= F_ERROR | F_ERROR_OPERAND;
      no_error_operand:

        c = *p++;
        if (m_reg <= 1) {
            if (opcode == 0xf6)
                cflags |= C_IMM8;
            else if (opcode == 0xf7)
                cflags |= C_IMM_P66;
        }

        switch (m_mod) {
            case 0:
                if (pref & PRE_67) {
                    if (m_rm == 6)
                        disp_size = 2;
                } else
                    if (m_rm == 5)
                        disp_size = 4;
                break;
            case 1:
                disp_size = 1;
                break;
            case 2:
                disp_size = 2;
                if (!(pref & PRE_67))
                    disp_size <<= 1;
        }

        if (m_mod != 3 && m_rm == 4) {
            hs->flags |= F_SIB;
            p++;
            hs->sib = c;
            hs->sib_scale = c >> 6;
            hs->sib_index = (c & 0x3f) >> 3;
            if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
                disp_size = 4;
        }

        p--;
        switch (disp_size) {
            case 1:
                hs->flags |= F_DISP8;
                hs->disp.disp8 = *p;
                break;
            case 2:
                hs->flags |= F_DISP16;
                hs->disp.disp16 = *(uint16_t *)p;
                break;
            case 4:
                hs->flags |= F_DISP32;
                hs->disp.disp32 = *(uint32_t *)p;
        }
        p += disp_size;
    } else if (pref & PRE_LOCK)
        hs->flags |= F_ERROR | F_ERROR_LOCK;

    if (cflags & C_IMM_P66) {
        if (cflags & C_REL32) {
            if (pref & PRE_66) {
                hs->flags |= F_IMM16 | F_RELATIVE;
                hs->imm.imm16 = *(uint16_t *)p;
                p += 2;
                goto disasm_done;
            }
            goto rel32_ok;
        }
        if (op64) {
            hs->flags |= F_IMM64;
            hs->imm.imm64 = *(uint64_t *)p;
            p += 8;
        } else if (!(pref & PRE_66)) {
            hs->flags |= F_IMM32;
            hs->imm.imm32 = *(uint32_t *)p;
            p += 4;
        } else
            goto imm16_ok;
    }


    if (cflags & C_IMM16) {
      imm16_ok:
        hs->flags |= F_IMM16;
        hs->imm.imm16 = *(uint16_t *)p;
        p += 2;
    }
    if (cflags & C_IMM8) {
        hs->flags |= F_IMM8;
        hs->imm.imm8 = *p++;
    }

    if (cflags & C_REL32) {
      rel32_ok:
        hs->flags |= F_IMM32 | F_RELATIVE;
        hs->imm.imm32 = *(uint32_t *)p;
        p += 4;
    } else if (cflags & C_REL8) {
        hs->flags |= F_IMM8 | F_RELATIVE;
        hs->imm.imm8 = *p++;
    }

  disasm_done:

    if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
        hs->flags |= F_ERROR | F_ERROR_LENGTH;
        hs->len = 15;
    }

    return (unsigned int)hs->len;
}

#endif // defined(_M_X64) || defined(__x86_64__)


================================================
FILE: SylantStrike/minhook/src/hde/hde64.h
================================================
/*
 * Hacker Disassembler Engine 64
 * Copyright (c) 2008-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 * hde64.h: C/C++ header file
 *
 */

#ifndef _HDE64_H_
#define _HDE64_H_

/* stdint.h - C99 standard header
 * http://en.wikipedia.org/wiki/stdint.h
 *
 * if your compiler doesn't contain "stdint.h" header (for
 * example, Microsoft Visual C++), you can download file:
 *   http://www.azillionmonkeys.com/qed/pstdint.h
 * and change next line to:
 *   #include "pstdint.h"
 */
#include "pstdint.h"

#define F_MODRM         0x00000001
#define F_SIB           0x00000002
#define F_IMM8          0x00000004
#define F_IMM16         0x00000008
#define F_IMM32         0x00000010
#define F_IMM64         0x00000020
#define F_DISP8         0x00000040
#define F_DISP16        0x00000080
#define F_DISP32        0x00000100
#define F_RELATIVE      0x00000200
#define F_ERROR         0x00001000
#define F_ERROR_OPCODE  0x00002000
#define F_ERROR_LENGTH  0x00004000
#define F_ERROR_LOCK    0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ  0x01000000
#define F_PREFIX_REPX   0x02000000
#define F_PREFIX_REP    0x03000000
#define F_PREFIX_66     0x04000000
#define F_PREFIX_67     0x08000000
#define F_PREFIX_LOCK   0x10000000
#define F_PREFIX_SEG    0x20000000
#define F_PREFIX_REX    0x40000000
#define F_PREFIX_ANY    0x7f000000

#define PREFIX_SEGMENT_CS   0x2e
#define PREFIX_SEGMENT_SS   0x36
#define PREFIX_SEGMENT_DS   0x3e
#define PREFIX_SEGMENT_ES   0x26
#define PREFIX_SEGMENT_FS   0x64
#define PREFIX_SEGMENT_GS   0x65
#define PREFIX_LOCK         0xf0
#define PREFIX_REPNZ        0xf2
#define PREFIX_REPX         0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67

#pragma pack(push,1)

typedef struct {
    uint8_t len;
    uint8_t p_rep;
    uint8_t p_lock;
    uint8_t p_seg;
    uint8_t p_66;
    uint8_t p_67;
    uint8_t rex;
    uint8_t rex_w;
    uint8_t rex_r;
    uint8_t rex_x;
    uint8_t rex_b;
    uint8_t opcode;
    uint8_t opcode2;
    uint8_t modrm;
    uint8_t modrm_mod;
    uint8_t modrm_reg;
    uint8_t modrm_rm;
    uint8_t sib;
    uint8_t sib_scale;
    uint8_t sib_index;
    uint8_t sib_base;
    union {
        uint8_t imm8;
        uint16_t imm16;
        uint32_t imm32;
        uint64_t imm64;
    } imm;
    union {
        uint8_t disp8;
        uint16_t disp16;
        uint32_t disp32;
    } disp;
    uint32_t flags;
} hde64s;

#pragma pack(pop)

#ifdef __cplusplus
extern "C" {
#endif

/* __cdecl */
unsigned int hde64_disasm(const void *code, hde64s *hs);

#ifdef __cplusplus
}
#endif

#endif /* _HDE64_H_ */


================================================
FILE: SylantStrike/minhook/src/hde/pstdint.h
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <windows.h>

// Integer types for HDE.
typedef INT8   int8_t;
typedef INT16  int16_t;
typedef INT32  int32_t;
typedef INT64  int64_t;
typedef UINT8  uint8_t;
typedef UINT16 uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;


================================================
FILE: SylantStrike/minhook/src/hde/table32.h
================================================
/*
 * Hacker Disassembler Engine 32 C
 * Copyright (c) 2008-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 */

#define C_NONE    0x00
#define C_MODRM   0x01
#define C_IMM8    0x02
#define C_IMM16   0x04
#define C_IMM_P66 0x10
#define C_REL8    0x20
#define C_REL32   0x40
#define C_GROUP   0x80
#define C_ERROR   0xff

#define PRE_ANY  0x00
#define PRE_NONE 0x01
#define PRE_F2   0x02
#define PRE_F3   0x04
#define PRE_66   0x08
#define PRE_67   0x10
#define PRE_LOCK 0x20
#define PRE_SEG  0x40
#define PRE_ALL  0xff

#define DELTA_OPCODES      0x4a
#define DELTA_FPU_REG      0xf1
#define DELTA_FPU_MODRM    0xf8
#define DELTA_PREFIXES     0x130
#define DELTA_OP_LOCK_OK   0x1a1
#define DELTA_OP2_LOCK_OK  0x1b9
#define DELTA_OP_ONLY_MEM  0x1cb
#define DELTA_OP2_ONLY_MEM 0x1da

unsigned char hde32_table[] = {
  0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
  0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
  0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
  0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
  0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
  0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
  0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
  0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
  0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
  0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
  0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
  0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
  0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
  0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
  0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
  0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
  0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
  0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
  0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
  0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
  0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
  0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
  0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
  0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
  0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
  0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
  0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
  0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
  0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
  0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
  0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
  0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
  0xe7,0x08,0x00,0xf0,0x02,0x00
};


================================================
FILE: SylantStrike/minhook/src/hde/table64.h
================================================
/*
 * Hacker Disassembler Engine 64 C
 * Copyright (c) 2008-2009, Vyacheslav Patkov.
 * All rights reserved.
 *
 */

#define C_NONE    0x00
#define C_MODRM   0x01
#define C_IMM8    0x02
#define C_IMM16   0x04
#define C_IMM_P66 0x10
#define C_REL8    0x20
#define C_REL32   0x40
#define C_GROUP   0x80
#define C_ERROR   0xff

#define PRE_ANY  0x00
#define PRE_NONE 0x01
#define PRE_F2   0x02
#define PRE_F3   0x04
#define PRE_66   0x08
#define PRE_67   0x10
#define PRE_LOCK 0x20
#define PRE_SEG  0x40
#define PRE_ALL  0xff

#define DELTA_OPCODES      0x4a
#define DELTA_FPU_REG      0xfd
#define DELTA_FPU_MODRM    0x104
#define DELTA_PREFIXES     0x13c
#define DELTA_OP_LOCK_OK   0x1ae
#define DELTA_OP2_LOCK_OK  0x1c6
#define DELTA_OP_ONLY_MEM  0x1d8
#define DELTA_OP2_ONLY_MEM 0x1e7

unsigned char hde64_table[] = {
  0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
  0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
  0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
  0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
  0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
  0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
  0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
  0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
  0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
  0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
  0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
  0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
  0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
  0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
  0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
  0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
  0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
  0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
  0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
  0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
  0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
  0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
  0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
  0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
  0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
  0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
  0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
  0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
  0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
  0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
  0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
  0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
  0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
  0x00,0xf0,0x02,0x00
};


================================================
FILE: SylantStrike/minhook/src/hook.c
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <windows.h>
#include <tlhelp32.h>
#include <limits.h>

#include "../include/MinHook.h"
#include "buffer.h"
#include "trampoline.h"

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

// Initial capacity of the HOOK_ENTRY buffer.
#define INITIAL_HOOK_CAPACITY   32

// Initial capacity of the thread IDs buffer.
#define INITIAL_THREAD_CAPACITY 128

// Special hook position values.
#define INVALID_HOOK_POS UINT_MAX
#define ALL_HOOKS_POS    UINT_MAX

// Freeze() action argument defines.
#define ACTION_DISABLE      0
#define ACTION_ENABLE       1
#define ACTION_APPLY_QUEUED 2

// Thread access rights for suspending/resuming threads.
#define THREAD_ACCESS \
    (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)

// Hook information.
typedef struct _HOOK_ENTRY
{
    LPVOID pTarget;             // Address of the target function.
    LPVOID pDetour;             // Address of the detour or relay function.
    LPVOID pTrampoline;         // Address of the trampoline function.
    UINT8  backup[8];           // Original prologue of the target function.

    UINT8  patchAbove  : 1;     // Uses the hot patch area.
    UINT8  isEnabled   : 1;     // Enabled.
    UINT8  queueEnable : 1;     // Queued for enabling/disabling when != isEnabled.

    UINT   nIP : 4;             // Count of the instruction boundaries.
    UINT8  oldIPs[8];           // Instruction boundaries of the target function.
    UINT8  newIPs[8];           // Instruction boundaries of the trampoline function.
} HOOK_ENTRY, *PHOOK_ENTRY;

// Suspended threads for Freeze()/Unfreeze().
typedef struct _FROZEN_THREADS
{
    LPDWORD pItems;         // Data heap
    UINT    capacity;       // Size of allocated data heap, items
    UINT    size;           // Actual number of data items
} FROZEN_THREADS, *PFROZEN_THREADS;

//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------

// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
volatile LONG g_isLocked = FALSE;

// Private heap handle. If not NULL, this library is initialized.
HANDLE g_hHeap = NULL;

// Hook entries.
struct
{
    PHOOK_ENTRY pItems;     // Data heap
    UINT        capacity;   // Size of allocated data heap, items
    UINT        size;       // Actual number of data items
} g_hooks;

//-------------------------------------------------------------------------
// Returns INVALID_HOOK_POS if not found.
static UINT FindHookEntry(LPVOID pTarget)
{
    UINT i;
    for (i = 0; i < g_hooks.size; ++i)
    {
        if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
            return i;
    }

    return INVALID_HOOK_POS;
}

//-------------------------------------------------------------------------
static PHOOK_ENTRY AddHookEntry()
{
    if (g_hooks.pItems == NULL)
    {
        g_hooks.capacity = INITIAL_HOOK_CAPACITY;
        g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
            g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
        if (g_hooks.pItems == NULL)
            return NULL;
    }
    else if (g_hooks.size >= g_hooks.capacity)
    {
        PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
            g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
        if (p == NULL)
            return NULL;

        g_hooks.capacity *= 2;
        g_hooks.pItems = p;
    }

    return &g_hooks.pItems[g_hooks.size++];
}

//-------------------------------------------------------------------------
static void DeleteHookEntry(UINT pos)
{
    if (pos < g_hooks.size - 1)
        g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];

    g_hooks.size--;

    if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
    {
        PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
            g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
        if (p == NULL)
            return;

        g_hooks.capacity /= 2;
        g_hooks.pItems = p;
    }
}

//-------------------------------------------------------------------------
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
    UINT i;

    if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
        return (DWORD_PTR)pHook->pTarget;

    for (i = 0; i < pHook->nIP; ++i)
    {
        if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
            return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
    }

#if defined(_M_X64) || defined(__x86_64__)
    // Check relay function.
    if (ip == (DWORD_PTR)pHook->pDetour)
        return (DWORD_PTR)pHook->pTarget;
#endif

    return 0;
}

//-------------------------------------------------------------------------
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
    UINT i;
    for (i = 0; i < pHook->nIP; ++i)
    {
        if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
            return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
    }

    return 0;
}

//-------------------------------------------------------------------------
static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
{
    // If the thread suspended in the overwritten area,
    // move IP to the proper address.

    CONTEXT c;
#if defined(_M_X64) || defined(__x86_64__)
    DWORD64 *pIP = &c.Rip;
#else
    DWORD   *pIP = &c.Eip;
#endif
    UINT count;

    c.ContextFlags = CONTEXT_CONTROL;
    if (!GetThreadContext(hThread, &c))
        return;

    if (pos == ALL_HOOKS_POS)
    {
        pos = 0;
        count = g_hooks.size;
    }
    else
    {
        count = pos + 1;
    }

    for (; pos < count; ++pos)
    {
        PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
        BOOL        enable;
        DWORD_PTR   ip;

        switch (action)
        {
        case ACTION_DISABLE:
            enable = FALSE;
            break;

        case ACTION_ENABLE:
            enable = TRUE;
            break;

        default: // ACTION_APPLY_QUEUED
            enable = pHook->queueEnable;
            break;
        }
        if (pHook->isEnabled == enable)
            continue;

        if (enable)
            ip = FindNewIP(pHook, *pIP);
        else
            ip = FindOldIP(pHook, *pIP);

        if (ip != 0)
        {
            *pIP = ip;
            SetThreadContext(hThread, &c);
        }
    }
}

//-------------------------------------------------------------------------
static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        THREADENTRY32 te;
        te.dwSize = sizeof(THREADENTRY32);
        if (Thread32First(hSnapshot, &te))
        {
            do
            {
                if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
                    && te.th32OwnerProcessID == GetCurrentProcessId()
                    && te.th32ThreadID != GetCurrentThreadId())
                {
                    if (pThreads->pItems == NULL)
                    {
                        pThreads->capacity = INITIAL_THREAD_CAPACITY;
                        pThreads->pItems
                            = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
                        if (pThreads->pItems == NULL)
                            break;
                    }
                    else if (pThreads->size >= pThreads->capacity)
                    {
                        LPDWORD p = (LPDWORD)HeapReAlloc(
                            g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
                        if (p == NULL)
                            break;

                        pThreads->capacity *= 2;
                        pThreads->pItems = p;
                    }
                    pThreads->pItems[pThreads->size++] = te.th32ThreadID;
                }

                te.dwSize = sizeof(THREADENTRY32);
            } while (Thread32Next(hSnapshot, &te));
        }
        CloseHandle(hSnapshot);
    }
}

//-------------------------------------------------------------------------
static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
{
    pThreads->pItems   = NULL;
    pThreads->capacity = 0;
    pThreads->size     = 0;
    EnumerateThreads(pThreads);

    if (pThreads->pItems != NULL)
    {
        UINT i;
        for (i = 0; i < pThreads->size; ++i)
        {
            HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
            if (hThread != NULL)
            {
                SuspendThread(hThread);
                ProcessThreadIPs(hThread, pos, action);
                CloseHandle(hThread);
            }
        }
    }
}

//-------------------------------------------------------------------------
static VOID Unfreeze(PFROZEN_THREADS pThreads)
{
    if (pThreads->pItems != NULL)
    {
        UINT i;
        for (i = 0; i < pThreads->size; ++i)
        {
            HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
            if (hThread != NULL)
            {
                ResumeThread(hThread);
                CloseHandle(hThread);
            }
        }

        HeapFree(g_hHeap, 0, pThreads->pItems);
    }
}

//-------------------------------------------------------------------------
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
{
    PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
    DWORD  oldProtect;
    SIZE_T patchSize    = sizeof(JMP_REL);
    LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;

    if (pHook->patchAbove)
    {
        pPatchTarget -= sizeof(JMP_REL);
        patchSize    += sizeof(JMP_REL_SHORT);
    }

    if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
        return MH_ERROR_MEMORY_PROTECT;

    if (enable)
    {
        PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
        pJmp->opcode = 0xE9;
        pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));

        if (pHook->patchAbove)
        {
            PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
            pShortJmp->opcode = 0xEB;
            pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
        }
    }
    else
    {
        if (pHook->patchAbove)
            memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
        else
            memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
    }

    VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);

    // Just-in-case measure.
    FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);

    pHook->isEnabled   = enable;
    pHook->queueEnable = enable;

    return MH_OK;
}

//-------------------------------------------------------------------------
static MH_STATUS EnableAllHooksLL(BOOL enable)
{
    MH_STATUS status = MH_OK;
    UINT i, first = INVALID_HOOK_POS;

    for (i = 0; i < g_hooks.size; ++i)
    {
        if (g_hooks.pItems[i].isEnabled != enable)
        {
            first = i;
            break;
        }
    }

    if (first != INVALID_HOOK_POS)
    {
        FROZEN_THREADS threads;
        Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);

        for (i = first; i < g_hooks.size; ++i)
        {
            if (g_hooks.pItems[i].isEnabled != enable)
            {
                status = EnableHookLL(i, enable);
                if (status != MH_OK)
                    break;
            }
        }

        Unfreeze(&threads);
    }

    return status;
}

//-------------------------------------------------------------------------
static VOID EnterSpinLock(VOID)
{
    SIZE_T spinCount = 0;

    // Wait until the flag is FALSE.
    while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
    {
        // No need to generate a memory barrier here, since InterlockedCompareExchange()
        // generates a full memory barrier itself.

        // Prevent the loop from being too busy.
        if (spinCount < 32)
            Sleep(0);
        else
            Sleep(1);

        spinCount++;
    }
}

//-------------------------------------------------------------------------
static VOID LeaveSpinLock(VOID)
{
    // No need to generate a memory barrier here, since InterlockedExchange()
    // generates a full memory barrier itself.

    InterlockedExchange(&g_isLocked, FALSE);
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Initialize(VOID)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap == NULL)
    {
        g_hHeap = HeapCreate(0, 0, 0);
        if (g_hHeap != NULL)
        {
            // Initialize the internal function buffer.
            InitializeBuffer();
        }
        else
        {
            status = MH_ERROR_MEMORY_ALLOC;
        }
    }
    else
    {
        status = MH_ERROR_ALREADY_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Uninitialize(VOID)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        status = EnableAllHooksLL(FALSE);
        if (status == MH_OK)
        {
            // Free the internal function buffer.

            // HeapFree is actually not required, but some tools detect a false
            // memory leak without HeapFree.

            UninitializeBuffer();

            HeapFree(g_hHeap, 0, g_hooks.pItems);
            HeapDestroy(g_hHeap);

            g_hHeap = NULL;

            g_hooks.pItems   = NULL;
            g_hooks.capacity = 0;
            g_hooks.size     = 0;
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
        {
            UINT pos = FindHookEntry(pTarget);
            if (pos == INVALID_HOOK_POS)
            {
                LPVOID pBuffer = AllocateBuffer(pTarget);
                if (pBuffer != NULL)
                {
                    TRAMPOLINE ct;

                    ct.pTarget     = pTarget;
                    ct.pDetour     = pDetour;
                    ct.pTrampoline = pBuffer;
                    if (CreateTrampolineFunction(&ct))
                    {
                        PHOOK_ENTRY pHook = AddHookEntry();
                        if (pHook != NULL)
                        {
                            pHook->pTarget     = ct.pTarget;
#if defined(_M_X64) || defined(__x86_64__)
                            pHook->pDetour     = ct.pRelay;
#else
                            pHook->pDetour     = ct.pDetour;
#endif
                            pHook->pTrampoline = ct.pTrampoline;
                            pHook->patchAbove  = ct.patchAbove;
                            pHook->isEnabled   = FALSE;
                            pHook->queueEnable = FALSE;
                            pHook->nIP         = ct.nIP;
                            memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
                            memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));

                            // Back up the target function.

                            if (ct.patchAbove)
                            {
                                memcpy(
                                    pHook->backup,
                                    (LPBYTE)pTarget - sizeof(JMP_REL),
                                    sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
                            }
                            else
                            {
                                memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
                            }

                            if (ppOriginal != NULL)
                                *ppOriginal = pHook->pTrampoline;
                        }
                        else
                        {
                            status = MH_ERROR_MEMORY_ALLOC;
                        }
                    }
                    else
                    {
                        status = MH_ERROR_UNSUPPORTED_FUNCTION;
                    }

                    if (status != MH_OK)
                    {
                        FreeBuffer(pBuffer);
                    }
                }
                else
                {
                    status = MH_ERROR_MEMORY_ALLOC;
                }
            }
            else
            {
                status = MH_ERROR_ALREADY_CREATED;
            }
        }
        else
        {
            status = MH_ERROR_NOT_EXECUTABLE;
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        UINT pos = FindHookEntry(pTarget);
        if (pos != INVALID_HOOK_POS)
        {
            if (g_hooks.pItems[pos].isEnabled)
            {
                FROZEN_THREADS threads;
                Freeze(&threads, pos, ACTION_DISABLE);

                status = EnableHookLL(pos, FALSE);

                Unfreeze(&threads);
            }

            if (status == MH_OK)
            {
                FreeBuffer(g_hooks.pItems[pos].pTrampoline);
                DeleteHookEntry(pos);
            }
        }
        else
        {
            status = MH_ERROR_NOT_CREATED;
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        if (pTarget == MH_ALL_HOOKS)
        {
            status = EnableAllHooksLL(enable);
        }
        else
        {
            FROZEN_THREADS threads;
            UINT pos = FindHookEntry(pTarget);
            if (pos != INVALID_HOOK_POS)
            {
                if (g_hooks.pItems[pos].isEnabled != enable)
                {
                    Freeze(&threads, pos, ACTION_ENABLE);

                    status = EnableHookLL(pos, enable);

                    Unfreeze(&threads);
                }
                else
                {
                    status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
                }
            }
            else
            {
                status = MH_ERROR_NOT_CREATED;
            }
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
{
    return EnableHook(pTarget, TRUE);
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
{
    return EnableHook(pTarget, FALSE);
}

//-------------------------------------------------------------------------
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
{
    MH_STATUS status = MH_OK;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        if (pTarget == MH_ALL_HOOKS)
        {
            UINT i;
            for (i = 0; i < g_hooks.size; ++i)
                g_hooks.pItems[i].queueEnable = queueEnable;
        }
        else
        {
            UINT pos = FindHookEntry(pTarget);
            if (pos != INVALID_HOOK_POS)
            {
                g_hooks.pItems[pos].queueEnable = queueEnable;
            }
            else
            {
                status = MH_ERROR_NOT_CREATED;
            }
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
{
    return QueueHook(pTarget, TRUE);
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
{
    return QueueHook(pTarget, FALSE);
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_ApplyQueued(VOID)
{
    MH_STATUS status = MH_OK;
    UINT i, first = INVALID_HOOK_POS;

    EnterSpinLock();

    if (g_hHeap != NULL)
    {
        for (i = 0; i < g_hooks.size; ++i)
        {
            if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
            {
                first = i;
                break;
            }
        }

        if (first != INVALID_HOOK_POS)
        {
            FROZEN_THREADS threads;
            Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);

            for (i = first; i < g_hooks.size; ++i)
            {
                PHOOK_ENTRY pHook = &g_hooks.pItems[i];
                if (pHook->isEnabled != pHook->queueEnable)
                {
                    status = EnableHookLL(i, pHook->queueEnable);
                    if (status != MH_OK)
                        break;
                }
            }

            Unfreeze(&threads);
        }
    }
    else
    {
        status = MH_ERROR_NOT_INITIALIZED;
    }

    LeaveSpinLock();

    return status;
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApiEx(
    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
    LPVOID *ppOriginal, LPVOID *ppTarget)
{
    HMODULE hModule;
    LPVOID  pTarget;

    hModule = GetModuleHandleW(pszModule);
    if (hModule == NULL)
        return MH_ERROR_MODULE_NOT_FOUND;

    pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
    if (pTarget == NULL)
        return MH_ERROR_FUNCTION_NOT_FOUND;

    if(ppTarget != NULL)
        *ppTarget = pTarget;

    return MH_CreateHook(pTarget, pDetour, ppOriginal);
}

//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApi(
    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
{
   return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
}

//-------------------------------------------------------------------------
const char * WINAPI MH_StatusToString(MH_STATUS status)
{
#define MH_ST2STR(x)    \
    case x:             \
        return #x;

    switch (status) {
        MH_ST2STR(MH_UNKNOWN)
        MH_ST2STR(MH_OK)
        MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
        MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
        MH_ST2STR(MH_ERROR_ALREADY_CREATED)
        MH_ST2STR(MH_ERROR_NOT_CREATED)
        MH_ST2STR(MH_ERROR_ENABLED)
        MH_ST2STR(MH_ERROR_DISABLED)
        MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
        MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
        MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
        MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
        MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
        MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
    }

#undef MH_ST2STR

    return "(unknown)";
}


================================================
FILE: SylantStrike/minhook/src/trampoline.c
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <windows.h>

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

#if defined(_M_X64) || defined(__x86_64__)
    #include "./hde/hde64.h"
    typedef hde64s HDE;
    #define HDE_DISASM(code, hs) hde64_disasm(code, hs)
#else
    #include "./hde/hde32.h"
    typedef hde32s HDE;
    #define HDE_DISASM(code, hs) hde32_disasm(code, hs)
#endif

#include "trampoline.h"
#include "buffer.h"

// Maximum size of a trampoline function.
#if defined(_M_X64) || defined(__x86_64__)
    #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
#else
    #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
#endif

//-------------------------------------------------------------------------
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
{
    UINT i;

    if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
        return FALSE;

    for (i = 1; i < size; ++i)
    {
        if (pInst[i] != pInst[0])
            return FALSE;
    }
    return TRUE;
}

//-------------------------------------------------------------------------
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
{
#if defined(_M_X64) || defined(__x86_64__)
    CALL_ABS call = {
        0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
        0xEB, 0x08,             // EB 08:         JMP +10
        0x0000000000000000ULL   // Absolute destination address
    };
    JMP_ABS jmp = {
        0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
        0x0000000000000000ULL   // Absolute destination address
    };
    JCC_ABS jcc = {
        0x70, 0x0E,             // 7* 0E:         J** +16
        0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
        0x0000000000000000ULL   // Absolute destination address
    };
#else
    CALL_REL call = {
        0xE8,                   // E8 xxxxxxxx: CALL +5+xxxxxxxx
        0x00000000              // Relative destination address
    };
    JMP_REL jmp = {
        0xE9,                   // E9 xxxxxxxx: JMP +5+xxxxxxxx
        0x00000000              // Relative destination address
    };
    JCC_REL jcc = {
        0x0F, 0x80,             // 0F8* xxxxxxxx: J** +6+xxxxxxxx
        0x00000000              // Relative destination address
    };
#endif

    UINT8     oldPos   = 0;
    UINT8     newPos   = 0;
    ULONG_PTR jmpDest  = 0;     // Destination address of an internal jump.
    BOOL      finished = FALSE; // Is the function completed?
#if defined(_M_X64) || defined(__x86_64__)
    UINT8     instBuf[16];
#endif

    ct->patchAbove = FALSE;
    ct->nIP        = 0;

    do
    {
        HDE       hs;
        UINT      copySize;
        LPVOID    pCopySrc;
        ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget     + oldPos;
        ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;

        copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
        if (hs.flags & F_ERROR)
            return FALSE;

        pCopySrc = (LPVOID)pOldInst;
        if (oldPos >= sizeof(JMP_REL))
        {
            // The trampoline function is long enough.
            // Complete the function with the jump to the target function.
#if defined(_M_X64) || defined(__x86_64__)
            jmp.address = pOldInst;
#else
            jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
#endif
            pCopySrc = &jmp;
            copySize = sizeof(jmp);

            finished = TRUE;
        }
#if defined(_M_X64) || defined(__x86_64__)
        else if ((hs.modrm & 0xC7) == 0x05)
        {
            // Instructions using RIP relative addressing. (ModR/M = 00???101B)

            // Modify the RIP relative address.
            PUINT32 pRelAddr;

            // Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
            memcpy(instBuf, (LPBYTE)pOldInst, copySize);
#else
            __movsb(instBuf, (LPBYTE)pOldInst, copySize);
#endif
            pCopySrc = instBuf;

            // Relative address is stored at (instruction length - immediate value length - 4).
            pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
            *pRelAddr
                = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));

            // Complete the function if JMP (FF /4).
            if (hs.opcode == 0xFF && hs.modrm_reg == 4)
                finished = TRUE;
        }
#endif
        else if (hs.opcode == 0xE8)
        {
            // Direct relative CALL
            ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
#if defined(_M_X64) || defined(__x86_64__)
            call.address = dest;
#else
            call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
#endif
            pCopySrc = &call;
            copySize = sizeof(call);
        }
        else if ((hs.opcode & 0xFD) == 0xE9)
        {
            // Direct relative JMP (EB or E9)
            ULONG_PTR dest = pOldInst + hs.len;

            if (hs.opcode == 0xEB) // isShort jmp
                dest += (INT8)hs.imm.imm8;
            else
                dest += (INT32)hs.imm.imm32;

            // Simply copy an internal jump.
            if ((ULONG_PTR)ct->pTarget <= dest
                && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
            {
                if (jmpDest < dest)
                    jmpDest = dest;
            }
            else
            {
#if defined(_M_X64) || defined(__x86_64__)
                jmp.address = dest;
#else
                jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
#endif
                pCopySrc = &jmp;
                copySize = sizeof(jmp);

                // Exit the function If it is not in the branch
                finished = (pOldInst >= jmpDest);
            }
        }
        else if ((hs.opcode & 0xF0) == 0x70
            || (hs.opcode & 0xFC) == 0xE0
            || (hs.opcode2 & 0xF0) == 0x80)
        {
            // Direct relative Jcc
            ULONG_PTR dest = pOldInst + hs.len;

            if ((hs.opcode & 0xF0) == 0x70      // Jcc
                || (hs.opcode & 0xFC) == 0xE0)  // LOOPNZ/LOOPZ/LOOP/JECXZ
                dest += (INT8)hs.imm.imm8;
            else
                dest += (INT32)hs.imm.imm32;

            // Simply copy an internal jump.
            if ((ULONG_PTR)ct->pTarget <= dest
                && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
            {
                if (jmpDest < dest)
                    jmpDest = dest;
            }
            else if ((hs.opcode & 0xFC) == 0xE0)
            {
                // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
                return FALSE;
            }
            else
            {
                UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
#if defined(_M_X64) || defined(__x86_64__)
                // Invert the condition in x64 mode to simplify the conditional jump logic.
                jcc.opcode  = 0x71 ^ cond;
                jcc.address = dest;
#else
                jcc.opcode1 = 0x80 | cond;
                jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
#endif
                pCopySrc = &jcc;
                copySize = sizeof(jcc);
            }
        }
        else if ((hs.opcode & 0xFE) == 0xC2)
        {
            // RET (C2 or C3)

            // Complete the function if not in a branch.
            finished = (pOldInst >= jmpDest);
        }

        // Can't alter the instruction length in a branch.
        if (pOldInst < jmpDest && copySize != hs.len)
            return FALSE;

        // Trampoline function is too large.
        if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
            return FALSE;

        // Trampoline function has too many instructions.
        if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
            return FALSE;

        ct->oldIPs[ct->nIP] = oldPos;
        ct->newIPs[ct->nIP] = newPos;
        ct->nIP++;

        // Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
        memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
#else
        __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
#endif
        newPos += copySize;
        oldPos += hs.len;
    }
    while (!finished);

    // Is there enough place for a long jump?
    if (oldPos < sizeof(JMP_REL)
        && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
    {
        // Is there enough place for a short jump?
        if (oldPos < sizeof(JMP_REL_SHORT)
            && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
        {
            return FALSE;
        }

        // Can we place the long jump above the function?
        if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
            return FALSE;

        if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
            return FALSE;

        ct->patchAbove = TRUE;
    }

#if defined(_M_X64) || defined(__x86_64__)
    // Create a relay function.
    jmp.address = (ULONG_PTR)ct->pDetour;

    ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
    memcpy(ct->pRelay, &jmp, sizeof(jmp));
#endif

    return TRUE;
}


================================================
FILE: SylantStrike/minhook/src/trampoline.h
================================================
/*
 *  MinHook - The Minimalistic API Hooking Library for x64/x86
 *  Copyright (C) 2009-2017 Tsuda Kageyu.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#pragma pack(push, 1)

// Structs for writing x86/x64 instructions.

// 8-bit relative jump.
typedef struct _JMP_REL_SHORT
{
    UINT8  opcode;      // EB xx: JMP +2+xx
    UINT8  operand;
} JMP_REL_SHORT, *PJMP_REL_SHORT;

// 32-bit direct relative jump/call.
typedef struct _JMP_REL
{
    UINT8  opcode;      // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
    UINT32 operand;     // Relative destination address
} JMP_REL, *PJMP_REL, CALL_REL;

// 64-bit indirect absolute jump.
typedef struct _JMP_ABS
{
    UINT8  opcode0;     // FF25 00000000: JMP [+6]
    UINT8  opcode1;
    UINT32 dummy;
    UINT64 address;     // Absolute destination address
} JMP_ABS, *PJMP_ABS;

// 64-bit indirect absolute call.
typedef struct _CALL_ABS
{
    UINT8  opcode0;     // FF15 00000002: CALL [+6]
    UINT8  opcode1;
    UINT32 dummy0;
    UINT8  dummy1;      // EB 08:         JMP +10
    UINT8  dummy2;
    UINT64 address;     // Absolute destination address
} CALL_ABS;

// 32-bit direct relative conditional jumps.
typedef struct _JCC_REL
{
    UINT8  opcode0;     // 0F8* xxxxxxxx: J** +6+xxxxxxxx
    UINT8  opcode1;
    UINT32 operand;     // Relative destination address
} JCC_REL;

// 64bit indirect absolute conditional jumps that x64 lacks.
typedef struct _JCC_ABS
{
    UINT8  opcode;      // 7* 0E:         J** +16
    UINT8  dummy0;
    UINT8  dummy1;      // FF25 00000000: JMP [+6]
    UINT8  dummy2;
    UINT32 dummy3;
    UINT64 address;     // Absolute destination address
} JCC_ABS;

#pragma pack(pop)

typedef struct _TRAMPOLINE
{
    LPVOID pTarget;         // [In] Address of the target function.
    LPVOID pDetour;         // [In] Address of the detour function.
    LPVOID pTrampoline;     // [In] Buffer address for the trampoline and relay function.

#if defined(_M_X64) || defined(__x86_64__)
    LPVOID pRelay;          // [Out] Address of the relay function.
#endif
    BOOL   patchAbove;      // [Out] Should use the hot patch area?
    UINT   nIP;             // [Out] Number of the instruction boundaries.
    UINT8  oldIPs[8];       // [Out] Instruction boundaries of the target function.
    UINT8  newIPs[8];       // [Out] Instruction boundaries of the trampoline function.
} TRAMPOLINE, *PTRAMPOLINE;

BOOL CreateTrampolineFunction(PTRAMPOLINE ct);


================================================
FILE: SylantStrike/pch.cpp
================================================
// pch.cpp: source file corresponding to the pre-compiled header

#include "pch.h"

// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.


================================================
FILE: SylantStrike/pch.h
================================================
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.

#ifndef PCH_H
#define PCH_H

// add headers that you want to pre-compile here
#include "framework.h"

#endif //PCH_H


================================================
FILE: SylantStrike.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SylantStrike", "SylantStrike\SylantStrike.vcxproj", "{1DDD15AA-D837-4143-A272-0E08F9ED6C40}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SylantStrikeInject", "SylantStrikeInject\SylantStrikeInject.csproj", "{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|Any CPU = Release|Any CPU
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|Any CPU.ActiveCfg = Debug|Win32
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.ActiveCfg = Debug|x64
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.Build.0 = Debug|x64
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.ActiveCfg = Debug|Win32
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.Build.0 = Debug|Win32
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|Any CPU.ActiveCfg = Release|Win32
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.ActiveCfg = Release|x64
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.Build.0 = Release|x64
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.ActiveCfg = Release|Win32
		{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.Build.0 = Release|Win32
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x64.ActiveCfg = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x64.Build.0 = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x86.ActiveCfg = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x86.Build.0 = Debug|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|Any CPU.Build.0 = Release|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x64.ActiveCfg = Release|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x64.Build.0 = Release|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x86.ActiveCfg = Release|Any CPU
		{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {C38993BA-BB45-4062-BD3E-AC155D4A3C84}
	EndGlobalSection
EndGlobal


================================================
FILE: SylantStrikeInject/App.config
================================================
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

================================================
FILE: SylantStrikeInject/BasicInject.cs
================================================
//Based on code from https://codingvision.net/security/c-inject-a-dll-into-a-process-w-createremotethread

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

public class BasicInject {
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
        uint dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateRemoteThread(IntPtr hProcess,
        IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

    // privileges
    const int PROCESS_CREATE_THREAD = 0x0002;
    const int PROCESS_QUERY_INFORMATION = 0x0400;
    const int PROCESS_VM_OPERATION = 0x0008;
    const int PROCESS_VM_WRITE = 0x0020;
    const int PROCESS_VM_READ = 0x0010;

    // used for memory allocation
    const uint MEM_COMMIT = 0x00001000;
    const uint MEM_RESERVE = 0x00002000;
    const uint PAGE_READWRITE = 4;

    public static int Inject(int pid, string dllName) {

        // geting the handle of the process - with required privileges
        IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, pid);

        // searching for the address of LoadLibraryA and storing it in a pointer
        IntPtr loadLibraryAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

        // alocating some memory on the target process - enough to store the name of the dll
        // and storing its address in a pointer
        IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

        // writing the name of the dll there
        UIntPtr bytesWritten;
        WriteProcessMemory(procHandle, allocMemAddress, Encoding.ASCII.GetBytes(dllName), (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten);

        // creating a thread that will call LoadLibraryA with allocMemAddress as argument
        CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);

        return 0;
    }
}

================================================
FILE: SylantStrikeInject/Options.cs
================================================
//
// Options.cs
//
// Authors:
//  Jonathan Pryor <jpryor@novell.com>, <Jonathan.Pryor@microsoft.com>
//  Federico Di Gregorio <fog@initd.org>
//  Rolf Bjarne Kvinge <rolf@xamarin.com>
//
// Copyright (C) 2008 Novell (http://www.novell.com)
// Copyright (C) 2009 Federico Di Gregorio.
// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// Compile With:
//   mcs -debug+ -r:System.Core Options.cs -o:Mono.Options.dll -t:library
//   mcs -debug+ -d:LINQ -r:System.Core Options.cs -o:Mono.Options.dll -t:library
//
// The LINQ version just changes the implementation of
// OptionSet.Parse(IEnumerable<string>), and confers no semantic changes.

//
// A Getopt::Long-inspired option parsing library for C#.
//
// Mono.Options.OptionSet is built upon a key/value table, where the
// key is a option format string and the value is a delegate that is 
// invoked when the format string is matched.
//
// Option format strings:
//  Regex-like BNF Grammar: 
//    name: .+
//    type: [=:]
//    sep: ( [^{}]+ | '{' .+ '}' )?
//    aliases: ( name type sep ) ( '|' name type sep )*
// 
// Each '|'-delimited name is an alias for the associated action.  If the
// format string ends in a '=', it has a required value.  If the format
// string ends in a ':', it has an optional value.  If neither '=' or ':'
// is present, no value is supported.  `=' or `:' need only be defined on one
// alias, but if they are provided on more than one they must be consistent.
//
// Each alias portion may also end with a "key/value separator", which is used
// to split option values if the option accepts > 1 value.  If not specified,
// it defaults to '=' and ':'.  If specified, it can be any character except
// '{' and '}' OR the *string* between '{' and '}'.  If no separator should be
// used (i.e. the separate values should be distinct arguments), then "{}"
// should be used as the separator.
//
// Options are extracted either from the current option by looking for
// the option name followed by an '=' or ':', or is taken from the
// following option IFF:
//  - The current option does not contain a '=' or a ':'
//  - The current option requires a value (i.e. not a Option type of ':')
//
// The `name' used in the option format string does NOT include any leading
// option indicator, such as '-', '--', or '/'.  All three of these are
// permitted/required on any named option.
//
// Option bundling is permitted so long as:
//   - '-' is used to start the option group
//   - all of the bundled options are a single character
//   - at most one of the bundled options accepts a value, and the value
//     provided starts from the next character to the end of the string.
//
// This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value'
// as '-Dname=value'.
//
// Option processing is disabled by specifying "--".  All options after "--"
// are returned by OptionSet.Parse() unchanged and unprocessed.
//
// Unprocessed options are returned from OptionSet.Parse().
//
// Examples:
//  int verbose = 0;
//  OptionSet p = new OptionSet ()
//    .Add ("v", v => ++verbose)
//    .Add ("name=|value=", v => Console.WriteLine (v));
//  p.Parse (new string[]{"-v", "--v", "/v", "-name=A", "/name", "B", "extra"});
//
// The above would parse the argument string array, and would invoke the
// lambda expression three times, setting `verbose' to 3 when complete.  
// It would also print out "A" and "B" to standard output.
// The returned array would contain the string "extra".
//
// C# 3.0 collection initializers are supported and encouraged:
//  var p = new OptionSet () {
//    { "h|?|help", v => ShowHelp () },
//  };
//
// System.ComponentModel.TypeConverter is also supported, allowing the use of
// custom data types in the callback type; TypeConverter.ConvertFromString()
// is used to convert the value option to an instance of the specified
// type:
//
//  var p = new OptionSet () {
//    { "foo=", (Foo f) => Console.WriteLine (f.ToString ()) },
//  };
//
// Random other tidbits:
//  - Boolean options (those w/o '=' or ':' in the option format string)
//    are explicitly enabled if they are followed with '+', and explicitly
//    disabled if they are followed with '-':
//      string a = null;
//      var p = new OptionSet () {
//        { "a", s => a = s },
//      };
//      p.Parse (new string[]{"-a"});   // sets v != null
//      p.Parse (new string[]{"-a+"});  // sets v != null
//      p.Parse (new string[]{"-a-"});  // sets v == null
//

//
// Mono.Options.CommandSet allows easily having separate commands and
// associated command options, allowing creation of a *suite* along the
// lines of **git**(1), **svn**(1), etc.
//
// CommandSet allows intermixing plain text strings for `--help` output,
// Option values -- as supported by OptionSet -- and Command instances,
// which have a name, optional help text, and an optional OptionSet.
//
//  var suite = new CommandSet ("suite-name") {
//    // Use strings and option values, as with OptionSet
//    "usage: suite-name COMMAND [OPTIONS]+",
//    { "v:", "verbosity", (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity+1 },
//    // Commands may also be specified
//    new Command ("command-name", "command help") {
//      Options = new OptionSet {/*...*/},
//      Run     = args => { /*...*/},
//    },
//    new MyCommandSubclass (),
//  };
//  return suite.Run (new string[]{...});
//
// CommandSet provides a `help` command, and forwards `help COMMAND`
// to the registered Command instance by invoking Command.Invoke()
// with `--help` as an option.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
#if PCL
using System.Reflection;
#else
using System.Runtime.Serialization;
using System.Security.Permissions;
#endif
using System.Text;
using System.Text.RegularExpressions;

#if LINQ
using System.Linq;
#endif

#if TEST
using NDesk.Options;
#endif

#if PCL
using MessageLocalizerConverter = System.Func<string, string>;
#else
using MessageLocalizerConverter = System.Converter<string, string>;
#endif

#if NDESK_OPTIONS
namespace NDesk.Options
#else
namespace Mono.Options
#endif
{
    static class StringCoda {

        public static IEnumerable<string> WrappedLines(string self, params int[] widths) {
            IEnumerable<int> w = widths;
            return WrappedLines(self, w);
        }

        public static IEnumerable<string> WrappedLines(string self, IEnumerable<int> widths) {
            if (widths == null)
                throw new ArgumentNullException("widths");
            return CreateWrappedLinesIterator(self, widths);
        }

        private static IEnumerable<string> CreateWrappedLinesIterator(string self, IEnumerable<int> widths) {
            if (string.IsNullOrEmpty(self)) {
                yield return string.Empty;
                yield break;
            }
            using (IEnumerator<int> ewidths = widths.GetEnumerator()) {
                bool? hw = null;
                int width = GetNextWidth(ewidths, int.MaxValue, ref hw);
                int start = 0, end;
                do {
                    end = GetLineEnd(start, width, self);
                    // endCorrection is 1 if the line end is '\n', and might be 2 if the line end is '\r\n'.
                    int endCorrection = 1;
                    if (end >= 2 && self.Substring(end - 2, 2).Equals("\r\n"))
                        endCorrection = 2;
                    char c = self[end - endCorrection];
                    if (char.IsWhiteSpace(c))
                        end -= endCorrection;
                    bool needContinuation = end != self.Length && !IsEolChar(c);
                    string continuation = "";
                    if (needContinuation) {
                        --end;
                        continuation = "-";
                    }
                    string line = self.Substring(start, end - start) + continuation;
                    yield return line;
                    start = end;
                    if (char.IsWhiteSpace(c))
                        start += endCorrection;
                    width = GetNextWidth(ewidths, width, ref hw);
                } while (start < self.Length);
            }
        }

        private static int GetNextWidth(IEnumerator<int> ewidths, int curWidth, ref bool? eValid) {
            if (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {
                curWidth = (eValid = ewidths.MoveNext()).Value ? ewidths.Current : curWidth;
                // '.' is any character, - is for a continuation
                const string minWidth = ".-";
                if (curWidth < minWidth.Length)
                    throw new ArgumentOutOfRangeException("widths",
                            string.Format("Element must be >= {0}, was {1}.", minWidth.Length, curWidth));
                return curWidth;
            }
            // no more elements, use the last element.
            return curWidth;
        }

        private static bool IsEolChar(char c) {
            return !char.IsLetterOrDigit(c);
        }

        private static int GetLineEnd(int start, int length, string description) {
            int end = System.Math.Min(start + length, description.Length);
            int sep = -1;
            for (int i = start; i < end; ++i) {
                if (i + 2 <= description.Length && description.Substring(i, 2).Equals("\r\n"))
                    return i + 2;
                if (description[i] == '\n')
                    return i + 1;
                if (IsEolChar(description[i]))
                    sep = i + 1;
            }
            if (sep == -1 || end == description.Length)
                return end;
            return sep;
        }
    }

    public class OptionValueCollection : IList, IList<string> {

        List<string> values = new List<string>();
        OptionContext c;

        internal OptionValueCollection(OptionContext c) {
            this.c = c;
        }

        #region ICollection
        void ICollection.CopyTo(Array array, int index) { (values as ICollection).CopyTo(array, index); }
        bool ICollection.IsSynchronized { get { return (values as ICollection).IsSynchronized; } }
        object ICollection.SyncRoot { get { return (values as ICollection).SyncRoot; } }
        #endregion

        #region ICollection<T>
        public void Add(string item) { values.Add(item); }
        public void Clear() { values.Clear(); }
        public bool Contains(string item) { return values.Contains(item); }
        public void CopyTo(string[] array, int arrayIndex) { values.CopyTo(array, arrayIndex); }
        public bool Remove(string item) { return values.Remove(item); }
        public int Count { get { return values.Count; } }
        public bool IsReadOnly { get { return false; } }
        #endregion

        #region IEnumerable
        IEnumerator IEnumerable.GetEnumerator() { return values.GetEnumerator(); }
        #endregion

        #region IEnumerable<T>
        public IEnumerator<string> GetEnumerator() { return values.GetEnumerator(); }
        #endregion

        #region IList
        int IList.Add(object value) { return (values as IList).Add(value); }
        bool IList.Contains(object value) { return (values as IList).Contains(value); }
        int IList.IndexOf(object value) { return (values as IList).IndexOf(value); }
        void IList.Insert(int index, object value) { (values as IList).Insert(index, value); }
        void IList.Remove(object value) { (values as IList).Remove(value); }
        void IList.RemoveAt(int index) { (values as IList).RemoveAt(index); }
        bool IList.IsFixedSize { get { return false; } }
        object IList.this[int index] { get { return this[index]; } set { (values as IList)[index] = value; } }
        #endregion

        #region IList<T>
        public int IndexOf(string item) { return values.IndexOf(item); }
        public void Insert(int index, string item) { values.Insert(index, item); }
        public void RemoveAt(int index) { values.RemoveAt(index); }

        private void AssertValid(int index) {
            if (c.Option == null)
                throw new InvalidOperationException("OptionContext.Option is null.");
            if (index >= c.Option.MaxValueCount)
                throw new ArgumentOutOfRangeException("index");
            if (c.Option.OptionValueType == OptionValueType.Required &&
                    index >= values.Count)
                throw new OptionException(string.Format(
                            c.OptionSet.MessageLocalizer("Missing required value for option '{0}'."), c.OptionName),
                        c.OptionName);
        }

        public string this[int index] {
            get {
                AssertValid(index);
                return index >= values.Count ? null : values[index];
            }
            set {
                values[index] = value;
            }
        }
        #endregion

        public List<string> ToList() {
            return new List<string>(values);
        }

        public string[] ToArray() {
            return values.ToArray();
        }

        public override string ToString() {
            return string.Join(", ", values.ToArray());
        }
    }

    public class OptionContext {
        private Option option;
        private string name;
        private int index;
        private OptionSet set;
        private OptionValueCollection c;

        public OptionContext(OptionSet set) {
            this.set = set;
            this.c = new OptionValueCollection(this);
        }

        public Option Option {
            get { return option; }
            set { option = value; }
        }

        public string OptionName {
            get { return name; }
            set { name = value; }
        }

        public int OptionIndex {
            get { return index; }
            set { index = value; }
        }

        public OptionSet OptionSet {
            get { return set; }
        }

        public OptionValueCollection OptionValues {
            get { return c; }
        }
    }

    public enum OptionValueType {
        None,
        Optional,
        Required,
    }

    public abstract class Option {
        string prototype, description;
        string[] names;
        OptionValueType type;
        int count;
        string[] separators;
        bool hidden;

        protected Option(string prototype, string description)
            : this(prototype, description, 1, false) {
        }

        protected Option(string prototype, string description, int maxValueCount)
            : this(prototype, description, maxValueCount, false) {
        }

        protected Option(string prototype, string description, int maxValueCount, bool hidden) {
            if (prototype == null)
                throw new ArgumentNullException("prototype");
            if (prototype.Length == 0)
                throw new ArgumentException("Cannot be the empty string.", "prototype");
            if (maxValueCount < 0)
                throw new ArgumentOutOfRangeException("maxValueCount");

            this.prototype = prototype;
            this.description = description;
            this.count = maxValueCount;
            this.names = (this is OptionSet.Category)
                // append GetHashCode() so that "duplicate" categories have distinct
                // names, e.g. adding multiple "" categories should be valid.
                ? new[] { prototype + this.GetHashCode() }
                : prototype.Split('|');

            if (this is OptionSet.Category || this is CommandOption)
                return;

            this.type = ParsePrototype();
            this.hidden = hidden;

            if (this.count == 0 && type != OptionValueType.None)
                throw new ArgumentException(
                        "Cannot provide maxValueCount of 0 for OptionValueType.Required or " +
                            "OptionValueType.Optional.",
                        "maxValueCount");
            if (this.type == OptionValueType.None && maxValueCount > 1)
                throw new ArgumentException(
                        string.Format("Cannot provide maxValueCount of {0} for OptionValueType.None.", maxValueCount),
                        "maxValueCount");
            if (Array.IndexOf(names, "<>") >= 0 &&
                    ((names.Length == 1 && this.type != OptionValueType.None) ||
                     (names.Length > 1 && this.MaxValueCount > 1)))
                throw new ArgumentException(
                        "The default option handler '<>' cannot require values.",
                        "prototype");
        }

        public string Prototype { get { return prototype; } }
        public string Description { get { return description; } }
        public OptionValueType OptionValueType { get { return type; } }
        public int MaxValueCount { get { return count; } }
        public bool Hidden { get { return hidden; } }

        public string[] GetNames() {
            return (string[])names.Clone();
        }

        public string[] GetValueSeparators() {
            if (separators == null)
                return new string[0];
            return (string[])separators.Clone();
        }

        protected static T Parse<T>(string value, OptionContext c) {
            Type tt = typeof(T);
#if PCL
			TypeInfo ti = tt.GetTypeInfo ();
#else
            Type ti = tt;
#endif
            bool nullable =
                ti.IsValueType &&
                ti.IsGenericType &&
                !ti.IsGenericTypeDefinition &&
                ti.GetGenericTypeDefinition() == typeof(Nullable<>);
#if PCL
			Type targetType = nullable ? tt.GenericTypeArguments [0] : tt;
#else
            Type targetType = nullable ? tt.GetGenericArguments()[0] : tt;
#endif
            T t = default(T);
            try {
                if (value != null) {
#if PCL
					if (targetType.GetTypeInfo ().IsEnum)
						t = (T) Enum.Parse (targetType, value, true);
					else
						t = (T) Convert.ChangeType (value, targetType);
#else
                    TypeConverter conv = TypeDescriptor.GetConverter(targetType);
                    t = (T)conv.ConvertFromString(value);
#endif
                }
            } catch (Exception e) {
                throw new OptionException(
                        string.Format(
                            c.OptionSet.MessageLocalizer("Could not convert string `{0}' to type {1} for option `{2}'."),
                            value, targetType.Name, c.OptionName),
                        c.OptionName, e);
            }
            return t;
        }

        internal string[] Names { get { return names; } }
        internal string[] ValueSeparators { get { return separators; } }

        static readonly char[] NameTerminator = new char[] { '=', ':' };

        private OptionValueType ParsePrototype() {
            char type = '\0';
            List<string> seps = new List<string>();
            for (int i = 0; i < names.Length; ++i) {
                string name = names[i];
                if (name.Length == 0)
                    throw new ArgumentException("Empty option names are not supported.", "prototype");

                int end = name.IndexOfAny(NameTerminator);
                if (end == -1)
                    continue;
                names[i] = name.Substring(0, end);
                if (type == '\0' || type == name[end])
                    type = name[end];
                else
                    throw new ArgumentException(
                            string.Format("Conflicting option types: '{0}' vs. '{1}'.", type, name[end]),
                            "prototype");
                AddSeparators(name, end, seps);
            }

            if (type == '\0')
                return OptionValueType.None;

            if (count <= 1 && seps.Count != 0)
                throw new ArgumentException(
                        string.Format("Cannot provide key/value separators for Options taking {0} value(s).", count),
                        "prototype");
            if (count > 1) {
                if (seps.Count == 0)
                    this.separators = new string[] { ":", "=" };
                else if (seps.Count == 1 && seps[0].Length == 0)
                    this.separators = null;
                else
                    this.separators = seps.ToArray();
            }

            return type == '=' ? OptionValueType.Required : OptionValueType.Optional;
        }

        private static void AddSeparators(string name, int end, ICollection<string> seps) {
            int start = -1;
            for (int i = end + 1; i < name.Length; ++i) {
                switch (name[i]) {
                    case '{':
                        if (start != -1)
                            throw new ArgumentException(
                                    string.Format("Ill-formed name/value separator found in \"{0}\".", name),
                                    "prototype");
                        start = i + 1;
                        break;
                    case '}':
                        if (start == -1)
                            throw new ArgumentException(
                                    string.Format("Ill-formed name/value separator found in \"{0}\".", name),
                                    "prototype");
                        seps.Add(name.Substring(start, i - start));
                        start = -1;
                        break;
                    default:
                        if (start == -1)
                            seps.Add(name[i].ToString());
                        break;
                }
            }
            if (start != -1)
                throw new ArgumentException(
                        string.Format("Ill-formed name/value separator found in \"{0}\".", name),
                        "prototype");
        }

        public void Invoke(OptionContext c) {
            OnParseComplete(c);
            c.OptionName = null;
            c.Option = null;
            c.OptionValues.Clear();
        }

        protected abstract void OnParseComplete(OptionContext c);

        internal void InvokeOnParseComplete(OptionContext c) {
            OnParseComplete(c);
        }

        public override string ToString() {
            return Prototype;
        }
    }

    public abstract class ArgumentSource {

        protected ArgumentSource() {
        }

        public abstract string[] GetNames();
        public abstract string Description { get; }
        public abstract bool GetArguments(string value, out IEnumerable<string> replacement);

#if !PCL || NETSTANDARD1_3
        public static IEnumerable<string> GetArgumentsFromFile(string file) {
            return GetArguments(File.OpenText(file), true);
        }
#endif

        public static IEnumerable<string> GetArguments(TextReader reader) {
            return GetArguments(reader, false);
        }

        // Cribbed from mcs/driver.cs:LoadArgs(string)
        static IEnumerable<string> GetArguments(TextReader reader, bool close) {
            try {
                StringBuilder arg = new StringBuilder();

                string line;
                while ((line = reader.ReadLine()) != null) {
                    int t = line.Length;

                    for (int i = 0; i < t; i++) {
                        char c = line[i];

                        if (c == '"' || c == '\'') {
                            char end = c;

                            for (i++; i < t; i++) {
                                c = line[i];

                                if (c == end)
                                    break;
                                arg.Append(c);
                            }
                        } else if (c == ' ') {
                            if (arg.Length > 0) {
                                yield return arg.ToString();
                                arg.Length = 0;
                            }
                        } else
                            arg.Append(c);
                    }
                    if (arg.Length > 0) {
                        yield return arg.ToString();
                        arg.Length = 0;
                    }
                }
            } finally {
                if (close)
                    reader.Dispose();
            }
        }
    }

#if !PCL || NETSTANDARD1_3
    internal class ResponseFileSource : ArgumentSource {

        public override string[] GetNames() {
            return new string[] { "@file" };
        }

        public override string Description {
            get { return "Read response file for more options."; }
        }

        public override bool GetArguments(string value, out IEnumerable<string> replacement) {
            if (string.IsNullOrEmpty(value) || !value.StartsWith("@")) {
                replacement = null;
                return false;
            }
            replacement = ArgumentSource.GetArgumentsFromFile(value.Substring(1));
            return true;
        }
    }
#endif

#if !PCL
    [Serializable]
#endif
    internal class OptionException : Exception {
        private string option;

        public OptionException() {
        }

        public OptionException(string message, string optionName)
            : base(message) {
            this.option = optionName;
        }

        public OptionException(string message, string optionName, Exception innerException)
            : base(message, innerException) {
            this.option = optionName;
        }

#if !PCL
        protected OptionException(SerializationInfo info, StreamingContext context)
            : base(info, context) {
            this.option = info.GetString("OptionName");
        }
#endif

        public string OptionName {
            get { return this.option; }
        }

#if !PCL
#pragma warning disable 618 // SecurityPermissionAttribute is obsolete
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
#pragma warning restore 618
        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("OptionName", option);
        }
#endif
    }

    public delegate void OptionAction<TKey, TValue>(TKey key, TValue value);

    public class OptionSet : KeyedCollection<string, Option> {
        public OptionSet()
            : this(null) {
        }

        public OptionSet(MessageLocalizerConverter localizer) {
            this.roSources = new ReadOnlyCollection<ArgumentSource>(sources);
            this.localizer = localizer;
            if (this.localizer == null) {
                this.localizer = delegate (string f) {
                    return f;
                };
            }
        }

        MessageLocalizerConverter localizer;

        public MessageLocalizerConverter MessageLocalizer {
            get { return localizer; }
            internal set { localizer = value; }
        }

        List<ArgumentSource> sources = new List<ArgumentSource>();
        ReadOnlyCollection<ArgumentSource> roSources;

        public ReadOnlyCollection<ArgumentSource> ArgumentSources {
            get { return roSources; }
        }


        protected override string GetKeyForItem(Option item) {
            if (item == null)
                throw new ArgumentNullException("option");
            if (item.Names != null && item.Names.Length > 0)
                return item.Names[0];
            // This should never happen, as it's invalid for Option to be
            // constructed w/o any names.
            throw new InvalidOperationException("Option has no names!");
        }

        [Obsolete("Use KeyedCollection.this[string]")]
        protected Option GetOptionForName(string option) {
            if (option == null)
                throw new ArgumentNullException("option");
            try {
                return base[option];
            } catch (KeyNotFoundException) {
                return null;
            }
        }

        protected override void InsertItem(int index, Option item) {
            base.InsertItem(index, item);
            AddImpl(item);
        }

        protected override void RemoveItem(int index) {
            Option p = Items[index];
            base.RemoveItem(index);
            // KeyedCollection.RemoveItem() handles the 0th item
            for (int i = 1; i < p.Names.Length; ++i) {
                Dictionary.Remove(p.Names[i]);
            }
        }

        protected override void SetItem(int index, Option item) {
            base.SetItem(index, item);
            AddImpl(item);
        }

        private void AddImpl(Option option) {
            if (option == null)
                throw new ArgumentNullException("option");
            List<string> added = new List<string>(option.Names.Length);
            try {
                // KeyedCollection.InsertItem/SetItem handle the 0th name.
                for (int i = 1; i < option.Names.Length; ++i) {
                    Dictionary.Add(option.Names[i], option);
                    added.Add(option.Names[i]);
                }
            } catch (Exception) {
                foreach (string name in added)
                    Dictionary.Remove(name);
                throw;
            }
        }

        public OptionSet Add(string header) {
            if (header == null)
                throw new ArgumentNullException("header");
            Add(new Category(header));
            return this;
        }

        internal sealed class Category : Option {

            // Prototype starts with '=' because this is an invalid prototype
            // (see Option.ParsePrototype(), and thus it'll prevent Category
            // instances from being accidentally used as normal options.
            public Category(string description)
                : base("=:Category:= " + description, description) {
            }

            protected override void OnParseComplete(OptionContext c) {
                throw new NotSupportedException("Category.OnParseComplete should not be invoked.");
            }
        }


        public new OptionSet Add(Option option) {
            base.Add(option);
            return this;
        }

        sealed class ActionOption : Option {
            Action<OptionValueCollection> action;

            public ActionOption(string prototype, string description, int count, Action<OptionValueCollection> action)
                : this(prototype, description, count, action, false) {
            }

            public ActionOption(string prototype, string description, int count, Action<OptionValueCollection> action, bool hidden)
                : base(prototype, description, count, hidden) {
                if (action == null)
                    throw new ArgumentNullException("action");
                this.action = action;
            }

            protected override void OnParseComplete(OptionContext c) {
                action(c.OptionValues);
            }
        }

        public OptionSet Add(string prototype, Action<string> action) {
            return Add(prototype, null, action);
        }

        public OptionSet Add(string prototype, string description, Action<string> action) {
            return Add(prototype, description, action, false);
        }

        public OptionSet Add(string prototype, string description, Action<string> action, bool hidden) {
            if (action == null)
                throw new ArgumentNullException("action");
            Option p = new ActionOption(prototype, description, 1,
                    delegate (OptionValueCollection v) { action(v[0]); }, hidden);
            base.Add(p);
            return this;
        }

        public OptionSet Add(string prototype, OptionAction<string, string> action) {
            return Add(prototype, null, action);
        }

        public OptionSet Add(string prototype, string description, OptionAction<string, string> action) {
            return Add(prototype, description, action, false);
        }

        public OptionSet Add(string prototype, string description, OptionAction<string, string> action, bool hidden) {
            if (action == null)
                throw new ArgumentNullException("action");
            Option p = new ActionOption(prototype, description, 2,
                    delegate (OptionValueCollection v) { action(v[0], v[1]); }, hidden);
            base.Add(p);
            return this;
        }

        sealed class ActionOption<T> : Option {
            Action<T> action;

            public ActionOption(string prototype, string description, Action<T> action)
                : base(prototype, description, 1) {
                if (action == null)
                    throw new ArgumentNullException("action");
                this.action = action;
            }

            protected override void OnParseComplete(OptionContext c) {
                action(Parse<T>(c.OptionValues[0], c));
            }
        }

        sealed class ActionOption<TKey, TValue> : Option {
            OptionAction<TKey, TValue> action;

            public ActionOption(string prototype, string description, OptionAction<TKey, TValue> action)
                : base(prototype, description, 2) {
                if (action == null)
                    throw new ArgumentNullException("action");
                this.action = action;
            }

            protected override void OnParseComplete(OptionContext c) {
                action(
                        Parse<TKey>(c.OptionValues[0], c),
                        Parse<TValue>(c.OptionValues[1], c));
            }
        }

        public OptionSet Add<T>(string prototype, Action<T> action) {
            return Add(prototype, null, action);
        }

        public OptionSet Add<T>(string prototype, string description, Action<T> action) {
            return Add(new ActionOption<T>(prototype, description, action));
        }

        public OptionSet Add<TKey, TValue>(string prototype, OptionAction<TKey, TValue> action) {
            return Add(prototype, null, action);
        }

        public OptionSet Add<TKey, TValue>(string prototype, string description, OptionAction<TKey, TValue> action) {
            return Add(new ActionOption<TKey, TValue>(prototype, description, action));
        }

        public OptionSet Add(ArgumentSource source) {
            if (source == null)
                throw new ArgumentNullException("source");
            sources.Add(source);
            return this;
        }

        protected virtual OptionContext CreateOptionContext() {
            return new OptionContext(this);
        }

        public List<string> Parse(IEnumerable<string> arguments) {
            if (arguments == null)
                throw new ArgumentNullException("arguments");
            OptionContext c = CreateOptionContext();
            c.OptionIndex = -1;
            bool process = true;
            List<string> unprocessed = new List<string>();
            Option def = Contains("<>") ? this["<>"] : null;
            ArgumentEnumerator ae = new ArgumentEnumerator(arguments);
            foreach (string argument in ae) {
                ++c.OptionIndex;
                if (argument == "--") {
                    process = false;
                    continue;
                }
                if (!process) {
                    Unprocessed(unprocessed, def, c, argument);
                    continue;
                }
                if (AddSource(ae, argument))
                    continue;
                if (!Parse(argument, c))
                    Unprocessed(unprocessed, def, c, argument);
            }
            if (c.Option != null)
                c.Option.Invoke(c);
            return unprocessed;
        }

        class ArgumentEnumerator : IEnumerable<string> {
            List<IEnumerator<string>> sources = new List<IEnumerator<string>>();

            public ArgumentEnumerator(IEnumerable<string> arguments) {
                sources.Add(arguments.GetEnumerator());
            }

            public void Add(IEnumerable<string> arguments) {
                sources.Add(arguments.GetEnumerator());
            }

            public IEnumerator<string> GetEnumerator() {
                do {
                    IEnumerator<string> c = sources[sources.Count - 1];
                    if (c.MoveNext())
                        yield return c.Current;
                    else {
                        c.Dispose();
                        sources.RemoveAt(sources.Count - 1);
                    }
                } while (sources.Count > 0);
            }

            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator();
            }
        }

        bool AddSource(ArgumentEnumerator ae, string argument) {
            foreach (ArgumentSource source in sources) {
                IEnumerable<string> replacement;
                if (!source.GetArguments(argument, out replacement))
                    continue;
                ae.Add(replacement);
                return true;
            }
            return false;
        }

        private static bool Unprocessed(ICollection<string> extra, Option def, OptionContext c, string argument) {
            if (def == null) {
                extra.Add(argument);
                return false;
            }
            c.OptionValues.Add(argument);
            c.Option = def;
            c.Option.Invoke(c);
            return false;
        }

        private readonly Regex ValueOption = new Regex(
            @"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$");

        protected bool GetOptionParts(string argument, out string flag, out string name, out string sep, out string value) {
            if (argument == null)
                throw new ArgumentNullException("argument");

            flag = name = sep = value = null;
            Match m = ValueOption.Match(argument);
            if (!m.Success) {
                return false;
            }
            flag = m.Groups["flag"].Value;
            name = m.Groups["name"].Value;
            if (m.Groups["sep"].Success && m.Groups["value"].Success) {
                sep = m.Groups["sep"].Value;
                value = m.Groups["value"].Value;
            }
            return true;
        }

        protected virtual bool Parse(string argument, OptionContext c) {
            if (c.Option != null) {
                ParseValue(argument, c);
                return true;
            }

            string f, n, s, v;
            if (!GetOptionParts(argument, out f, out n, out s, out v))
                return false;

            Option p;
            if (Contains(n)) {
                p = this[n];
                c.OptionName = f + n;
                c.Option = p;
                switch (p.OptionValueType) {
                    case OptionValueType.None:
                        c.OptionValues.Add(n);
                        c.Option.Invoke(c);
                        break;
                    case OptionValueType.Optional:
                    case OptionValueType.Required:
                        ParseValue(v, c);
                        break;
                }
                return true;
            }
            // no match; is it a bool option?
            if (ParseBool(argument, n, c))
                return true;
            // is it a bundled option?
            if (ParseBundledValue(f, string.Concat(n + s + v), c))
                return true;

            return false;
        }

        private void ParseValue(string option, OptionContext c) {
            if (option != null)
                foreach (string o in c.Option.ValueSeparators != null
                        ? option.Split(c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)
                        : new string[] { option }) {
                    c.OptionValues.Add(o);
                }
            if (c.OptionValues.Count == c.Option.MaxValueCount ||
                    c.Option.OptionValueType == OptionValueType.Optional)
                c.Option.Invoke(c);
            else if (c.OptionValues.Count > c.Option.MaxValueCount) {
                throw new OptionException(localizer(string.Format(
                                "Error: Found {0} option values when expecting {1}.",
                                c.OptionValues.Count, c.Option.MaxValueCount)),
                        c.OptionName);
            }
        }

        private bool ParseBool(string option, string n, OptionContext c) {
            Option p;
            string rn;
            if (n.Length >= 1 && (n[n.Length - 1] == '+' || n[n.Length - 1] == '-') &&
                    Contains((rn = n.Substring(0, n.Length - 1)))) {
                p = this[rn];
                string v = n[n.Length - 1] == '+' ? option : null;
                c.OptionName = option;
                c.Option = p;
                c.OptionValues.Add(v);
                p.Invoke(c);
                return true;
            }
            return false;
        }

        private bool ParseBundledValue(string f, string n, OptionContext c) {
            if (f != "-")
                return false;
            for (int i = 0; i < n.Length; ++i) {
                Option p;
                string opt = f + n[i].ToString();
                string rn = n[i].ToString();
                if (!Contains(rn)) {
                    if (i == 0)
                        return false;
                    throw new OptionException(string.Format(localizer(
                                    "Cannot use unregistered option '{0}' in bundle '{1}'."), rn, f + n), null);
                }
                p = this[rn];
                switch (p.OptionValueType) {
                    case OptionValueType.None:
                        Invoke(c, opt, n, p);
                        break;
                    case OptionValueType.Optional:
                    case OptionValueType.Required: {
                            string v = n.Substring(i + 1);
                            c.Option = p;
                            c.OptionName = opt;
                            ParseValue(v.Length != 0 ? v : null, c);
                            return true;
                        }
                    default:
                        throw new InvalidOperationException("Unknown OptionValueType: " + p.OptionValueType);
                }
            }
            return true;
        }

        private static void Invoke(OptionContext c, string name, string value, Option option) {
            c.OptionName = name;
            c.Option = option;
            c.OptionValues.Add(value);
            option.Invoke(c);
        }

        private const int OptionWidth = 29;
        private const int Description_FirstWidth = 80 - OptionWidth;
        private const int Description_RemWidth = 80 - OptionWidth - 2;

        static readonly string CommandHelpIndentStart = new string(' ', OptionWidth);
        static readonly string CommandHelpIndentRemaining = new string(' ', OptionWidth + 2);

        public void WriteOptionDescriptions(TextWriter o) {
            foreach (Option p in this) {
                int written = 0;

                if (p.Hidden)
                    continue;

                Category c = p as Category;
                if (c != null) {
                    WriteDescription(o, p.Description, "", 80, 80);
                    continue;
                }
                CommandOption co = p as CommandOption;
                if (co != null) {
                    WriteCommandDescription(o, co.Command, co.CommandName);
                    continue;
                }

                if (!WriteOptionPrototype(o, p, ref written))
                    continue;

                if (written < OptionWidth)
                    o.Write(new string(' ', OptionWidth - written));
                else {
                    o.WriteLine();
                    o.Write(new string(' ', OptionWidth));
                }

                WriteDescription(o, p.Description, new string(' ', OptionWidth + 2),
                        Description_FirstWidth, Description_RemWidth);
            }

            foreach (ArgumentSource s in sources) {
                string[] names = s.GetNames();
                if (names == null || names.Length == 0)
                    continue;

                int written = 0;

                Write(o, ref written, "  ");
                Write(o, ref written, names[0]);
                for (int i = 1; i < names.Length; ++i) {
                    Write(o, ref written, ", ");
                    Write(o, ref written, names[i]);
                }

                if (written < OptionWidth)
                    o.Write(new string(' ', OptionWidth - written));
                else {
                    o.WriteLine();
                    o.Write(new string(' ', OptionWidth));
                }

                WriteDescription(o, s.Description, new string(' ', OptionWidth + 2),
                        Description_FirstWidth, Description_RemWidth);
            }
        }

        internal void WriteCommandDescription(TextWriter o, Command c, string commandName) {
            var name = new string(' ', 8) + (commandName ?? c.Name);
            if (name.Length < OptionWidth - 1) {
                WriteDescription(o, name + new string(' ', OptionWidth - name.Length) + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);
            } else {
                WriteDescription(o, name, "", 80, 80);
                WriteDescription(o, CommandHelpIndentStart + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);
            }
        }

        void WriteDescription(TextWriter o, string value, string prefix, int firstWidth, int remWidth) {
            bool indent = false;
            foreach (string line in GetLines(localizer(GetDescription(value)), firstWidth, remWidth)) {
                if (indent)
                    o.Write(prefix);
                o.WriteLine(line);
                indent = true;
            }
        }

        bool WriteOptionPrototype(TextWriter o, Option p, ref int written) {
            string[] names = p.Names;

            int i = GetNextOptionIndex(names, 0);
            if (i == names.Length)
                return false;

            if (names[i].Length == 1) {
                Write(o, ref written, "  -");
                Write(o, ref written, names[0]);
            } else {
                Write(o, ref written, "      --");
                Write(o, ref written, names[0]);
            }

            for (i = GetNextOptionIndex(names, i + 1);
                    i < names.Length; i = GetNextOptionIndex(names, i + 1)) {
                Write(o, ref written, ", ");
                Write(o, ref written, names[i].Length == 1 ? "-" : "--");
                Write(o, ref written, names[i]);
            }

            if (p.OptionValueType == OptionValueType.Optional ||
                    p.OptionValueType == OptionValueType.Required) {
                if (p.OptionValueType == OptionValueType.Optional) {
                    Write(o, ref written, localizer("["));
                }
                Write(o, ref written, localizer("=" + GetArgumentName(0, p.MaxValueCount, p.Description)));
                string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0
                    ? p.ValueSeparators[0]
                    : " ";
                for (int c = 1; c < p.MaxValueCount; ++c) {
                    Write(o, ref written, localizer(sep + GetArgumentName(c, p.MaxValueCount, p.Description)));
                }
                if (p.OptionValueType == OptionValueType.Optional) {
                    Write(o, ref written, localizer("]"));
                }
            }
            return true;
        }

        static int GetNextOptionIndex(string[] names, int i) {
            while (i < names.Length && names[i] == "<>") {
                ++i;
            }
            return i;
        }

        static void Write(TextWriter o, ref int n, string s) {
            n += s.Length;
            o.Write(s);
        }

        static string GetArgumentName(int index, int maxIndex, string description) {
            var matches = Regex.Matches(description ?? "", @"(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))"); // ignore double braces 
            string argName = "";
            foreach (Match match in matches) {
                var parts = match.Value.Split(':');
                // for maxIndex=1 it can be {foo} or {0:foo}
                if (maxIndex == 1) {
                    argName = parts[parts.Length - 1];
                }
                // look for {i:foo} if maxIndex > 1
                if (maxIndex > 1 && parts.Length == 2 &&
                    parts[0] == index.ToString(CultureInfo.InvariantCulture)) {
                    argName = parts[1];
                }
            }

            if (string.IsNullOrEmpty(argName)) {
                argName = maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
            }
            return argName;
        }

        private static string GetDescription(string description) {
            if (description == null)
                return string.Empty;
            StringBuilder sb = new StringBuilder(description.Length);
            int start = -1;
            for (int i = 0; i < description.Length; ++i) {
                switch (description[i]) {
                    case '{':
                        if (i == start) {
                            sb.Append('{');
                            start = -1;
                        } else if (start < 0)
                            start = i + 1;
                        break;
                    case '}':
                        if (start < 0) {
                            if ((i + 1) == description.Length || description[i + 1] != '}')
                                throw new InvalidOperationException("Invalid option description: " + description);
                            ++i;
                            sb.Append("}");
                        } else {
                            sb.Append(description.Substring(start, i - start));
                            start = -1;
                        }
                        break;
                    case ':':
                        if (start < 0)
                            goto default;
                        start = i + 1;
                        break;
                    default:
                        if (start < 0)
                            sb.Append(description[i]);
                        break;
                }
            }
            return sb.ToString();
        }

        private static IEnumerable<string> GetLines(string description, int firstWidth, int remWidth) {
            return StringCoda.WrappedLines(description, firstWidth, remWidth);
        }
    }

    internal class Command {
        public string Name { get; }
        public string Help { get; }

        public OptionSet Options { get; set; }
        public Action<IEnumerable<string>> Run { get; set; }

        public CommandSet CommandSet { get; internal set; }

        public Command(string name, string help = null) {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException(nameof(name));

            Name = NormalizeCommandName(name);
            Help = help;
        }

        static string NormalizeCommandName(string name) {
            var value = new StringBuilder(name.Length);
            var space = false;
            for (int i = 0; i < name.Length; ++i) {
                if (!char.IsWhiteSpace(name, i)) {
                    space = false;
                    value.Append(name[i]);
                } else if (!space) {
                    space = true;
                    value.Append(' ');
                }
            }
            return value.ToString();
        }

        public virtual int Invoke(IEnumerable<string> arguments) {
            var rest = Options?.Parse(arguments) ?? arguments;
            Run?.Invoke(rest);
            return 0;
        }
    }

    class CommandOption : Option {
        public Command Command { get; }
        public string CommandName { get; }

        // Prototype starts with '=' because this is an invalid prototype
        // (see Option.ParsePrototype(), and thus it'll prevent Category
        // instances from being accidentally used as normal options.
        public CommandOption(Command command, string commandName = null, bool hidden = false)
            : base("=:Command:= " + (commandName ?? command?.Name), (commandName ?? command?.Name), maxValueCount: 0, hidden: hidden) {
            if (command == null)
                throw new ArgumentNullException(nameof(command));
            Command = command;
            CommandName = commandName ?? command.Name;
        }

        protected override void OnParseComplete(OptionContext c) {
            throw new NotSupportedException("CommandOption.OnParseComplete should not be invoked.");
        }
    }

    class HelpOption : Option {
        Option option;
        CommandSet commands;

        public HelpOption(CommandSet commands, Option d)
            : base(d.Prototype, d.Description, d.MaxValueCount, d.Hidden) {
            this.commands = commands;
            this.option = d;
        }

        protected override void OnParseComplete(OptionContext c) {
            commands.showHelp = true;

            option?.InvokeOnParseComplete(c);
        }
    }

    class CommandOptionSet : OptionSet {
        CommandSet commands;

        public CommandOptionSet(CommandSet commands, MessageLocalizerConverter localizer)
            : base(localizer) {
            this.commands = commands;
        }

        protected override void SetItem(int index, Option item) {
            if (ShouldWrapOption(item)) {
                base.SetItem(index, new HelpOption(commands, item));
                return;
            }
            base.SetItem(index, item);
        }

        bool ShouldWrapOption(Option item) {
            if (item == null)
                return false;
            var help = item as HelpOption;
            if (help != null)
                return false;
            foreach (var n in item.Names) {
                if (n == "help")
                    return true;
            }
            return false;
        }

        protected override void InsertItem(int index, Option item) {
            if (ShouldWrapOption(item)) {
                base.InsertItem(index, new HelpOption(commands, item));
                return;
            }
            base.InsertItem(index, item);
        }
    }

    internal class CommandSet : KeyedCollection<string, Command> {
        readonly string suite;

        OptionSet options;
        TextWriter outWriter;
        TextWriter errorWriter;

        internal List<CommandSet> NestedCommandSets;

        internal HelpCommand help;

        internal bool showHelp;

        internal OptionSet Options => options;

#if !PCL || NETSTANDARD1_3
        public CommandSet(string suite, MessageLocalizerConverter localizer = null)
            : this(suite, Console.Out, Console.Error, localizer) {
        }
#endif

        public CommandSet(string suite, TextWriter output, TextWriter error, MessageLocalizerConverter localizer = null) {
            if (suite == null)
                throw new ArgumentNullException(nameof(suite));
            if (output == null)
                throw new ArgumentNullException(nameof(output));
            if (error == null)
                throw new ArgumentNullException(nameof(error));

            this.suite = suite;
            options = new CommandOptionSet(this, localizer);
            outWriter = output;
            errorWriter = error;
        }

        public string Suite => suite;
        public TextWriter Out => outWriter;
        public TextWriter Error => errorWriter;
        public MessageLocalizerConverter MessageLocalizer => options.MessageLocalizer;

        protected override string GetKeyForItem(Command item) {
            return item?.Name;
        }

        public new CommandSet Add(Command value) {
            if (value == null)
                throw new ArgumentNullException(nameof(value));
            AddCommand(value);
            options.Add(new CommandOption(value));
            return this;
        }

        void AddCommand(Command value) {
            if (value.CommandSet != null && value.CommandSet != this) {
                throw new ArgumentException("Command instances can only be added to a single CommandSet.", nameof(value));
            }
            value.CommandSet = this;
            if (value.Options != null) {
                value.Options.MessageLocalizer = options.MessageLocalizer;
            }

            base.Add(value);

            help = help ?? value as HelpCommand;
        }

        public CommandSet Add(string header) {
            options.Add(header);
            return this;
        }

        public CommandSet Add(Option option) {
            options.Add(option);
            return this;
        }

        public CommandSet Add(string prototype, Action<string> action) {
            options.Add(prototype, action);
            return this;
        }

        public CommandSet Add(string prototype, string description, Action<string> action) {
            options.Add(prototype, description, action);
            return this;
        }

        public CommandSet Add(string prototype, string description, Action<string> action, bool hidden) {
            options.Add(prototype, description, action, hidden);
            return this;
        }

        public CommandSet Add(string prototype, OptionAction<string, string> action) {
            options.Add(prototype, action);
            return this;
        }

        public CommandSet Add(string prototype, string description, OptionAction<string, string> action) {
            options.Add(prototype, description, action);
            return this;
        }

        public CommandSet Add(string prototype, string description, OptionAction<string, string> action, bool hidden) {
            options.Add(prototype, description, action, hidden);
            return this;
        }

        public CommandSet Add<T>(string prototype, Action<T> action) {
            options.Add(prototype, null, action);
            return this;
        }

        public CommandSet Add<T>(string prototype, string description, Action<T> action) {
            options.Add(prototype, description, action);
            return this;
        }

        public CommandSet Add<TKey, TValue>(string prototype, OptionAction<TKey, TValue> action) {
            options.Add(prototype, action);
            return this;
        }

        public CommandSet Add<TKey, TValue>(string prototype, string description, OptionAction<TKey, TValue> action) {
            options.Add(prototype, description, action);
            return this;
        }

        public CommandSet Add(ArgumentSource source) {
            options.Add(source);
            return this;
        }

        public CommandSet Add(CommandSet nestedCommands) {
            if (nestedCommands == null)
                throw new ArgumentNullException(nameof(nestedCommands));

            if (NestedCommandSets == null) {
                NestedCommandSets = new List<CommandSet>();
            }

            if (!AlreadyAdded(nestedCommands)) {
                NestedCommandSets.Add(nestedCommands);
                foreach (var o in nestedCommands.options) {
                    if (o is CommandOption c) {
                        options.Add(new CommandOption(c.Command, $"{nestedCommands.Suite} {c.CommandName}"));
                    } else {
                        options.Add(o);
                    }
                }
            }

            nestedCommands.options = this.options;
            nestedCommands.outWriter = this.outWriter;
            nestedCommands.errorWriter = this.errorWriter;

            return this;
        }

        bool AlreadyAdded(CommandSet value) {
            if (value == this)
                return true;
            if (NestedCommandSets == null)
                return false;
            foreach (var nc in NestedCommandSets) {
                if (nc.AlreadyAdded(value))
                    return true;
            }
            return false;
        }

        public IEnumerable<string> GetCompletions(string prefix = null) {
            string rest;
            ExtractToken(ref prefix, out rest);

            foreach (var command in this) {
                if (command.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {
                    yield return command.Name;
                }
            }

            if (NestedCommandSets == null)
                yield break;

            foreach (var subset in NestedCommandSets) {
                if (subset.Suite.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {
                    foreach (var c in subset.GetCompletions(rest)) {
                        yield return $"{subset.Suite} {c}";
                    }
                }
            }
        }

        static void ExtractToken(ref string input, out string rest) {
            rest = "";
            input = input ?? "";

            int top = input.Length;
            for (int i = 0; i < top; i++) {
                if (char.IsWhiteSpace(input[i]))
                    continue;

                for (int j = i; j < top; j++) {
                    if (char.IsWhiteSpace(input[j])) {
                        rest = input.Substring(j).Trim();
                        input = input.Substring(i, j).Trim();
                        return;
                    }
                }
                rest = "";
                if (i != 0)
                    input = input.Substring(i).Trim();
                return;
            }
        }

        public int Run(IEnumerable<string> arguments) {
            if (arguments == null)
                throw new ArgumentNullException(nameof(arguments));

            this.showHelp = false;
            if (help == null) {
                help = new HelpCommand();
                AddCommand(help);
            }
            Action<string> setHelp = v => showHelp = v != null;
            if (!options.Contains("help")) {
                options.Add("help", "", setHelp, hidden: true);
            }
            if (!options.Contains("?")) {
                options.Add("?", "", setHelp, hidden: true);
            }
            var extra = options.Parse(arguments);
            if (extra.Count == 0) {
                if (showHelp) {
                    return help.Invoke(extra);
                }
                Out.WriteLine(options.MessageLocalizer($"Use `{Suite} help` for usage."));
                return 1;
            }
            var command = GetCommand(extra);
            if (command == null) {
                help.WriteUnknownCommand(extra[0]);
                return 1;
            }
            if (showHelp) {
                if (command.Options?.Contains("help") ?? true) {
                    extra.Add("--help");
                    return command.Invoke(extra);
                }
                command.Options.WriteOptionDescriptions(Out);
                return 0;
            }
            return command.Invoke(extra);
        }

        internal Command GetCommand(List<string> extra) {
            return TryGetLocalCommand(extra) ?? TryGetNestedCommand(extra);
        }

        Command TryGetLocalCommand(List<string> extra) {
            var name = extra[0];
            if (Contains(name)) {
                extra.RemoveAt(0);
                return this[name];
            }
            for (int i = 1; i < extra.Count; ++i) {
                name = name + " " + extra[i];
                if (!Contains(name))
                    continue;
                extra.RemoveRange(0, i + 1);
                return this[name];
            }
            return null;
        }

        Command TryGetNestedCommand(List<string> extra) {
            if (NestedCommandSets == null)
                return null;

            var nestedCommands = NestedCommandSets.Find(c => c.Suite == extra[0]);
            if (nestedCommands == null)
                return null;

            var extraCopy = new List<string>(extra);
            extraCopy.RemoveAt(0);
            if (extraCopy.Count == 0)
                return null;

            var command = nestedCommands.GetCommand(extraCopy);
            if (command != null) {
                extra.Clear();
                extra.AddRange(extraCopy);
                return command;
            }
            return null;
        }
    }

    internal class HelpCommand : Command {
        public HelpCommand()
            : base("help", help: "Show this message and exit") {
        }

        public override int Invoke(IEnumerable<string> arguments) {
            var extra = new List<string>(arguments ?? new string[0]);
            var _ = CommandSet.Options.MessageLocalizer;
            if (extra.Count == 0) {
                CommandSet.Options.WriteOptionDescriptions(CommandSet.Out);
                return 0;
            }
            var command = CommandSet.GetCommand(extra);
            if (command == this || extra.Contains("--help")) {
                CommandSet.Out.WriteLine(_($"Usage: {CommandSet.Suite} COMMAND [OPTIONS]"));
                CommandSet.Out.WriteLine(_($"Use `{CommandSet.Suite} help COMMAND` for help on a specific command."));
                CommandSet.Out.WriteLine();
                CommandSet.Out.WriteLine(_($"Available commands:"));
                CommandSet.Out.WriteLine();
                var commands = GetCommands();
                commands.Sort((x, y) => string.Compare(x.Key, y.Key, StringComparison.OrdinalIgnoreCase));
                foreach (var c in commands) {
                    if (c.Key == "help") {
                        continue;
                    }
                    CommandSet.Options.WriteCommandDescription(CommandSet.Out, c.Value, c.Key);
                }
                CommandSet.Options.WriteCommandDescription(CommandSet.Out, CommandSet.help, "help");
                return 0;
            }
            if (command == null) {
                WriteUnknownCommand(extra[0]);
                return 1;
            }
            if (command.Options != null) {
                command.Options.WriteOptionDescriptions(CommandSet.Out);
                return 0;
            }
            return command.Invoke(new[] { "--help" });
        }

        List<KeyValuePair<string, Command>> GetCommands() {
            var commands = new List<KeyValuePair<string, Command>>();

            foreach (var c in CommandSet) {
                commands.Add(new KeyValuePair<string, Command>(c.Name, c));
            }

            if (CommandSet.NestedCommandSets == null)
                return commands;

            foreach (var nc in CommandSet.NestedCommandSets) {
                AddNestedCommands(commands, "", nc);
            }

            return commands;
        }

        void AddNestedCommands(List<KeyValuePair<string, Command>> commands, string outer, CommandSet value) {
            foreach (var v in value) {
                commands.Add(new KeyValuePair<string, Command>($"{outer}{value.Suite} {v.Name}", v));
            }
            if (value.NestedCommandSets == null)
                return;
            foreach (var nc in value.NestedCommandSets) {
                AddNestedCommands(commands, $"{outer}{value.Suite} ", nc);
            }
        }

        internal void WriteUnknownCommand(string unknownCommand) {
            CommandSet.Error.WriteLine(CommandSet.Options.MessageLocalizer($"{CommandSet.Suite}: Unknown command: {unknownCommand}"));
            CommandSet.Error.WriteLine(CommandSet.Options.MessageLocalizer($"{CommandSet.Suite}: Use `{CommandSet.Suite} help` for usage."));
        }
    }
}


================================================
FILE: SylantStrikeInject/Program.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
using Mono.Options;

namespace SylantStrikeInject {

    class Program
    {
        private static List<string> processList = new List<string>();
        pr
Download .txt
gitextract_uwm5figu/

├── .gitattributes
├── .gitignore
├── README.md
├── SylantStrike/
│   ├── SylantStrike.cpp
│   ├── SylantStrike.h
│   ├── SylantStrike.vcxproj
│   ├── SylantStrike.vcxproj.filters
│   ├── cpp.hint
│   ├── dllmain.cpp
│   ├── framework.h
│   ├── minhook/
│   │   ├── include/
│   │   │   └── MinHook.h
│   │   └── src/
│   │       ├── buffer.c
│   │       ├── buffer.h
│   │       ├── hde/
│   │       │   ├── hde32.c
│   │       │   ├── hde32.h
│   │       │   ├── hde64.c
│   │       │   ├── hde64.h
│   │       │   ├── pstdint.h
│   │       │   ├── table32.h
│   │       │   └── table64.h
│   │       ├── hook.c
│   │       ├── trampoline.c
│   │       └── trampoline.h
│   ├── pch.cpp
│   └── pch.h
├── SylantStrike.sln
└── SylantStrikeInject/
    ├── App.config
    ├── BasicInject.cs
    ├── Options.cs
    ├── Program.cs
    ├── Properties/
    │   └── AssemblyInfo.cs
    └── SylantStrikeInject.csproj
Download .txt
SYMBOL INDEX (250 symbols across 15 files)

FILE: SylantStrike/SylantStrike.cpp
  function DWORD (line 11) | DWORD NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID...

FILE: SylantStrike/dllmain.cpp
  function DWORD (line 7) | DWORD WINAPI InitHooksThread(LPVOID param) {
  function BOOL (line 26) | BOOL APIENTRY DllMain( HMODULE hModule,

FILE: SylantStrike/minhook/include/MinHook.h
  type MH_STATUS (line 38) | typedef enum MH_STATUS

FILE: SylantStrike/minhook/src/buffer.c
  type MEMORY_SLOT (line 43) | typedef struct _MEMORY_SLOT
  type MEMORY_BLOCK (line 53) | typedef struct _MEMORY_BLOCK
  function VOID (line 68) | VOID InitializeBuffer(VOID)
  function VOID (line 74) | VOID UninitializeBuffer(VOID)
  function LPVOID (line 89) | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD...
  function LPVOID (line 120) | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD...
  function PMEMORY_BLOCK (line 151) | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
  function LPVOID (line 247) | LPVOID AllocateBuffer(LPVOID pOrigin)
  function VOID (line 266) | VOID FreeBuffer(LPVOID pBuffer)
  function BOOL (line 306) | BOOL IsExecutableAddress(LPVOID pAddress)

FILE: SylantStrike/minhook/src/hde/hde32.c
  function hde32_disasm (line 13) | unsigned int hde32_disasm(const void *code, hde32s *hs)

FILE: SylantStrike/minhook/src/hde/hde32.h
  type hde32s (line 62) | typedef struct {

FILE: SylantStrike/minhook/src/hde/hde64.c
  function hde64_disasm (line 13) | unsigned int hde64_disasm(const void *code, hde64s *hs)

FILE: SylantStrike/minhook/src/hde/hde64.h
  type hde64s (line 63) | typedef struct {

FILE: SylantStrike/minhook/src/hde/pstdint.h
  type INT8 (line 32) | typedef INT8   int8_t;
  type INT16 (line 33) | typedef INT16  int16_t;
  type INT32 (line 34) | typedef INT32  int32_t;
  type INT64 (line 35) | typedef INT64  int64_t;
  type UINT8 (line 36) | typedef UINT8  uint8_t;
  type UINT16 (line 37) | typedef UINT16 uint16_t;
  type UINT32 (line 38) | typedef UINT32 uint32_t;
  type UINT64 (line 39) | typedef UINT64 uint64_t;

FILE: SylantStrike/minhook/src/hook.c
  type HOOK_ENTRY (line 61) | typedef struct _HOOK_ENTRY
  type FROZEN_THREADS (line 78) | typedef struct _FROZEN_THREADS
  function UINT (line 105) | static UINT FindHookEntry(LPVOID pTarget)
  function PHOOK_ENTRY (line 118) | static PHOOK_ENTRY AddHookEntry()
  function DeleteHookEntry (line 143) | static void DeleteHookEntry(UINT pos)
  function DWORD_PTR (line 163) | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
  function DWORD_PTR (line 186) | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
  function ProcessThreadIPs (line 199) | static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
  function VOID (line 263) | static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
  function VOID (line 307) | static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
  function VOID (line 331) | static VOID Unfreeze(PFROZEN_THREADS pThreads)
  function MH_STATUS (line 351) | static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
  function MH_STATUS (line 400) | static MH_STATUS EnableAllHooksLL(BOOL enable)
  function VOID (line 436) | static VOID EnterSpinLock(VOID)
  function VOID (line 457) | static VOID LeaveSpinLock(VOID)
  function MH_STATUS (line 466) | MH_STATUS WINAPI MH_Initialize(VOID)
  function MH_STATUS (line 496) | MH_STATUS WINAPI MH_Uninitialize(VOID)
  function MH_STATUS (line 535) | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *p...
  function MH_STATUS (line 633) | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
  function MH_STATUS (line 676) | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
  function MH_STATUS (line 724) | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
  function MH_STATUS (line 730) | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
  function MH_STATUS (line 736) | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
  function MH_STATUS (line 774) | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
  function MH_STATUS (line 780) | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
  function MH_STATUS (line 786) | MH_STATUS WINAPI MH_ApplyQueued(VOID)
  function MH_STATUS (line 834) | MH_STATUS WINAPI MH_CreateHookApiEx(
  function MH_STATUS (line 856) | MH_STATUS WINAPI MH_CreateHookApi(

FILE: SylantStrike/minhook/src/trampoline.c
  type hde64s (line 37) | typedef hde64s HDE;
  type hde32s (line 41) | typedef hde32s HDE;
  function BOOL (line 56) | static BOOL IsCodePadding(LPBYTE pInst, UINT size)
  function BOOL (line 72) | BOOL CreateTrampolineFunction(PTRAMPOLINE ct)

FILE: SylantStrike/minhook/src/trampoline.h
  type JMP_REL_SHORT (line 36) | typedef struct _JMP_REL_SHORT
  type JMP_REL (line 43) | typedef struct _JMP_REL
  type JMP_ABS (line 50) | typedef struct _JMP_ABS
  type CALL_ABS (line 59) | typedef struct _CALL_ABS
  type JCC_REL (line 70) | typedef struct _JCC_REL
  type JCC_ABS (line 78) | typedef struct _JCC_ABS
  type TRAMPOLINE (line 90) | typedef struct _TRAMPOLINE

FILE: SylantStrikeInject/BasicInject.cs
  class BasicInject (line 8) | public class BasicInject {
    method OpenProcess (line 9) | [DllImport("kernel32.dll")]
    method GetModuleHandle (line 12) | [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    method GetProcAddress (line 15) | [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, S...
    method VirtualAllocEx (line 18) | [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    method WriteProcessMemory (line 22) | [DllImport("kernel32.dll", SetLastError = true)]
    method CreateRemoteThread (line 25) | [DllImport("kernel32.dll")]
    method Inject (line 41) | public static int Inject(int pid, string dllName) {

FILE: SylantStrikeInject/Options.cs
  class StringCoda (line 194) | static class StringCoda {
    method WrappedLines (line 196) | public static IEnumerable<string> WrappedLines(string self, params int...
    method WrappedLines (line 201) | public static IEnumerable<string> WrappedLines(string self, IEnumerabl...
    method CreateWrappedLinesIterator (line 207) | private static IEnumerable<string> CreateWrappedLinesIterator(string s...
    method GetNextWidth (line 241) | private static int GetNextWidth(IEnumerator<int> ewidths, int curWidth...
    method IsEolChar (line 255) | private static bool IsEolChar(char c) {
    method GetLineEnd (line 259) | private static int GetLineEnd(int start, int length, string descriptio...
  class OptionValueCollection (line 276) | public class OptionValueCollection : IList, IList<string> {
    method OptionValueCollection (line 281) | internal OptionValueCollection(OptionContext c) {
    method CopyTo (line 286) | void ICollection.CopyTo(Array array, int index) { (values as ICollecti...
    method Add (line 292) | public void Add(string item) { values.Add(item); }
    method Clear (line 293) | public void Clear() { values.Clear(); }
    method Contains (line 294) | public bool Contains(string item) { return values.Contains(item); }
    method CopyTo (line 295) | public void CopyTo(string[] array, int arrayIndex) { values.CopyTo(arr...
    method Remove (line 296) | public bool Remove(string item) { return values.Remove(item); }
    method GetEnumerator (line 302) | IEnumerator IEnumerable.GetEnumerator() { return values.GetEnumerator(...
    method GetEnumerator (line 306) | public IEnumerator<string> GetEnumerator() { return values.GetEnumerat...
    method Add (line 310) | int IList.Add(object value) { return (values as IList).Add(value); }
    method Contains (line 311) | bool IList.Contains(object value) { return (values as IList).Contains(...
    method IndexOf (line 312) | int IList.IndexOf(object value) { return (values as IList).IndexOf(val...
    method Insert (line 313) | void IList.Insert(int index, object value) { (values as IList).Insert(...
    method Remove (line 314) | void IList.Remove(object value) { (values as IList).Remove(value); }
    method RemoveAt (line 315) | void IList.RemoveAt(int index) { (values as IList).RemoveAt(index); }
    method IndexOf (line 321) | public int IndexOf(string item) { return values.IndexOf(item); }
    method Insert (line 322) | public void Insert(int index, string item) { values.Insert(index, item...
    method RemoveAt (line 323) | public void RemoveAt(int index) { values.RemoveAt(index); }
    method AssertValid (line 325) | private void AssertValid(int index) {
    method ToList (line 348) | public List<string> ToList() {
    method ToArray (line 352) | public string[] ToArray() {
    method ToString (line 356) | public override string ToString() {
  class OptionContext (line 361) | public class OptionContext {
    method OptionContext (line 368) | public OptionContext(OptionSet set) {
  type OptionValueType (line 397) | public enum OptionValueType {
  class Option (line 403) | public abstract class Option {
    method Option (line 411) | protected Option(string prototype, string description)
    method Option (line 415) | protected Option(string prototype, string description, int maxValueCount)
    method Option (line 419) | protected Option(string prototype, string description, int maxValueCou...
    method GetNames (line 465) | public string[] GetNames() {
    method GetValueSeparators (line 469) | public string[] GetValueSeparators() {
    method Parse (line 475) | protected static T Parse<T>(string value, OptionContext c) {
    method ParsePrototype (line 520) | private OptionValueType ParsePrototype() {
    method AddSeparators (line 560) | private static void AddSeparators(string name, int end, ICollection<st...
    method Invoke (line 591) | public void Invoke(OptionContext c) {
    method OnParseComplete (line 598) | protected abstract void OnParseComplete(OptionContext c);
    method InvokeOnParseComplete (line 600) | internal void InvokeOnParseComplete(OptionContext c) {
    method ToString (line 604) | public override string ToString() {
  class ArgumentSource (line 609) | public abstract class ArgumentSource {
    method ArgumentSource (line 611) | protected ArgumentSource() {
    method GetNames (line 614) | public abstract string[] GetNames();
    method GetArguments (line 616) | public abstract bool GetArguments(string value, out IEnumerable<string...
    method GetArgumentsFromFile (line 619) | public static IEnumerable<string> GetArgumentsFromFile(string file) {
    method GetArguments (line 624) | public static IEnumerable<string> GetArguments(TextReader reader) {
    method GetArguments (line 629) | static IEnumerable<string> GetArguments(TextReader reader, bool close) {
  class ResponseFileSource (line 671) | internal class ResponseFileSource : ArgumentSource {
    method GetNames (line 673) | public override string[] GetNames() {
    method GetArguments (line 681) | public override bool GetArguments(string value, out IEnumerable<string...
  class OptionException (line 692) | #if !PCL
    method OptionException (line 698) | public OptionException() {
    method OptionException (line 701) | public OptionException(string message, string optionName)
    method OptionException (line 706) | public OptionException(string message, string optionName, Exception in...
    method OptionException (line 712) | protected OptionException(SerializationInfo info, StreamingContext con...
    method GetObjectData (line 724) | [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter ...
  class OptionSet (line 735) | public class OptionSet : KeyedCollection<string, Option> {
    method OptionSet (line 736) | public OptionSet()
    method OptionSet (line 740) | public OptionSet(MessageLocalizerConverter localizer) {
    method GetKeyForItem (line 765) | protected override string GetKeyForItem(Option item) {
    method GetOptionForName (line 775) | [Obsolete("Use KeyedCollection.this[string]")]
    method InsertItem (line 786) | protected override void InsertItem(int index, Option item) {
    method RemoveItem (line 791) | protected override void RemoveItem(int index) {
    method SetItem (line 800) | protected override void SetItem(int index, Option item) {
    method AddImpl (line 805) | private void AddImpl(Option option) {
    method Add (line 822) | public OptionSet Add(string header) {
    class Category (line 829) | internal sealed class Category : Option {
      method Category (line 834) | public Category(string description)
      method OnParseComplete (line 838) | protected override void OnParseComplete(OptionContext c) {
    method Add (line 844) | public new OptionSet Add(Option option) {
    class ActionOption (line 849) | sealed class ActionOption : Option {
      method ActionOption (line 852) | public ActionOption(string prototype, string description, int count,...
      method ActionOption (line 856) | public ActionOption(string prototype, string description, int count,...
      method OnParseComplete (line 863) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 905) | public ActionOption(string prototype, string description, Action<T> ...
      method OnParseComplete (line 912) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 920) | public ActionOption(string prototype, string description, OptionActi...
      method OnParseComplete (line 927) | protected override void OnParseComplete(OptionContext c) {
    method Add (line 868) | public OptionSet Add(string prototype, Action<string> action) {
    method Add (line 872) | public OptionSet Add(string prototype, string description, Action<stri...
    method Add (line 876) | public OptionSet Add(string prototype, string description, Action<stri...
    method Add (line 885) | public OptionSet Add(string prototype, OptionAction<string, string> ac...
    method Add (line 889) | public OptionSet Add(string prototype, string description, OptionActio...
    method Add (line 893) | public OptionSet Add(string prototype, string description, OptionActio...
    class ActionOption (line 902) | sealed class ActionOption<T> : Option {
      method ActionOption (line 852) | public ActionOption(string prototype, string description, int count,...
      method ActionOption (line 856) | public ActionOption(string prototype, string description, int count,...
      method OnParseComplete (line 863) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 905) | public ActionOption(string prototype, string description, Action<T> ...
      method OnParseComplete (line 912) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 920) | public ActionOption(string prototype, string description, OptionActi...
      method OnParseComplete (line 927) | protected override void OnParseComplete(OptionContext c) {
    class ActionOption (line 917) | sealed class ActionOption<TKey, TValue> : Option {
      method ActionOption (line 852) | public ActionOption(string prototype, string description, int count,...
      method ActionOption (line 856) | public ActionOption(string prototype, string description, int count,...
      method OnParseComplete (line 863) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 905) | public ActionOption(string prototype, string description, Action<T> ...
      method OnParseComplete (line 912) | protected override void OnParseComplete(OptionContext c) {
      method ActionOption (line 920) | public ActionOption(string prototype, string description, OptionActi...
      method OnParseComplete (line 927) | protected override void OnParseComplete(OptionContext c) {
    method Add (line 934) | public OptionSet Add<T>(string prototype, Action<T> action) {
    method Add (line 938) | public OptionSet Add<T>(string prototype, string description, Action<T...
    method Add (line 942) | public OptionSet Add<TKey, TValue>(string prototype, OptionAction<TKey...
    method Add (line 946) | public OptionSet Add<TKey, TValue>(string prototype, string descriptio...
    method Add (line 950) | public OptionSet Add(ArgumentSource source) {
    method CreateOptionContext (line 957) | protected virtual OptionContext CreateOptionContext() {
    method Parse (line 961) | public List<string> Parse(IEnumerable<string> arguments) {
    class ArgumentEnumerator (line 990) | class ArgumentEnumerator : IEnumerable<string> {
      method ArgumentEnumerator (line 993) | public ArgumentEnumerator(IEnumerable<string> arguments) {
      method Add (line 997) | public void Add(IEnumerable<string> arguments) {
      method GetEnumerator (line 1001) | public IEnumerator<string> GetEnumerator() {
      method GetEnumerator (line 1013) | IEnumerator IEnumerable.GetEnumerator() {
    method AddSource (line 1018) | bool AddSource(ArgumentEnumerator ae, string argument) {
    method Unprocessed (line 1029) | private static bool Unprocessed(ICollection<string> extra, Option def,...
    method GetOptionParts (line 1043) | protected bool GetOptionParts(string argument, out string flag, out st...
    method Parse (line 1061) | protected virtual bool Parse(string argument, OptionContext c) {
    method ParseValue (line 1098) | private void ParseValue(string option, OptionContext c) {
    method ParseBool (line 1116) | private bool ParseBool(string option, string n, OptionContext c) {
    method ParseBundledValue (line 1132) | private bool ParseBundledValue(string f, string n, OptionContext c) {
    method Invoke (line 1165) | private static void Invoke(OptionContext c, string name, string value,...
    method WriteOptionDescriptions (line 1179) | public void WriteOptionDescriptions(TextWriter o) {
    method WriteCommandDescription (line 1237) | internal void WriteCommandDescription(TextWriter o, Command c, string ...
    method WriteDescription (line 1247) | void WriteDescription(TextWriter o, string value, string prefix, int f...
    method WriteOptionPrototype (line 1257) | bool WriteOptionPrototype(TextWriter o, Option p, ref int written) {
    method GetNextOptionIndex (line 1298) | static int GetNextOptionIndex(string[] names, int i) {
    method Write (line 1305) | static void Write(TextWriter o, ref int n, string s) {
    method GetArgumentName (line 1310) | static string GetArgumentName(int index, int maxIndex, string descript...
    method GetDescription (line 1332) | private static string GetDescription(string description) {
    method GetLines (line 1371) | private static IEnumerable<string> GetLines(string description, int fi...
  class Command (line 1376) | internal class Command {
    method Command (line 1385) | public Command(string name, string help = null) {
    method NormalizeCommandName (line 1393) | static string NormalizeCommandName(string name) {
    method Invoke (line 1408) | public virtual int Invoke(IEnumerable<string> arguments) {
  class CommandOption (line 1415) | class CommandOption : Option {
    method CommandOption (line 1422) | public CommandOption(Command command, string commandName = null, bool ...
    method OnParseComplete (line 1430) | protected override void OnParseComplete(OptionContext c) {
  class HelpOption (line 1435) | class HelpOption : Option {
    method HelpOption (line 1439) | public HelpOption(CommandSet commands, Option d)
    method OnParseComplete (line 1445) | protected override void OnParseComplete(OptionContext c) {
  class CommandOptionSet (line 1452) | class CommandOptionSet : OptionSet {
    method CommandOptionSet (line 1455) | public CommandOptionSet(CommandSet commands, MessageLocalizerConverter...
    method SetItem (line 1460) | protected override void SetItem(int index, Option item) {
    method ShouldWrapOption (line 1468) | bool ShouldWrapOption(Option item) {
    method InsertItem (line 1481) | protected override void InsertItem(int index, Option item) {
  class CommandSet (line 1490) | internal class CommandSet : KeyedCollection<string, Command> {
    method CommandSet (line 1506) | public CommandSet(string suite, MessageLocalizerConverter localizer = ...
    method CommandSet (line 1511) | public CommandSet(string suite, TextWriter output, TextWriter error, M...
    method GetKeyForItem (line 1530) | protected override string GetKeyForItem(Command item) {
    method Add (line 1534) | public new CommandSet Add(Command value) {
    method AddCommand (line 1542) | void AddCommand(Command value) {
    method Add (line 1556) | public CommandSet Add(string header) {
    method Add (line 1561) | public CommandSet Add(Option option) {
    method Add (line 1566) | public CommandSet Add(string prototype, Action<string> action) {
    method Add (line 1571) | public CommandSet Add(string prototype, string description, Action<str...
    method Add (line 1576) | public CommandSet Add(string prototype, string description, Action<str...
    method Add (line 1581) | public CommandSet Add(string prototype, OptionAction<string, string> a...
    method Add (line 1586) | public CommandSet Add(string prototype, string description, OptionActi...
    method Add (line 1591) | public CommandSet Add(string prototype, string description, OptionActi...
    method Add (line 1596) | public CommandSet Add<T>(string prototype, Action<T> action) {
    method Add (line 1601) | public CommandSet Add<T>(string prototype, string description, Action<...
    method Add (line 1606) | public CommandSet Add<TKey, TValue>(string prototype, OptionAction<TKe...
    method Add (line 1611) | public CommandSet Add<TKey, TValue>(string prototype, string descripti...
    method Add (line 1616) | public CommandSet Add(ArgumentSource source) {
    method Add (line 1621) | public CommandSet Add(CommandSet nestedCommands) {
    method AlreadyAdded (line 1647) | bool AlreadyAdded(CommandSet value) {
    method GetCompletions (line 1659) | public IEnumerable<string> GetCompletions(string prefix = null) {
    method ExtractToken (line 1681) | static void ExtractToken(ref string input, out string rest) {
    method Run (line 1704) | public int Run(IEnumerable<string> arguments) {
    method GetCommand (line 1744) | internal Command GetCommand(List<string> extra) {
    method TryGetLocalCommand (line 1748) | Command TryGetLocalCommand(List<string> extra) {
    method TryGetNestedCommand (line 1764) | Command TryGetNestedCommand(List<string> extra) {
  class HelpCommand (line 1787) | internal class HelpCommand : Command {
    method HelpCommand (line 1788) | public HelpCommand()
    method Invoke (line 1792) | public override int Invoke(IEnumerable<string> arguments) {
    method GetCommands (line 1828) | List<KeyValuePair<string, Command>> GetCommands() {
    method AddNestedCommands (line 1845) | void AddNestedCommands(List<KeyValuePair<string, Command>> commands, s...
    method WriteUnknownCommand (line 1856) | internal void WriteUnknownCommand(string unknownCommand) {

FILE: SylantStrikeInject/Program.cs
  class Program (line 13) | class Program
    method Main (line 18) | static void Main(string[] args)
    method RunThisAsAdmin (line 47) | private static void RunThisAsAdmin(string args)
    method IsAdministrator (line 65) | private static bool IsAdministrator()
    method WaitForProcess (line 72) | static void WaitForProcess()
    method startWatch_EventArrived (line 89) | static void startWatch_EventArrived(object sender, EventArrivedEventAr...
    method GetProcessInfo (line 108) | static ProcessInfo GetProcessInfo(EventArrivedEventArgs e)
    class ProcessInfo (line 118) | internal class ProcessInfo
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (212K chars).
[
  {
    "path": ".gitattributes",
    "chars": 2518,
    "preview": "###############################################################################\n# Set default behavior to automatically "
  },
  {
    "path": ".gitignore",
    "chars": 5745,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "README.md",
    "chars": 224,
    "preview": "### SylantStrike - a simple EDR written as part of a two part blog series on creating and bypassing an EDR\n\nOriginal blo"
  },
  {
    "path": "SylantStrike/SylantStrike.cpp",
    "chars": 1082,
    "preview": "// SylantStrike.cpp : Hooked API implementations\n//\n\n#include \"pch.h\"\n#include \"framework.h\"\n#include \"SylantStrike.h\"\n\n"
  },
  {
    "path": "SylantStrike/SylantStrike.h",
    "chars": 1090,
    "preview": "// The following ifdef block is the standard way of creating macros which make exporting\n// from a DLL simpler. All file"
  },
  {
    "path": "SylantStrike/SylantStrike.vcxproj",
    "chars": 12871,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "SylantStrike/SylantStrike.vcxproj.filters",
    "chars": 2829,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "SylantStrike/cpp.hint",
    "chars": 94,
    "preview": "#define CYLANTSTRIKE_API __declspec(dllexport)\n#define CYLANTSTRIKE_API __declspec(dllimport)\n"
  },
  {
    "path": "SylantStrike/dllmain.cpp",
    "chars": 1591,
    "preview": "// dllmain.cpp : Defines the entry point for the DLL application.\n#include \"pch.h\"\n\n#include \"minhook/include/MinHook.h\""
  },
  {
    "path": "SylantStrike/framework.h",
    "chars": 149,
    "preview": "#pragma once\n\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\n// Windows Heade"
  },
  {
    "path": "SylantStrike/minhook/include/MinHook.h",
    "chars": 7503,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All righ"
  },
  {
    "path": "SylantStrike/minhook/src/buffer.c",
    "chars": 9806,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rig"
  },
  {
    "path": "SylantStrike/minhook/src/buffer.h",
    "chars": 1818,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rig"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde32.c",
    "chars": 9381,
    "preview": "/*\n * Hacker Disassembler Engine 32 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#i"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde32.h",
    "chars": 2448,
    "preview": "/*\n * Hacker Disassembler Engine 32\n * Copyright (c) 2006-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n * hde32."
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde64.c",
    "chars": 9570,
    "preview": "/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#i"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde64.h",
    "chars": 2600,
    "preview": "/*\n * Hacker Disassembler Engine 64\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n * hde64."
  },
  {
    "path": "SylantStrike/minhook/src/hde/pstdint.h",
    "chars": 1660,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu. All rights "
  },
  {
    "path": "SylantStrike/minhook/src/hde/table32.h",
    "chars": 3506,
    "preview": "/*\n * Hacker Disassembler Engine 32 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#d"
  },
  {
    "path": "SylantStrike/minhook/src/hde/table64.h",
    "chars": 3575,
    "preview": "/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#d"
  },
  {
    "path": "SylantStrike/minhook/src/hook.c",
    "chars": 25041,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rig"
  },
  {
    "path": "SylantStrike/minhook/src/trampoline.c",
    "chars": 10572,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rig"
  },
  {
    "path": "SylantStrike/minhook/src/trampoline.h",
    "chars": 3757,
    "preview": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rig"
  },
  {
    "path": "SylantStrike/pch.cpp",
    "chars": 186,
    "preview": "// pch.cpp: source file corresponding to the pre-compiled header\n\n#include \"pch.h\"\n\n// When you are using pre-compiled h"
  },
  {
    "path": "SylantStrike/pch.h",
    "chars": 563,
    "preview": "// pch.h: This is a precompiled header file.\n// Files listed below are compiled only once, improving build performance f"
  },
  {
    "path": "SylantStrike.sln",
    "chars": 2780,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.3011"
  },
  {
    "path": "SylantStrikeInject/App.config",
    "chars": 180,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".N"
  },
  {
    "path": "SylantStrikeInject/BasicInject.cs",
    "chars": 2964,
    "preview": "//Based on code from https://codingvision.net/security/c-inject-a-dll-into-a-process-w-createremotethread\n\nusing System"
  },
  {
    "path": "SylantStrikeInject/Options.cs",
    "chars": 69445,
    "preview": "//\n// Options.cs\n//\n// Authors:\n//  Jonathan Pryor <jpryor@novell.com>, <Jonathan.Pryor@microsoft.com>\n//  Federico Di "
  },
  {
    "path": "SylantStrikeInject/Program.cs",
    "chars": 4070,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Management;\nu"
  },
  {
    "path": "SylantStrikeInject/Properties/AssemblyInfo.cs",
    "chars": 1404,
    "preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
  },
  {
    "path": "SylantStrikeInject/SylantStrikeInject.csproj",
    "chars": 2421,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  }
]

About this extraction

This page contains the full source code of the CCob/SylantStrike GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (198.7 KB), approximately 51.6k tokens, and a symbol index with 250 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!