[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- Backup*.rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb"
  },
  {
    "path": "README.md",
    "content": "### SylantStrike - a simple EDR written as part of a two part blog series on creating and bypassing an EDR\n\nOriginal blog post with description at https://ethicalchaos.dev/2020/05/27/lets-create-an-edr-and-bypass-it-part-1/\n"
  },
  {
    "path": "SylantStrike/SylantStrike.cpp",
    "content": "// SylantStrike.cpp : Hooked API implementations\n//\n\n#include \"pch.h\"\n#include \"framework.h\"\n#include \"SylantStrike.h\"\n\n//Pointer to the trampoline function used to call the original API\npNtProtectVirtualMemory pOriginalNtProtectVirtualMemory = nullptr;\n\nDWORD NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection) {\n\n\t//Check to see if the calling application is requesting RWX\n\tif ((NewAccessProtection & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE) {\n\t\t//It was, so notify the user of naughtly behaviour and terminate the running program\n\t\tMessageBox(nullptr, TEXT(\"You've been a naughty little hax0r, terminating program\"), TEXT(\"Hax0r Detected\"), MB_OK);\n\t\tTerminateProcess(GetCurrentProcess(), 0xdead1337);\n\t\t//Unreachable code\n\t\treturn 0;\n\t}\n\n\t//No it wasn't, so just call the original function as normal\n\treturn pOriginalNtProtectVirtualMemory(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection);\n}\n"
  },
  {
    "path": "SylantStrike/SylantStrike.h",
    "content": "// The following ifdef block is the standard way of creating macros which make exporting\n// from a DLL simpler. All files within this DLL are compiled with the CYLANTSTRIKE_EXPORTS\n// symbol defined on the command line. This symbol should not be defined on any project\n// that uses this DLL. This way any other project whose source files include this file see\n// CYLANTSTRIKE_API functions as being imported from a DLL, whereas this DLL sees symbols\n// defined with this macro as being exported.\n#ifdef CYLANTSTRIKE_EXPORTS\n#define CYLANTSTRIKE_API __declspec(dllexport)\n#else\n#define CYLANTSTRIKE_API __declspec(dllimport)\n#endif\n\ntypedef DWORD (NTAPI *pNtProtectVirtualMemory)(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection);\n\nextern pNtProtectVirtualMemory pOriginalNtProtectVirtualMemory;\n\n\nDWORD NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN OUT PULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection);\n\n\n\n"
  },
  {
    "path": "SylantStrike/SylantStrike.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{1ddd15aa-d837-4143-a272-0e08f9ed6c40}</ProjectGuid>\n    <RootNamespace>CylantStrike</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <ProjectName>SylantStrike</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <TargetName>SylantStrike</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <TargetName>SylantStrike</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <TargetName>SylantStrike</TargetName>\n    <IgnoreImportLibrary>true</IgnoreImportLibrary>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <TargetName>SylantStrike</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <None Include=\"cpp.hint\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"SylantStrike.h\" />\n    <ClInclude Include=\"framework.h\" />\n    <ClInclude Include=\"minhook\\include\\MinHook.h\" />\n    <ClInclude Include=\"minhook\\src\\buffer.h\" />\n    <ClInclude Include=\"minhook\\src\\hde\\hde32.h\" />\n    <ClInclude Include=\"minhook\\src\\hde\\hde64.h\" />\n    <ClInclude Include=\"minhook\\src\\hde\\pstdint.h\" />\n    <ClInclude Include=\"minhook\\src\\hde\\table32.h\" />\n    <ClInclude Include=\"minhook\\src\\hde\\table64.h\" />\n    <ClInclude Include=\"minhook\\src\\trampoline.h\" />\n    <ClInclude Include=\"pch.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"SylantStrike.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"dllmain.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\buffer.c\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hde\\hde32.c\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hde\\hde64.c\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hook.c\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\trampoline.c\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">NotUsing</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "SylantStrike/SylantStrike.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"cpp.hint\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"framework.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"pch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\buffer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\trampoline.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\include\\MinHook.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\hde\\hde32.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\hde\\hde64.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\hde\\pstdint.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\hde\\table32.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"minhook\\src\\hde\\table64.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SylantStrike.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"dllmain.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"pch.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\buffer.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hook.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\trampoline.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hde\\hde32.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"minhook\\src\\hde\\hde64.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SylantStrike.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SylantStrike/cpp.hint",
    "content": "#define CYLANTSTRIKE_API __declspec(dllexport)\n#define CYLANTSTRIKE_API __declspec(dllimport)\n"
  },
  {
    "path": "SylantStrike/dllmain.cpp",
    "content": "// dllmain.cpp : Defines the entry point for the DLL application.\n#include \"pch.h\"\n\n#include \"minhook/include/MinHook.h\"\n#include \"SylantStrike.h\"\n\nDWORD WINAPI InitHooksThread(LPVOID param) {\n\n    //MinHook itself requires initialisation, lets do this\n    //before we hook specific API calls.\n    if (MH_Initialize() != MH_OK) {\n        OutputDebugString(TEXT(\"Failed to initalize MinHook library\\n\"));\n        return -1;\n    }\n\n    //Now that we have initialised MinHook, lets prepare to hook NtProtectVirtualMemory from ntdll.dll\n    MH_STATUS status = MH_CreateHookApi(TEXT(\"ntdll\"), \"NtProtectVirtualMemory\", NtProtectVirtualMemory, \n                                           reinterpret_cast<LPVOID*>(&pOriginalNtProtectVirtualMemory));  \n\n    //Enable our hooks so they become active\n    status = MH_EnableHook(MH_ALL_HOOKS);\n\n    return status;\n}\n\nBOOL APIENTRY DllMain( HMODULE hModule,\n                       DWORD  ul_reason_for_call,\n                       LPVOID lpReserved\n                     )\n{\n    switch (ul_reason_for_call)\n    {\n    case DLL_PROCESS_ATTACH: {\n        //We are not interested in callbacks when a thread is created\n        DisableThreadLibraryCalls(hModule);\n\n        //We need to create a thread when initialising our hooks since\n        //DllMain is prone to lockups if executing code inline.\n        HANDLE hThread = CreateThread(nullptr, 0, InitHooksThread, nullptr, 0, nullptr);\n        if (hThread != nullptr) {\n            CloseHandle(hThread);\n        }\n        break;\n    }\n    case DLL_PROCESS_DETACH:\n\n        break;\n    }\n    return TRUE;\n}\n\n"
  },
  {
    "path": "SylantStrike/framework.h",
    "content": "#pragma once\n\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\n// Windows Header Files\n#include <windows.h>\n"
  },
  {
    "path": "SylantStrike/minhook/include/MinHook.h",
    "content": "/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)\n    #error MinHook supports only x86 and x64 systems.\n#endif\n\n#include <windows.h>\n\n// MinHook Error Codes.\ntypedef enum MH_STATUS\n{\n    // Unknown error. Should not be returned.\n    MH_UNKNOWN = -1,\n\n    // Successful.\n    MH_OK = 0,\n\n    // MinHook is already initialized.\n    MH_ERROR_ALREADY_INITIALIZED,\n\n    // MinHook is not initialized yet, or already uninitialized.\n    MH_ERROR_NOT_INITIALIZED,\n\n    // The hook for the specified target function is already created.\n    MH_ERROR_ALREADY_CREATED,\n\n    // The hook for the specified target function is not created yet.\n    MH_ERROR_NOT_CREATED,\n\n    // The hook for the specified target function is already enabled.\n    MH_ERROR_ENABLED,\n\n    // The hook for the specified target function is not enabled yet, or already\n    // disabled.\n    MH_ERROR_DISABLED,\n\n    // The specified pointer is invalid. It points the address of non-allocated\n    // and/or non-executable region.\n    MH_ERROR_NOT_EXECUTABLE,\n\n    // The specified target function cannot be hooked.\n    MH_ERROR_UNSUPPORTED_FUNCTION,\n\n    // Failed to allocate memory.\n    MH_ERROR_MEMORY_ALLOC,\n\n    // Failed to change the memory protection.\n    MH_ERROR_MEMORY_PROTECT,\n\n    // The specified module is not loaded.\n    MH_ERROR_MODULE_NOT_FOUND,\n\n    // The specified function is not found.\n    MH_ERROR_FUNCTION_NOT_FOUND\n}\nMH_STATUS;\n\n// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,\n// MH_QueueEnableHook or MH_QueueDisableHook.\n#define MH_ALL_HOOKS NULL\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n    // Initialize the MinHook library. You must call this function EXACTLY ONCE\n    // at the beginning of your program.\n    MH_STATUS WINAPI MH_Initialize(VOID);\n\n    // Uninitialize the MinHook library. You must call this function EXACTLY\n    // ONCE at the end of your program.\n    MH_STATUS WINAPI MH_Uninitialize(VOID);\n\n    // Creates a Hook for the specified target function, in disabled state.\n    // Parameters:\n    //   pTarget    [in]  A pointer to the target function, which will be\n    //                    overridden by the detour function.\n    //   pDetour    [in]  A pointer to the detour function, which will override\n    //                    the target function.\n    //   ppOriginal [out] A pointer to the trampoline function, which will be\n    //                    used to call the original target function.\n    //                    This parameter can be NULL.\n    MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);\n\n    // Creates a Hook for the specified API function, in disabled state.\n    // Parameters:\n    //   pszModule  [in]  A pointer to the loaded module name which contains the\n    //                    target function.\n    //   pszTarget  [in]  A pointer to the target function name, which will be\n    //                    overridden by the detour function.\n    //   pDetour    [in]  A pointer to the detour function, which will override\n    //                    the target function.\n    //   ppOriginal [out] A pointer to the trampoline function, which will be\n    //                    used to call the original target function.\n    //                    This parameter can be NULL.\n    MH_STATUS WINAPI MH_CreateHookApi(\n        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);\n\n    // Creates a Hook for the specified API function, in disabled state.\n    // Parameters:\n    //   pszModule  [in]  A pointer to the loaded module name which contains the\n    //                    target function.\n    //   pszTarget  [in]  A pointer to the target function name, which will be\n    //                    overridden by the detour function.\n    //   pDetour    [in]  A pointer to the detour function, which will override\n    //                    the target function.\n    //   ppOriginal [out] A pointer to the trampoline function, which will be\n    //                    used to call the original target function.\n    //                    This parameter can be NULL.\n    //   ppTarget   [out] A pointer to the target function, which will be used\n    //                    with other functions.\n    //                    This parameter can be NULL.\n    MH_STATUS WINAPI MH_CreateHookApiEx(\n        LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);\n\n    // Removes an already created hook.\n    // Parameters:\n    //   pTarget [in] A pointer to the target function.\n    MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);\n\n    // Enables an already created hook.\n    // Parameters:\n    //   pTarget [in] A pointer to the target function.\n    //                If this parameter is MH_ALL_HOOKS, all created hooks are\n    //                enabled in one go.\n    MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);\n\n    // Disables an already created hook.\n    // Parameters:\n    //   pTarget [in] A pointer to the target function.\n    //                If this parameter is MH_ALL_HOOKS, all created hooks are\n    //                disabled in one go.\n    MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);\n\n    // Queues to enable an already created hook.\n    // Parameters:\n    //   pTarget [in] A pointer to the target function.\n    //                If this parameter is MH_ALL_HOOKS, all created hooks are\n    //                queued to be enabled.\n    MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);\n\n    // Queues to disable an already created hook.\n    // Parameters:\n    //   pTarget [in] A pointer to the target function.\n    //                If this parameter is MH_ALL_HOOKS, all created hooks are\n    //                queued to be disabled.\n    MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);\n\n    // Applies all queued changes in one go.\n    MH_STATUS WINAPI MH_ApplyQueued(VOID);\n\n    // Translates the MH_STATUS to its name as a string.\n    const char * WINAPI MH_StatusToString(MH_STATUS status);\n\n#ifdef __cplusplus\n}\n#endif\n\n"
  },
  {
    "path": "SylantStrike/minhook/src/buffer.c",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <windows.h>\n#include \"buffer.h\"\n\n// Size of each memory block. (= page size of VirtualAlloc)\n#define MEMORY_BLOCK_SIZE 0x1000\n\n// Max range for seeking a memory block. (= 1024MB)\n#define MAX_MEMORY_RANGE 0x40000000\n\n// Memory protection flags to check the executable address.\n#define PAGE_EXECUTE_FLAGS \\\n    (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)\n\n// Memory slot.\ntypedef struct _MEMORY_SLOT\n{\n    union\n    {\n        struct _MEMORY_SLOT *pNext;\n        UINT8 buffer[MEMORY_SLOT_SIZE];\n    };\n} MEMORY_SLOT, *PMEMORY_SLOT;\n\n// Memory block info. Placed at the head of each block.\ntypedef struct _MEMORY_BLOCK\n{\n    struct _MEMORY_BLOCK *pNext;\n    PMEMORY_SLOT pFree;         // First element of the free slot list.\n    UINT usedCount;\n} MEMORY_BLOCK, *PMEMORY_BLOCK;\n\n//-------------------------------------------------------------------------\n// Global Variables:\n//-------------------------------------------------------------------------\n\n// First element of the memory block list.\nPMEMORY_BLOCK g_pMemoryBlocks;\n\n//-------------------------------------------------------------------------\nVOID InitializeBuffer(VOID)\n{\n    // Nothing to do for now.\n}\n\n//-------------------------------------------------------------------------\nVOID UninitializeBuffer(VOID)\n{\n    PMEMORY_BLOCK pBlock = g_pMemoryBlocks;\n    g_pMemoryBlocks = NULL;\n\n    while (pBlock)\n    {\n        PMEMORY_BLOCK pNext = pBlock->pNext;\n        VirtualFree(pBlock, 0, MEM_RELEASE);\n        pBlock = pNext;\n    }\n}\n\n//-------------------------------------------------------------------------\n#if defined(_M_X64) || defined(__x86_64__)\nstatic LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)\n{\n    ULONG_PTR tryAddr = (ULONG_PTR)pAddress;\n\n    // Round down to the allocation granularity.\n    tryAddr -= tryAddr % dwAllocationGranularity;\n\n    // Start from the previous allocation granularity multiply.\n    tryAddr -= dwAllocationGranularity;\n\n    while (tryAddr >= (ULONG_PTR)pMinAddr)\n    {\n        MEMORY_BASIC_INFORMATION mbi;\n        if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)\n            break;\n\n        if (mbi.State == MEM_FREE)\n            return (LPVOID)tryAddr;\n\n        if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)\n            break;\n\n        tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;\n    }\n\n    return NULL;\n}\n#endif\n\n//-------------------------------------------------------------------------\n#if defined(_M_X64) || defined(__x86_64__)\nstatic LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)\n{\n    ULONG_PTR tryAddr = (ULONG_PTR)pAddress;\n\n    // Round down to the allocation granularity.\n    tryAddr -= tryAddr % dwAllocationGranularity;\n\n    // Start from the next allocation granularity multiply.\n    tryAddr += dwAllocationGranularity;\n\n    while (tryAddr <= (ULONG_PTR)pMaxAddr)\n    {\n        MEMORY_BASIC_INFORMATION mbi;\n        if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)\n            break;\n\n        if (mbi.State == MEM_FREE)\n            return (LPVOID)tryAddr;\n\n        tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;\n\n        // Round up to the next allocation granularity.\n        tryAddr += dwAllocationGranularity - 1;\n        tryAddr -= tryAddr % dwAllocationGranularity;\n    }\n\n    return NULL;\n}\n#endif\n\n//-------------------------------------------------------------------------\nstatic PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)\n{\n    PMEMORY_BLOCK pBlock;\n#if defined(_M_X64) || defined(__x86_64__)\n    ULONG_PTR minAddr;\n    ULONG_PTR maxAddr;\n\n    SYSTEM_INFO si;\n    GetSystemInfo(&si);\n    minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;\n    maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;\n\n    // pOrigin ± 512MB\n    if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)\n        minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;\n\n    if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)\n        maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;\n\n    // Make room for MEMORY_BLOCK_SIZE bytes.\n    maxAddr -= MEMORY_BLOCK_SIZE - 1;\n#endif\n\n    // Look the registered blocks for a reachable one.\n    for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)\n    {\n#if defined(_M_X64) || defined(__x86_64__)\n        // Ignore the blocks too far.\n        if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)\n            continue;\n#endif\n        // The block has at least one unused slot.\n        if (pBlock->pFree != NULL)\n            return pBlock;\n    }\n\n#if defined(_M_X64) || defined(__x86_64__)\n    // Alloc a new block above if not found.\n    {\n        LPVOID pAlloc = pOrigin;\n        while ((ULONG_PTR)pAlloc >= minAddr)\n        {\n            pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);\n            if (pAlloc == NULL)\n                break;\n\n            pBlock = (PMEMORY_BLOCK)VirtualAlloc(\n                pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);\n            if (pBlock != NULL)\n                break;\n        }\n    }\n\n    // Alloc a new block below if not found.\n    if (pBlock == NULL)\n    {\n        LPVOID pAlloc = pOrigin;\n        while ((ULONG_PTR)pAlloc <= maxAddr)\n        {\n            pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);\n            if (pAlloc == NULL)\n                break;\n\n            pBlock = (PMEMORY_BLOCK)VirtualAlloc(\n                pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);\n            if (pBlock != NULL)\n                break;\n        }\n    }\n#else\n    // In x86 mode, a memory block can be placed anywhere.\n    pBlock = (PMEMORY_BLOCK)VirtualAlloc(\n        NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);\n#endif\n\n    if (pBlock != NULL)\n    {\n        // Build a linked list of all the slots.\n        PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;\n        pBlock->pFree = NULL;\n        pBlock->usedCount = 0;\n        do\n        {\n            pSlot->pNext = pBlock->pFree;\n            pBlock->pFree = pSlot;\n            pSlot++;\n        } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);\n\n        pBlock->pNext = g_pMemoryBlocks;\n        g_pMemoryBlocks = pBlock;\n    }\n\n    return pBlock;\n}\n\n//-------------------------------------------------------------------------\nLPVOID AllocateBuffer(LPVOID pOrigin)\n{\n    PMEMORY_SLOT  pSlot;\n    PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);\n    if (pBlock == NULL)\n        return NULL;\n\n    // Remove an unused slot from the list.\n    pSlot = pBlock->pFree;\n    pBlock->pFree = pSlot->pNext;\n    pBlock->usedCount++;\n#ifdef _DEBUG\n    // Fill the slot with INT3 for debugging.\n    memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));\n#endif\n    return pSlot;\n}\n\n//-------------------------------------------------------------------------\nVOID FreeBuffer(LPVOID pBuffer)\n{\n    PMEMORY_BLOCK pBlock = g_pMemoryBlocks;\n    PMEMORY_BLOCK pPrev = NULL;\n    ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;\n\n    while (pBlock != NULL)\n    {\n        if ((ULONG_PTR)pBlock == pTargetBlock)\n        {\n            PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;\n#ifdef _DEBUG\n            // Clear the released slot for debugging.\n            memset(pSlot, 0x00, sizeof(*pSlot));\n#endif\n            // Restore the released slot to the list.\n            pSlot->pNext = pBlock->pFree;\n            pBlock->pFree = pSlot;\n            pBlock->usedCount--;\n\n            // Free if unused.\n            if (pBlock->usedCount == 0)\n            {\n                if (pPrev)\n                    pPrev->pNext = pBlock->pNext;\n                else\n                    g_pMemoryBlocks = pBlock->pNext;\n\n                VirtualFree(pBlock, 0, MEM_RELEASE);\n            }\n\n            break;\n        }\n\n        pPrev = pBlock;\n        pBlock = pBlock->pNext;\n    }\n}\n\n//-------------------------------------------------------------------------\nBOOL IsExecutableAddress(LPVOID pAddress)\n{\n    MEMORY_BASIC_INFORMATION mi;\n    VirtualQuery(pAddress, &mi, sizeof(mi));\n\n    return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));\n}\n"
  },
  {
    "path": "SylantStrike/minhook/src/buffer.h",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n// Size of each memory slot.\n#if defined(_M_X64) || defined(__x86_64__)\n    #define MEMORY_SLOT_SIZE 64\n#else\n    #define MEMORY_SLOT_SIZE 32\n#endif\n\nVOID   InitializeBuffer(VOID);\nVOID   UninitializeBuffer(VOID);\nLPVOID AllocateBuffer(LPVOID pOrigin);\nVOID   FreeBuffer(LPVOID pBuffer);\nBOOL   IsExecutableAddress(LPVOID pAddress);\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde32.c",
    "content": "﻿/*\n * Hacker Disassembler Engine 32 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#if defined(_M_IX86) || defined(__i386__)\n\n#include \"hde32.h\"\n#include \"table32.h\"\n\nunsigned int hde32_disasm(const void *code, hde32s *hs)\n{\n    uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;\n    uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;\n\n    // Avoid using memset to reduce the footprint.\n#ifndef _MSC_VER\n    memset((LPBYTE)hs, 0, sizeof(hde32s));\n#else\n    __stosb((LPBYTE)hs, 0, sizeof(hde32s));\n#endif\n\n    for (x = 16; x; x--)\n        switch (c = *p++) {\n            case 0xf3:\n                hs->p_rep = c;\n                pref |= PRE_F3;\n                break;\n            case 0xf2:\n                hs->p_rep = c;\n                pref |= PRE_F2;\n                break;\n            case 0xf0:\n                hs->p_lock = c;\n                pref |= PRE_LOCK;\n                break;\n            case 0x26: case 0x2e: case 0x36:\n            case 0x3e: case 0x64: case 0x65:\n                hs->p_seg = c;\n                pref |= PRE_SEG;\n                break;\n            case 0x66:\n                hs->p_66 = c;\n                pref |= PRE_66;\n                break;\n            case 0x67:\n                hs->p_67 = c;\n                pref |= PRE_67;\n                break;\n            default:\n                goto pref_done;\n        }\n  pref_done:\n\n    hs->flags = (uint32_t)pref << 23;\n\n    if (!pref)\n        pref |= PRE_NONE;\n\n    if ((hs->opcode = c) == 0x0f) {\n        hs->opcode2 = c = *p++;\n        ht += DELTA_OPCODES;\n    } else if (c >= 0xa0 && c <= 0xa3) {\n        if (pref & PRE_67)\n            pref |= PRE_66;\n        else\n            pref &= ~PRE_66;\n    }\n\n    opcode = c;\n    cflags = ht[ht[opcode / 4] + (opcode % 4)];\n\n    if (cflags == C_ERROR) {\n        hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        cflags = 0;\n        if ((opcode & -3) == 0x24)\n            cflags++;\n    }\n\n    x = 0;\n    if (cflags & C_GROUP) {\n        uint16_t t;\n        t = *(uint16_t *)(ht + (cflags & 0x7f));\n        cflags = (uint8_t)t;\n        x = (uint8_t)(t >> 8);\n    }\n\n    if (hs->opcode2) {\n        ht = hde32_table + DELTA_PREFIXES;\n        if (ht[ht[opcode / 4] + (opcode % 4)] & pref)\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n    }\n\n    if (cflags & C_MODRM) {\n        hs->flags |= F_MODRM;\n        hs->modrm = c = *p++;\n        hs->modrm_mod = m_mod = c >> 6;\n        hs->modrm_rm = m_rm = c & 7;\n        hs->modrm_reg = m_reg = (c & 0x3f) >> 3;\n\n        if (x && ((x << m_reg) & 0x80))\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n\n        if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {\n            uint8_t t = opcode - 0xd9;\n            if (m_mod == 3) {\n                ht = hde32_table + DELTA_FPU_MODRM + t*8;\n                t = ht[m_reg] << m_rm;\n            } else {\n                ht = hde32_table + DELTA_FPU_REG;\n                t = ht[t] << m_reg;\n            }\n            if (t & 0x80)\n                hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        }\n\n        if (pref & PRE_LOCK) {\n            if (m_mod == 3) {\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n            } else {\n                uint8_t *table_end, op = opcode;\n                if (hs->opcode2) {\n                    ht = hde32_table + DELTA_OP2_LOCK_OK;\n                    table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;\n                } else {\n                    ht = hde32_table + DELTA_OP_LOCK_OK;\n                    table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;\n                    op &= -2;\n                }\n                for (; ht != table_end; ht++)\n                    if (*ht++ == op) {\n                        if (!((*ht << m_reg) & 0x80))\n                            goto no_lock_error;\n                        else\n                            break;\n                    }\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n              no_lock_error:\n                ;\n            }\n        }\n\n        if (hs->opcode2) {\n            switch (opcode) {\n                case 0x20: case 0x22:\n                    m_mod = 3;\n                    if (m_reg > 4 || m_reg == 1)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x21: case 0x23:\n                    m_mod = 3;\n                    if (m_reg == 4 || m_reg == 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        } else {\n            switch (opcode) {\n                case 0x8c:\n                    if (m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x8e:\n                    if (m_reg == 1 || m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        }\n\n        if (m_mod == 3) {\n            uint8_t *table_end;\n            if (hs->opcode2) {\n                ht = hde32_table + DELTA_OP2_ONLY_MEM;\n                table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;\n            } else {\n                ht = hde32_table + DELTA_OP_ONLY_MEM;\n                table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;\n            }\n            for (; ht != table_end; ht += 2)\n                if (*ht++ == opcode) {\n                    if (*ht++ & pref && !((*ht << m_reg) & 0x80))\n                        goto error_operand;\n                    else\n                        break;\n                }\n            goto no_error_operand;\n        } else if (hs->opcode2) {\n            switch (opcode) {\n                case 0x50: case 0xd7: case 0xf7:\n                    if (pref & (PRE_NONE | PRE_66))\n                        goto error_operand;\n                    break;\n                case 0xd6:\n                    if (pref & (PRE_F2 | PRE_F3))\n                        goto error_operand;\n                    break;\n                case 0xc5:\n                    goto error_operand;\n            }\n            goto no_error_operand;\n        } else\n            goto no_error_operand;\n\n      error_operand:\n        hs->flags |= F_ERROR | F_ERROR_OPERAND;\n      no_error_operand:\n\n        c = *p++;\n        if (m_reg <= 1) {\n            if (opcode == 0xf6)\n                cflags |= C_IMM8;\n            else if (opcode == 0xf7)\n                cflags |= C_IMM_P66;\n        }\n\n        switch (m_mod) {\n            case 0:\n                if (pref & PRE_67) {\n                    if (m_rm == 6)\n                        disp_size = 2;\n                } else\n                    if (m_rm == 5)\n                        disp_size = 4;\n                break;\n            case 1:\n                disp_size = 1;\n                break;\n            case 2:\n                disp_size = 2;\n                if (!(pref & PRE_67))\n                    disp_size <<= 1;\n        }\n\n        if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {\n            hs->flags |= F_SIB;\n            p++;\n            hs->sib = c;\n            hs->sib_scale = c >> 6;\n            hs->sib_index = (c & 0x3f) >> 3;\n            if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))\n                disp_size = 4;\n        }\n\n        p--;\n        switch (disp_size) {\n            case 1:\n                hs->flags |= F_DISP8;\n                hs->disp.disp8 = *p;\n                break;\n            case 2:\n                hs->flags |= F_DISP16;\n                hs->disp.disp16 = *(uint16_t *)p;\n                break;\n            case 4:\n                hs->flags |= F_DISP32;\n                hs->disp.disp32 = *(uint32_t *)p;\n        }\n        p += disp_size;\n    } else if (pref & PRE_LOCK)\n        hs->flags |= F_ERROR | F_ERROR_LOCK;\n\n    if (cflags & C_IMM_P66) {\n        if (cflags & C_REL32) {\n            if (pref & PRE_66) {\n                hs->flags |= F_IMM16 | F_RELATIVE;\n                hs->imm.imm16 = *(uint16_t *)p;\n                p += 2;\n                goto disasm_done;\n            }\n            goto rel32_ok;\n        }\n        if (pref & PRE_66) {\n            hs->flags |= F_IMM16;\n            hs->imm.imm16 = *(uint16_t *)p;\n            p += 2;\n        } else {\n            hs->flags |= F_IMM32;\n            hs->imm.imm32 = *(uint32_t *)p;\n            p += 4;\n        }\n    }\n\n    if (cflags & C_IMM16) {\n        if (hs->flags & F_IMM32) {\n            hs->flags |= F_IMM16;\n            hs->disp.disp16 = *(uint16_t *)p;\n        } else if (hs->flags & F_IMM16) {\n            hs->flags |= F_2IMM16;\n            hs->disp.disp16 = *(uint16_t *)p;\n        } else {\n            hs->flags |= F_IMM16;\n            hs->imm.imm16 = *(uint16_t *)p;\n        }\n        p += 2;\n    }\n    if (cflags & C_IMM8) {\n        hs->flags |= F_IMM8;\n        hs->imm.imm8 = *p++;\n    }\n\n    if (cflags & C_REL32) {\n      rel32_ok:\n        hs->flags |= F_IMM32 | F_RELATIVE;\n        hs->imm.imm32 = *(uint32_t *)p;\n        p += 4;\n    } else if (cflags & C_REL8) {\n        hs->flags |= F_IMM8 | F_RELATIVE;\n        hs->imm.imm8 = *p++;\n    }\n\n  disasm_done:\n\n    if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {\n        hs->flags |= F_ERROR | F_ERROR_LENGTH;\n        hs->len = 15;\n    }\n\n    return (unsigned int)hs->len;\n}\n\n#endif // defined(_M_IX86) || defined(__i386__)\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde32.h",
    "content": "﻿/*\n * Hacker Disassembler Engine 32\n * Copyright (c) 2006-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n * hde32.h: C/C++ header file\n *\n */\n\n#ifndef _HDE32_H_\n#define _HDE32_H_\n\n/* stdint.h - C99 standard header\n * http://en.wikipedia.org/wiki/stdint.h\n *\n * if your compiler doesn't contain \"stdint.h\" header (for\n * example, Microsoft Visual C++), you can download file:\n *   http://www.azillionmonkeys.com/qed/pstdint.h\n * and change next line to:\n *   #include \"pstdint.h\"\n */\n#include \"pstdint.h\"\n\n#define F_MODRM         0x00000001\n#define F_SIB           0x00000002\n#define F_IMM8          0x00000004\n#define F_IMM16         0x00000008\n#define F_IMM32         0x00000010\n#define F_DISP8         0x00000020\n#define F_DISP16        0x00000040\n#define F_DISP32        0x00000080\n#define F_RELATIVE      0x00000100\n#define F_2IMM16        0x00000800\n#define F_ERROR         0x00001000\n#define F_ERROR_OPCODE  0x00002000\n#define F_ERROR_LENGTH  0x00004000\n#define F_ERROR_LOCK    0x00008000\n#define F_ERROR_OPERAND 0x00010000\n#define F_PREFIX_REPNZ  0x01000000\n#define F_PREFIX_REPX   0x02000000\n#define F_PREFIX_REP    0x03000000\n#define F_PREFIX_66     0x04000000\n#define F_PREFIX_67     0x08000000\n#define F_PREFIX_LOCK   0x10000000\n#define F_PREFIX_SEG    0x20000000\n#define F_PREFIX_ANY    0x3f000000\n\n#define PREFIX_SEGMENT_CS   0x2e\n#define PREFIX_SEGMENT_SS   0x36\n#define PREFIX_SEGMENT_DS   0x3e\n#define PREFIX_SEGMENT_ES   0x26\n#define PREFIX_SEGMENT_FS   0x64\n#define PREFIX_SEGMENT_GS   0x65\n#define PREFIX_LOCK         0xf0\n#define PREFIX_REPNZ        0xf2\n#define PREFIX_REPX         0xf3\n#define PREFIX_OPERAND_SIZE 0x66\n#define PREFIX_ADDRESS_SIZE 0x67\n\n#pragma pack(push,1)\n\ntypedef struct {\n    uint8_t len;\n    uint8_t p_rep;\n    uint8_t p_lock;\n    uint8_t p_seg;\n    uint8_t p_66;\n    uint8_t p_67;\n    uint8_t opcode;\n    uint8_t opcode2;\n    uint8_t modrm;\n    uint8_t modrm_mod;\n    uint8_t modrm_reg;\n    uint8_t modrm_rm;\n    uint8_t sib;\n    uint8_t sib_scale;\n    uint8_t sib_index;\n    uint8_t sib_base;\n    union {\n        uint8_t imm8;\n        uint16_t imm16;\n        uint32_t imm32;\n    } imm;\n    union {\n        uint8_t disp8;\n        uint16_t disp16;\n        uint32_t disp32;\n    } disp;\n    uint32_t flags;\n} hde32s;\n\n#pragma pack(pop)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* __cdecl */\nunsigned int hde32_disasm(const void *code, hde32s *hs);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _HDE32_H_ */\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde64.c",
    "content": "﻿/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#if defined(_M_X64) || defined(__x86_64__)\n\n#include \"hde64.h\"\n#include \"table64.h\"\n\nunsigned int hde64_disasm(const void *code, hde64s *hs)\n{\n    uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;\n    uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;\n    uint8_t op64 = 0;\n\n    // Avoid using memset to reduce the footprint.\n#ifndef _MSC_VER\n    memset((LPBYTE)hs, 0, sizeof(hde64s));\n#else\n    __stosb((LPBYTE)hs, 0, sizeof(hde64s));\n#endif\n\n    for (x = 16; x; x--)\n        switch (c = *p++) {\n            case 0xf3:\n                hs->p_rep = c;\n                pref |= PRE_F3;\n                break;\n            case 0xf2:\n                hs->p_rep = c;\n                pref |= PRE_F2;\n                break;\n            case 0xf0:\n                hs->p_lock = c;\n                pref |= PRE_LOCK;\n                break;\n            case 0x26: case 0x2e: case 0x36:\n            case 0x3e: case 0x64: case 0x65:\n                hs->p_seg = c;\n                pref |= PRE_SEG;\n                break;\n            case 0x66:\n                hs->p_66 = c;\n                pref |= PRE_66;\n                break;\n            case 0x67:\n                hs->p_67 = c;\n                pref |= PRE_67;\n                break;\n            default:\n                goto pref_done;\n        }\n  pref_done:\n\n    hs->flags = (uint32_t)pref << 23;\n\n    if (!pref)\n        pref |= PRE_NONE;\n\n    if ((c & 0xf0) == 0x40) {\n        hs->flags |= F_PREFIX_REX;\n        if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)\n            op64++;\n        hs->rex_r = (c & 7) >> 2;\n        hs->rex_x = (c & 3) >> 1;\n        hs->rex_b = c & 1;\n        if (((c = *p++) & 0xf0) == 0x40) {\n            opcode = c;\n            goto error_opcode;\n        }\n    }\n\n    if ((hs->opcode = c) == 0x0f) {\n        hs->opcode2 = c = *p++;\n        ht += DELTA_OPCODES;\n    } else if (c >= 0xa0 && c <= 0xa3) {\n        op64++;\n        if (pref & PRE_67)\n            pref |= PRE_66;\n        else\n            pref &= ~PRE_66;\n    }\n\n    opcode = c;\n    cflags = ht[ht[opcode / 4] + (opcode % 4)];\n\n    if (cflags == C_ERROR) {\n      error_opcode:\n        hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        cflags = 0;\n        if ((opcode & -3) == 0x24)\n            cflags++;\n    }\n\n    x = 0;\n    if (cflags & C_GROUP) {\n        uint16_t t;\n        t = *(uint16_t *)(ht + (cflags & 0x7f));\n        cflags = (uint8_t)t;\n        x = (uint8_t)(t >> 8);\n    }\n\n    if (hs->opcode2) {\n        ht = hde64_table + DELTA_PREFIXES;\n        if (ht[ht[opcode / 4] + (opcode % 4)] & pref)\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n    }\n\n    if (cflags & C_MODRM) {\n        hs->flags |= F_MODRM;\n        hs->modrm = c = *p++;\n        hs->modrm_mod = m_mod = c >> 6;\n        hs->modrm_rm = m_rm = c & 7;\n        hs->modrm_reg = m_reg = (c & 0x3f) >> 3;\n\n        if (x && ((x << m_reg) & 0x80))\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n\n        if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {\n            uint8_t t = opcode - 0xd9;\n            if (m_mod == 3) {\n                ht = hde64_table + DELTA_FPU_MODRM + t*8;\n                t = ht[m_reg] << m_rm;\n            } else {\n                ht = hde64_table + DELTA_FPU_REG;\n                t = ht[t] << m_reg;\n            }\n            if (t & 0x80)\n                hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        }\n\n        if (pref & PRE_LOCK) {\n            if (m_mod == 3) {\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n            } else {\n                uint8_t *table_end, op = opcode;\n                if (hs->opcode2) {\n                    ht = hde64_table + DELTA_OP2_LOCK_OK;\n                    table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;\n                } else {\n                    ht = hde64_table + DELTA_OP_LOCK_OK;\n                    table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;\n                    op &= -2;\n                }\n                for (; ht != table_end; ht++)\n                    if (*ht++ == op) {\n                        if (!((*ht << m_reg) & 0x80))\n                            goto no_lock_error;\n                        else\n                            break;\n                    }\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n              no_lock_error:\n                ;\n            }\n        }\n\n        if (hs->opcode2) {\n            switch (opcode) {\n                case 0x20: case 0x22:\n                    m_mod = 3;\n                    if (m_reg > 4 || m_reg == 1)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x21: case 0x23:\n                    m_mod = 3;\n                    if (m_reg == 4 || m_reg == 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        } else {\n            switch (opcode) {\n                case 0x8c:\n                    if (m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x8e:\n                    if (m_reg == 1 || m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        }\n\n        if (m_mod == 3) {\n            uint8_t *table_end;\n            if (hs->opcode2) {\n                ht = hde64_table + DELTA_OP2_ONLY_MEM;\n                table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;\n            } else {\n                ht = hde64_table + DELTA_OP_ONLY_MEM;\n                table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;\n            }\n            for (; ht != table_end; ht += 2)\n                if (*ht++ == opcode) {\n                    if (*ht++ & pref && !((*ht << m_reg) & 0x80))\n                        goto error_operand;\n                    else\n                        break;\n                }\n            goto no_error_operand;\n        } else if (hs->opcode2) {\n            switch (opcode) {\n                case 0x50: case 0xd7: case 0xf7:\n                    if (pref & (PRE_NONE | PRE_66))\n                        goto error_operand;\n                    break;\n                case 0xd6:\n                    if (pref & (PRE_F2 | PRE_F3))\n                        goto error_operand;\n                    break;\n                case 0xc5:\n                    goto error_operand;\n            }\n            goto no_error_operand;\n        } else\n            goto no_error_operand;\n\n      error_operand:\n        hs->flags |= F_ERROR | F_ERROR_OPERAND;\n      no_error_operand:\n\n        c = *p++;\n        if (m_reg <= 1) {\n            if (opcode == 0xf6)\n                cflags |= C_IMM8;\n            else if (opcode == 0xf7)\n                cflags |= C_IMM_P66;\n        }\n\n        switch (m_mod) {\n            case 0:\n                if (pref & PRE_67) {\n                    if (m_rm == 6)\n                        disp_size = 2;\n                } else\n                    if (m_rm == 5)\n                        disp_size = 4;\n                break;\n            case 1:\n                disp_size = 1;\n                break;\n            case 2:\n                disp_size = 2;\n                if (!(pref & PRE_67))\n                    disp_size <<= 1;\n        }\n\n        if (m_mod != 3 && m_rm == 4) {\n            hs->flags |= F_SIB;\n            p++;\n            hs->sib = c;\n            hs->sib_scale = c >> 6;\n            hs->sib_index = (c & 0x3f) >> 3;\n            if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))\n                disp_size = 4;\n        }\n\n        p--;\n        switch (disp_size) {\n            case 1:\n                hs->flags |= F_DISP8;\n                hs->disp.disp8 = *p;\n                break;\n            case 2:\n                hs->flags |= F_DISP16;\n                hs->disp.disp16 = *(uint16_t *)p;\n                break;\n            case 4:\n                hs->flags |= F_DISP32;\n                hs->disp.disp32 = *(uint32_t *)p;\n        }\n        p += disp_size;\n    } else if (pref & PRE_LOCK)\n        hs->flags |= F_ERROR | F_ERROR_LOCK;\n\n    if (cflags & C_IMM_P66) {\n        if (cflags & C_REL32) {\n            if (pref & PRE_66) {\n                hs->flags |= F_IMM16 | F_RELATIVE;\n                hs->imm.imm16 = *(uint16_t *)p;\n                p += 2;\n                goto disasm_done;\n            }\n            goto rel32_ok;\n        }\n        if (op64) {\n            hs->flags |= F_IMM64;\n            hs->imm.imm64 = *(uint64_t *)p;\n            p += 8;\n        } else if (!(pref & PRE_66)) {\n            hs->flags |= F_IMM32;\n            hs->imm.imm32 = *(uint32_t *)p;\n            p += 4;\n        } else\n            goto imm16_ok;\n    }\n\n\n    if (cflags & C_IMM16) {\n      imm16_ok:\n        hs->flags |= F_IMM16;\n        hs->imm.imm16 = *(uint16_t *)p;\n        p += 2;\n    }\n    if (cflags & C_IMM8) {\n        hs->flags |= F_IMM8;\n        hs->imm.imm8 = *p++;\n    }\n\n    if (cflags & C_REL32) {\n      rel32_ok:\n        hs->flags |= F_IMM32 | F_RELATIVE;\n        hs->imm.imm32 = *(uint32_t *)p;\n        p += 4;\n    } else if (cflags & C_REL8) {\n        hs->flags |= F_IMM8 | F_RELATIVE;\n        hs->imm.imm8 = *p++;\n    }\n\n  disasm_done:\n\n    if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {\n        hs->flags |= F_ERROR | F_ERROR_LENGTH;\n        hs->len = 15;\n    }\n\n    return (unsigned int)hs->len;\n}\n\n#endif // defined(_M_X64) || defined(__x86_64__)\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/hde64.h",
    "content": "﻿/*\n * Hacker Disassembler Engine 64\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n * hde64.h: C/C++ header file\n *\n */\n\n#ifndef _HDE64_H_\n#define _HDE64_H_\n\n/* stdint.h - C99 standard header\n * http://en.wikipedia.org/wiki/stdint.h\n *\n * if your compiler doesn't contain \"stdint.h\" header (for\n * example, Microsoft Visual C++), you can download file:\n *   http://www.azillionmonkeys.com/qed/pstdint.h\n * and change next line to:\n *   #include \"pstdint.h\"\n */\n#include \"pstdint.h\"\n\n#define F_MODRM         0x00000001\n#define F_SIB           0x00000002\n#define F_IMM8          0x00000004\n#define F_IMM16         0x00000008\n#define F_IMM32         0x00000010\n#define F_IMM64         0x00000020\n#define F_DISP8         0x00000040\n#define F_DISP16        0x00000080\n#define F_DISP32        0x00000100\n#define F_RELATIVE      0x00000200\n#define F_ERROR         0x00001000\n#define F_ERROR_OPCODE  0x00002000\n#define F_ERROR_LENGTH  0x00004000\n#define F_ERROR_LOCK    0x00008000\n#define F_ERROR_OPERAND 0x00010000\n#define F_PREFIX_REPNZ  0x01000000\n#define F_PREFIX_REPX   0x02000000\n#define F_PREFIX_REP    0x03000000\n#define F_PREFIX_66     0x04000000\n#define F_PREFIX_67     0x08000000\n#define F_PREFIX_LOCK   0x10000000\n#define F_PREFIX_SEG    0x20000000\n#define F_PREFIX_REX    0x40000000\n#define F_PREFIX_ANY    0x7f000000\n\n#define PREFIX_SEGMENT_CS   0x2e\n#define PREFIX_SEGMENT_SS   0x36\n#define PREFIX_SEGMENT_DS   0x3e\n#define PREFIX_SEGMENT_ES   0x26\n#define PREFIX_SEGMENT_FS   0x64\n#define PREFIX_SEGMENT_GS   0x65\n#define PREFIX_LOCK         0xf0\n#define PREFIX_REPNZ        0xf2\n#define PREFIX_REPX         0xf3\n#define PREFIX_OPERAND_SIZE 0x66\n#define PREFIX_ADDRESS_SIZE 0x67\n\n#pragma pack(push,1)\n\ntypedef struct {\n    uint8_t len;\n    uint8_t p_rep;\n    uint8_t p_lock;\n    uint8_t p_seg;\n    uint8_t p_66;\n    uint8_t p_67;\n    uint8_t rex;\n    uint8_t rex_w;\n    uint8_t rex_r;\n    uint8_t rex_x;\n    uint8_t rex_b;\n    uint8_t opcode;\n    uint8_t opcode2;\n    uint8_t modrm;\n    uint8_t modrm_mod;\n    uint8_t modrm_reg;\n    uint8_t modrm_rm;\n    uint8_t sib;\n    uint8_t sib_scale;\n    uint8_t sib_index;\n    uint8_t sib_base;\n    union {\n        uint8_t imm8;\n        uint16_t imm16;\n        uint32_t imm32;\n        uint64_t imm64;\n    } imm;\n    union {\n        uint8_t disp8;\n        uint16_t disp16;\n        uint32_t disp32;\n    } disp;\n    uint32_t flags;\n} hde64s;\n\n#pragma pack(pop)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* __cdecl */\nunsigned int hde64_disasm(const void *code, hde64s *hs);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _HDE64_H_ */\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/pstdint.h",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *  1. Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR\n *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n#include <windows.h>\n\n// Integer types for HDE.\ntypedef INT8   int8_t;\ntypedef INT16  int16_t;\ntypedef INT32  int32_t;\ntypedef INT64  int64_t;\ntypedef UINT8  uint8_t;\ntypedef UINT16 uint16_t;\ntypedef UINT32 uint32_t;\ntypedef UINT64 uint64_t;\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/table32.h",
    "content": "﻿/*\n * Hacker Disassembler Engine 32 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#define C_NONE    0x00\n#define C_MODRM   0x01\n#define C_IMM8    0x02\n#define C_IMM16   0x04\n#define C_IMM_P66 0x10\n#define C_REL8    0x20\n#define C_REL32   0x40\n#define C_GROUP   0x80\n#define C_ERROR   0xff\n\n#define PRE_ANY  0x00\n#define PRE_NONE 0x01\n#define PRE_F2   0x02\n#define PRE_F3   0x04\n#define PRE_66   0x08\n#define PRE_67   0x10\n#define PRE_LOCK 0x20\n#define PRE_SEG  0x40\n#define PRE_ALL  0xff\n\n#define DELTA_OPCODES      0x4a\n#define DELTA_FPU_REG      0xf1\n#define DELTA_FPU_MODRM    0xf8\n#define DELTA_PREFIXES     0x130\n#define DELTA_OP_LOCK_OK   0x1a1\n#define DELTA_OP2_LOCK_OK  0x1b9\n#define DELTA_OP_ONLY_MEM  0x1cb\n#define DELTA_OP2_ONLY_MEM 0x1da\n\nunsigned char hde32_table[] = {\n  0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,\n  0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,\n  0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,\n  0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,\n  0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,\n  0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,\n  0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,\n  0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,\n  0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,\n  0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,\n  0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,\n  0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,\n  0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,\n  0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,\n  0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,\n  0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,\n  0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,\n  0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,\n  0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\n  0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\n  0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,\n  0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,\n  0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,\n  0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,\n  0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,\n  0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,\n  0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,\n  0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,\n  0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,\n  0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,\n  0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,\n  0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,\n  0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,\n  0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,\n  0xe7,0x08,0x00,0xf0,0x02,0x00\n};\n"
  },
  {
    "path": "SylantStrike/minhook/src/hde/table64.h",
    "content": "﻿/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#define C_NONE    0x00\n#define C_MODRM   0x01\n#define C_IMM8    0x02\n#define C_IMM16   0x04\n#define C_IMM_P66 0x10\n#define C_REL8    0x20\n#define C_REL32   0x40\n#define C_GROUP   0x80\n#define C_ERROR   0xff\n\n#define PRE_ANY  0x00\n#define PRE_NONE 0x01\n#define PRE_F2   0x02\n#define PRE_F3   0x04\n#define PRE_66   0x08\n#define PRE_67   0x10\n#define PRE_LOCK 0x20\n#define PRE_SEG  0x40\n#define PRE_ALL  0xff\n\n#define DELTA_OPCODES      0x4a\n#define DELTA_FPU_REG      0xfd\n#define DELTA_FPU_MODRM    0x104\n#define DELTA_PREFIXES     0x13c\n#define DELTA_OP_LOCK_OK   0x1ae\n#define DELTA_OP2_LOCK_OK  0x1c6\n#define DELTA_OP_ONLY_MEM  0x1d8\n#define DELTA_OP2_ONLY_MEM 0x1e7\n\nunsigned char hde64_table[] = {\n  0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,\n  0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,\n  0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,\n  0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,\n  0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,\n  0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,\n  0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,\n  0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,\n  0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,\n  0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,\n  0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,\n  0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,\n  0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,\n  0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,\n  0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,\n  0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,\n  0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,\n  0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,\n  0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,\n  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,\n  0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,\n  0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,\n  0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,\n  0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,\n  0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,\n  0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,\n  0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,\n  0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,\n  0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,\n  0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,\n  0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,\n  0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,\n  0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,\n  0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,\n  0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,\n  0x00,0xf0,0x02,0x00\n};\n"
  },
  {
    "path": "SylantStrike/minhook/src/hook.c",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <windows.h>\n#include <tlhelp32.h>\n#include <limits.h>\n\n#include \"../include/MinHook.h\"\n#include \"buffer.h\"\n#include \"trampoline.h\"\n\n#ifndef ARRAYSIZE\n    #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))\n#endif\n\n// Initial capacity of the HOOK_ENTRY buffer.\n#define INITIAL_HOOK_CAPACITY   32\n\n// Initial capacity of the thread IDs buffer.\n#define INITIAL_THREAD_CAPACITY 128\n\n// Special hook position values.\n#define INVALID_HOOK_POS UINT_MAX\n#define ALL_HOOKS_POS    UINT_MAX\n\n// Freeze() action argument defines.\n#define ACTION_DISABLE      0\n#define ACTION_ENABLE       1\n#define ACTION_APPLY_QUEUED 2\n\n// Thread access rights for suspending/resuming threads.\n#define THREAD_ACCESS \\\n    (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)\n\n// Hook information.\ntypedef struct _HOOK_ENTRY\n{\n    LPVOID pTarget;             // Address of the target function.\n    LPVOID pDetour;             // Address of the detour or relay function.\n    LPVOID pTrampoline;         // Address of the trampoline function.\n    UINT8  backup[8];           // Original prologue of the target function.\n\n    UINT8  patchAbove  : 1;     // Uses the hot patch area.\n    UINT8  isEnabled   : 1;     // Enabled.\n    UINT8  queueEnable : 1;     // Queued for enabling/disabling when != isEnabled.\n\n    UINT   nIP : 4;             // Count of the instruction boundaries.\n    UINT8  oldIPs[8];           // Instruction boundaries of the target function.\n    UINT8  newIPs[8];           // Instruction boundaries of the trampoline function.\n} HOOK_ENTRY, *PHOOK_ENTRY;\n\n// Suspended threads for Freeze()/Unfreeze().\ntypedef struct _FROZEN_THREADS\n{\n    LPDWORD pItems;         // Data heap\n    UINT    capacity;       // Size of allocated data heap, items\n    UINT    size;           // Actual number of data items\n} FROZEN_THREADS, *PFROZEN_THREADS;\n\n//-------------------------------------------------------------------------\n// Global Variables:\n//-------------------------------------------------------------------------\n\n// Spin lock flag for EnterSpinLock()/LeaveSpinLock().\nvolatile LONG g_isLocked = FALSE;\n\n// Private heap handle. If not NULL, this library is initialized.\nHANDLE g_hHeap = NULL;\n\n// Hook entries.\nstruct\n{\n    PHOOK_ENTRY pItems;     // Data heap\n    UINT        capacity;   // Size of allocated data heap, items\n    UINT        size;       // Actual number of data items\n} g_hooks;\n\n//-------------------------------------------------------------------------\n// Returns INVALID_HOOK_POS if not found.\nstatic UINT FindHookEntry(LPVOID pTarget)\n{\n    UINT i;\n    for (i = 0; i < g_hooks.size; ++i)\n    {\n        if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)\n            return i;\n    }\n\n    return INVALID_HOOK_POS;\n}\n\n//-------------------------------------------------------------------------\nstatic PHOOK_ENTRY AddHookEntry()\n{\n    if (g_hooks.pItems == NULL)\n    {\n        g_hooks.capacity = INITIAL_HOOK_CAPACITY;\n        g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(\n            g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));\n        if (g_hooks.pItems == NULL)\n            return NULL;\n    }\n    else if (g_hooks.size >= g_hooks.capacity)\n    {\n        PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(\n            g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));\n        if (p == NULL)\n            return NULL;\n\n        g_hooks.capacity *= 2;\n        g_hooks.pItems = p;\n    }\n\n    return &g_hooks.pItems[g_hooks.size++];\n}\n\n//-------------------------------------------------------------------------\nstatic void DeleteHookEntry(UINT pos)\n{\n    if (pos < g_hooks.size - 1)\n        g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];\n\n    g_hooks.size--;\n\n    if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)\n    {\n        PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(\n            g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));\n        if (p == NULL)\n            return;\n\n        g_hooks.capacity /= 2;\n        g_hooks.pItems = p;\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)\n{\n    UINT i;\n\n    if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))\n        return (DWORD_PTR)pHook->pTarget;\n\n    for (i = 0; i < pHook->nIP; ++i)\n    {\n        if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))\n            return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];\n    }\n\n#if defined(_M_X64) || defined(__x86_64__)\n    // Check relay function.\n    if (ip == (DWORD_PTR)pHook->pDetour)\n        return (DWORD_PTR)pHook->pTarget;\n#endif\n\n    return 0;\n}\n\n//-------------------------------------------------------------------------\nstatic DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)\n{\n    UINT i;\n    for (i = 0; i < pHook->nIP; ++i)\n    {\n        if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))\n            return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];\n    }\n\n    return 0;\n}\n\n//-------------------------------------------------------------------------\nstatic void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)\n{\n    // If the thread suspended in the overwritten area,\n    // move IP to the proper address.\n\n    CONTEXT c;\n#if defined(_M_X64) || defined(__x86_64__)\n    DWORD64 *pIP = &c.Rip;\n#else\n    DWORD   *pIP = &c.Eip;\n#endif\n    UINT count;\n\n    c.ContextFlags = CONTEXT_CONTROL;\n    if (!GetThreadContext(hThread, &c))\n        return;\n\n    if (pos == ALL_HOOKS_POS)\n    {\n        pos = 0;\n        count = g_hooks.size;\n    }\n    else\n    {\n        count = pos + 1;\n    }\n\n    for (; pos < count; ++pos)\n    {\n        PHOOK_ENTRY pHook = &g_hooks.pItems[pos];\n        BOOL        enable;\n        DWORD_PTR   ip;\n\n        switch (action)\n        {\n        case ACTION_DISABLE:\n            enable = FALSE;\n            break;\n\n        case ACTION_ENABLE:\n            enable = TRUE;\n            break;\n\n        default: // ACTION_APPLY_QUEUED\n            enable = pHook->queueEnable;\n            break;\n        }\n        if (pHook->isEnabled == enable)\n            continue;\n\n        if (enable)\n            ip = FindNewIP(pHook, *pIP);\n        else\n            ip = FindOldIP(pHook, *pIP);\n\n        if (ip != 0)\n        {\n            *pIP = ip;\n            SetThreadContext(hThread, &c);\n        }\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic VOID EnumerateThreads(PFROZEN_THREADS pThreads)\n{\n    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);\n    if (hSnapshot != INVALID_HANDLE_VALUE)\n    {\n        THREADENTRY32 te;\n        te.dwSize = sizeof(THREADENTRY32);\n        if (Thread32First(hSnapshot, &te))\n        {\n            do\n            {\n                if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))\n                    && te.th32OwnerProcessID == GetCurrentProcessId()\n                    && te.th32ThreadID != GetCurrentThreadId())\n                {\n                    if (pThreads->pItems == NULL)\n                    {\n                        pThreads->capacity = INITIAL_THREAD_CAPACITY;\n                        pThreads->pItems\n                            = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));\n                        if (pThreads->pItems == NULL)\n                            break;\n                    }\n                    else if (pThreads->size >= pThreads->capacity)\n                    {\n                        LPDWORD p = (LPDWORD)HeapReAlloc(\n                            g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));\n                        if (p == NULL)\n                            break;\n\n                        pThreads->capacity *= 2;\n                        pThreads->pItems = p;\n                    }\n                    pThreads->pItems[pThreads->size++] = te.th32ThreadID;\n                }\n\n                te.dwSize = sizeof(THREADENTRY32);\n            } while (Thread32Next(hSnapshot, &te));\n        }\n        CloseHandle(hSnapshot);\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)\n{\n    pThreads->pItems   = NULL;\n    pThreads->capacity = 0;\n    pThreads->size     = 0;\n    EnumerateThreads(pThreads);\n\n    if (pThreads->pItems != NULL)\n    {\n        UINT i;\n        for (i = 0; i < pThreads->size; ++i)\n        {\n            HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);\n            if (hThread != NULL)\n            {\n                SuspendThread(hThread);\n                ProcessThreadIPs(hThread, pos, action);\n                CloseHandle(hThread);\n            }\n        }\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic VOID Unfreeze(PFROZEN_THREADS pThreads)\n{\n    if (pThreads->pItems != NULL)\n    {\n        UINT i;\n        for (i = 0; i < pThreads->size; ++i)\n        {\n            HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);\n            if (hThread != NULL)\n            {\n                ResumeThread(hThread);\n                CloseHandle(hThread);\n            }\n        }\n\n        HeapFree(g_hHeap, 0, pThreads->pItems);\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic MH_STATUS EnableHookLL(UINT pos, BOOL enable)\n{\n    PHOOK_ENTRY pHook = &g_hooks.pItems[pos];\n    DWORD  oldProtect;\n    SIZE_T patchSize    = sizeof(JMP_REL);\n    LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;\n\n    if (pHook->patchAbove)\n    {\n        pPatchTarget -= sizeof(JMP_REL);\n        patchSize    += sizeof(JMP_REL_SHORT);\n    }\n\n    if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))\n        return MH_ERROR_MEMORY_PROTECT;\n\n    if (enable)\n    {\n        PJMP_REL pJmp = (PJMP_REL)pPatchTarget;\n        pJmp->opcode = 0xE9;\n        pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));\n\n        if (pHook->patchAbove)\n        {\n            PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;\n            pShortJmp->opcode = 0xEB;\n            pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));\n        }\n    }\n    else\n    {\n        if (pHook->patchAbove)\n            memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));\n        else\n            memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));\n    }\n\n    VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);\n\n    // Just-in-case measure.\n    FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);\n\n    pHook->isEnabled   = enable;\n    pHook->queueEnable = enable;\n\n    return MH_OK;\n}\n\n//-------------------------------------------------------------------------\nstatic MH_STATUS EnableAllHooksLL(BOOL enable)\n{\n    MH_STATUS status = MH_OK;\n    UINT i, first = INVALID_HOOK_POS;\n\n    for (i = 0; i < g_hooks.size; ++i)\n    {\n        if (g_hooks.pItems[i].isEnabled != enable)\n        {\n            first = i;\n            break;\n        }\n    }\n\n    if (first != INVALID_HOOK_POS)\n    {\n        FROZEN_THREADS threads;\n        Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);\n\n        for (i = first; i < g_hooks.size; ++i)\n        {\n            if (g_hooks.pItems[i].isEnabled != enable)\n            {\n                status = EnableHookLL(i, enable);\n                if (status != MH_OK)\n                    break;\n            }\n        }\n\n        Unfreeze(&threads);\n    }\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nstatic VOID EnterSpinLock(VOID)\n{\n    SIZE_T spinCount = 0;\n\n    // Wait until the flag is FALSE.\n    while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)\n    {\n        // No need to generate a memory barrier here, since InterlockedCompareExchange()\n        // generates a full memory barrier itself.\n\n        // Prevent the loop from being too busy.\n        if (spinCount < 32)\n            Sleep(0);\n        else\n            Sleep(1);\n\n        spinCount++;\n    }\n}\n\n//-------------------------------------------------------------------------\nstatic VOID LeaveSpinLock(VOID)\n{\n    // No need to generate a memory barrier here, since InterlockedExchange()\n    // generates a full memory barrier itself.\n\n    InterlockedExchange(&g_isLocked, FALSE);\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_Initialize(VOID)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap == NULL)\n    {\n        g_hHeap = HeapCreate(0, 0, 0);\n        if (g_hHeap != NULL)\n        {\n            // Initialize the internal function buffer.\n            InitializeBuffer();\n        }\n        else\n        {\n            status = MH_ERROR_MEMORY_ALLOC;\n        }\n    }\n    else\n    {\n        status = MH_ERROR_ALREADY_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_Uninitialize(VOID)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        status = EnableAllHooksLL(FALSE);\n        if (status == MH_OK)\n        {\n            // Free the internal function buffer.\n\n            // HeapFree is actually not required, but some tools detect a false\n            // memory leak without HeapFree.\n\n            UninitializeBuffer();\n\n            HeapFree(g_hHeap, 0, g_hooks.pItems);\n            HeapDestroy(g_hHeap);\n\n            g_hHeap = NULL;\n\n            g_hooks.pItems   = NULL;\n            g_hooks.capacity = 0;\n            g_hooks.size     = 0;\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))\n        {\n            UINT pos = FindHookEntry(pTarget);\n            if (pos == INVALID_HOOK_POS)\n            {\n                LPVOID pBuffer = AllocateBuffer(pTarget);\n                if (pBuffer != NULL)\n                {\n                    TRAMPOLINE ct;\n\n                    ct.pTarget     = pTarget;\n                    ct.pDetour     = pDetour;\n                    ct.pTrampoline = pBuffer;\n                    if (CreateTrampolineFunction(&ct))\n                    {\n                        PHOOK_ENTRY pHook = AddHookEntry();\n                        if (pHook != NULL)\n                        {\n                            pHook->pTarget     = ct.pTarget;\n#if defined(_M_X64) || defined(__x86_64__)\n                            pHook->pDetour     = ct.pRelay;\n#else\n                            pHook->pDetour     = ct.pDetour;\n#endif\n                            pHook->pTrampoline = ct.pTrampoline;\n                            pHook->patchAbove  = ct.patchAbove;\n                            pHook->isEnabled   = FALSE;\n                            pHook->queueEnable = FALSE;\n                            pHook->nIP         = ct.nIP;\n                            memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));\n                            memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));\n\n                            // Back up the target function.\n\n                            if (ct.patchAbove)\n                            {\n                                memcpy(\n                                    pHook->backup,\n                                    (LPBYTE)pTarget - sizeof(JMP_REL),\n                                    sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));\n                            }\n                            else\n                            {\n                                memcpy(pHook->backup, pTarget, sizeof(JMP_REL));\n                            }\n\n                            if (ppOriginal != NULL)\n                                *ppOriginal = pHook->pTrampoline;\n                        }\n                        else\n                        {\n                            status = MH_ERROR_MEMORY_ALLOC;\n                        }\n                    }\n                    else\n                    {\n                        status = MH_ERROR_UNSUPPORTED_FUNCTION;\n                    }\n\n                    if (status != MH_OK)\n                    {\n                        FreeBuffer(pBuffer);\n                    }\n                }\n                else\n                {\n                    status = MH_ERROR_MEMORY_ALLOC;\n                }\n            }\n            else\n            {\n                status = MH_ERROR_ALREADY_CREATED;\n            }\n        }\n        else\n        {\n            status = MH_ERROR_NOT_EXECUTABLE;\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        UINT pos = FindHookEntry(pTarget);\n        if (pos != INVALID_HOOK_POS)\n        {\n            if (g_hooks.pItems[pos].isEnabled)\n            {\n                FROZEN_THREADS threads;\n                Freeze(&threads, pos, ACTION_DISABLE);\n\n                status = EnableHookLL(pos, FALSE);\n\n                Unfreeze(&threads);\n            }\n\n            if (status == MH_OK)\n            {\n                FreeBuffer(g_hooks.pItems[pos].pTrampoline);\n                DeleteHookEntry(pos);\n            }\n        }\n        else\n        {\n            status = MH_ERROR_NOT_CREATED;\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nstatic MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        if (pTarget == MH_ALL_HOOKS)\n        {\n            status = EnableAllHooksLL(enable);\n        }\n        else\n        {\n            FROZEN_THREADS threads;\n            UINT pos = FindHookEntry(pTarget);\n            if (pos != INVALID_HOOK_POS)\n            {\n                if (g_hooks.pItems[pos].isEnabled != enable)\n                {\n                    Freeze(&threads, pos, ACTION_ENABLE);\n\n                    status = EnableHookLL(pos, enable);\n\n                    Unfreeze(&threads);\n                }\n                else\n                {\n                    status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;\n                }\n            }\n            else\n            {\n                status = MH_ERROR_NOT_CREATED;\n            }\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)\n{\n    return EnableHook(pTarget, TRUE);\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)\n{\n    return EnableHook(pTarget, FALSE);\n}\n\n//-------------------------------------------------------------------------\nstatic MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)\n{\n    MH_STATUS status = MH_OK;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        if (pTarget == MH_ALL_HOOKS)\n        {\n            UINT i;\n            for (i = 0; i < g_hooks.size; ++i)\n                g_hooks.pItems[i].queueEnable = queueEnable;\n        }\n        else\n        {\n            UINT pos = FindHookEntry(pTarget);\n            if (pos != INVALID_HOOK_POS)\n            {\n                g_hooks.pItems[pos].queueEnable = queueEnable;\n            }\n            else\n            {\n                status = MH_ERROR_NOT_CREATED;\n            }\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)\n{\n    return QueueHook(pTarget, TRUE);\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)\n{\n    return QueueHook(pTarget, FALSE);\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_ApplyQueued(VOID)\n{\n    MH_STATUS status = MH_OK;\n    UINT i, first = INVALID_HOOK_POS;\n\n    EnterSpinLock();\n\n    if (g_hHeap != NULL)\n    {\n        for (i = 0; i < g_hooks.size; ++i)\n        {\n            if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)\n            {\n                first = i;\n                break;\n            }\n        }\n\n        if (first != INVALID_HOOK_POS)\n        {\n            FROZEN_THREADS threads;\n            Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);\n\n            for (i = first; i < g_hooks.size; ++i)\n            {\n                PHOOK_ENTRY pHook = &g_hooks.pItems[i];\n                if (pHook->isEnabled != pHook->queueEnable)\n                {\n                    status = EnableHookLL(i, pHook->queueEnable);\n                    if (status != MH_OK)\n                        break;\n                }\n            }\n\n            Unfreeze(&threads);\n        }\n    }\n    else\n    {\n        status = MH_ERROR_NOT_INITIALIZED;\n    }\n\n    LeaveSpinLock();\n\n    return status;\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_CreateHookApiEx(\n    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,\n    LPVOID *ppOriginal, LPVOID *ppTarget)\n{\n    HMODULE hModule;\n    LPVOID  pTarget;\n\n    hModule = GetModuleHandleW(pszModule);\n    if (hModule == NULL)\n        return MH_ERROR_MODULE_NOT_FOUND;\n\n    pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);\n    if (pTarget == NULL)\n        return MH_ERROR_FUNCTION_NOT_FOUND;\n\n    if(ppTarget != NULL)\n        *ppTarget = pTarget;\n\n    return MH_CreateHook(pTarget, pDetour, ppOriginal);\n}\n\n//-------------------------------------------------------------------------\nMH_STATUS WINAPI MH_CreateHookApi(\n    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)\n{\n   return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);\n}\n\n//-------------------------------------------------------------------------\nconst char * WINAPI MH_StatusToString(MH_STATUS status)\n{\n#define MH_ST2STR(x)    \\\n    case x:             \\\n        return #x;\n\n    switch (status) {\n        MH_ST2STR(MH_UNKNOWN)\n        MH_ST2STR(MH_OK)\n        MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)\n        MH_ST2STR(MH_ERROR_NOT_INITIALIZED)\n        MH_ST2STR(MH_ERROR_ALREADY_CREATED)\n        MH_ST2STR(MH_ERROR_NOT_CREATED)\n        MH_ST2STR(MH_ERROR_ENABLED)\n        MH_ST2STR(MH_ERROR_DISABLED)\n        MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)\n        MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)\n        MH_ST2STR(MH_ERROR_MEMORY_ALLOC)\n        MH_ST2STR(MH_ERROR_MEMORY_PROTECT)\n        MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)\n        MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)\n    }\n\n#undef MH_ST2STR\n\n    return \"(unknown)\";\n}\n"
  },
  {
    "path": "SylantStrike/minhook/src/trampoline.c",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <windows.h>\n\n#ifndef ARRAYSIZE\n    #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))\n#endif\n\n#if defined(_M_X64) || defined(__x86_64__)\n    #include \"./hde/hde64.h\"\n    typedef hde64s HDE;\n    #define HDE_DISASM(code, hs) hde64_disasm(code, hs)\n#else\n    #include \"./hde/hde32.h\"\n    typedef hde32s HDE;\n    #define HDE_DISASM(code, hs) hde32_disasm(code, hs)\n#endif\n\n#include \"trampoline.h\"\n#include \"buffer.h\"\n\n// Maximum size of a trampoline function.\n#if defined(_M_X64) || defined(__x86_64__)\n    #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))\n#else\n    #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE\n#endif\n\n//-------------------------------------------------------------------------\nstatic BOOL IsCodePadding(LPBYTE pInst, UINT size)\n{\n    UINT i;\n\n    if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)\n        return FALSE;\n\n    for (i = 1; i < size; ++i)\n    {\n        if (pInst[i] != pInst[0])\n            return FALSE;\n    }\n    return TRUE;\n}\n\n//-------------------------------------------------------------------------\nBOOL CreateTrampolineFunction(PTRAMPOLINE ct)\n{\n#if defined(_M_X64) || defined(__x86_64__)\n    CALL_ABS call = {\n        0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]\n        0xEB, 0x08,             // EB 08:         JMP +10\n        0x0000000000000000ULL   // Absolute destination address\n    };\n    JMP_ABS jmp = {\n        0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]\n        0x0000000000000000ULL   // Absolute destination address\n    };\n    JCC_ABS jcc = {\n        0x70, 0x0E,             // 7* 0E:         J** +16\n        0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]\n        0x0000000000000000ULL   // Absolute destination address\n    };\n#else\n    CALL_REL call = {\n        0xE8,                   // E8 xxxxxxxx: CALL +5+xxxxxxxx\n        0x00000000              // Relative destination address\n    };\n    JMP_REL jmp = {\n        0xE9,                   // E9 xxxxxxxx: JMP +5+xxxxxxxx\n        0x00000000              // Relative destination address\n    };\n    JCC_REL jcc = {\n        0x0F, 0x80,             // 0F8* xxxxxxxx: J** +6+xxxxxxxx\n        0x00000000              // Relative destination address\n    };\n#endif\n\n    UINT8     oldPos   = 0;\n    UINT8     newPos   = 0;\n    ULONG_PTR jmpDest  = 0;     // Destination address of an internal jump.\n    BOOL      finished = FALSE; // Is the function completed?\n#if defined(_M_X64) || defined(__x86_64__)\n    UINT8     instBuf[16];\n#endif\n\n    ct->patchAbove = FALSE;\n    ct->nIP        = 0;\n\n    do\n    {\n        HDE       hs;\n        UINT      copySize;\n        LPVOID    pCopySrc;\n        ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget     + oldPos;\n        ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;\n\n        copySize = HDE_DISASM((LPVOID)pOldInst, &hs);\n        if (hs.flags & F_ERROR)\n            return FALSE;\n\n        pCopySrc = (LPVOID)pOldInst;\n        if (oldPos >= sizeof(JMP_REL))\n        {\n            // The trampoline function is long enough.\n            // Complete the function with the jump to the target function.\n#if defined(_M_X64) || defined(__x86_64__)\n            jmp.address = pOldInst;\n#else\n            jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));\n#endif\n            pCopySrc = &jmp;\n            copySize = sizeof(jmp);\n\n            finished = TRUE;\n        }\n#if defined(_M_X64) || defined(__x86_64__)\n        else if ((hs.modrm & 0xC7) == 0x05)\n        {\n            // Instructions using RIP relative addressing. (ModR/M = 00???101B)\n\n            // Modify the RIP relative address.\n            PUINT32 pRelAddr;\n\n            // Avoid using memcpy to reduce the footprint.\n#ifndef _MSC_VER\n            memcpy(instBuf, (LPBYTE)pOldInst, copySize);\n#else\n            __movsb(instBuf, (LPBYTE)pOldInst, copySize);\n#endif\n            pCopySrc = instBuf;\n\n            // Relative address is stored at (instruction length - immediate value length - 4).\n            pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);\n            *pRelAddr\n                = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));\n\n            // Complete the function if JMP (FF /4).\n            if (hs.opcode == 0xFF && hs.modrm_reg == 4)\n                finished = TRUE;\n        }\n#endif\n        else if (hs.opcode == 0xE8)\n        {\n            // Direct relative CALL\n            ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;\n#if defined(_M_X64) || defined(__x86_64__)\n            call.address = dest;\n#else\n            call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));\n#endif\n            pCopySrc = &call;\n            copySize = sizeof(call);\n        }\n        else if ((hs.opcode & 0xFD) == 0xE9)\n        {\n            // Direct relative JMP (EB or E9)\n            ULONG_PTR dest = pOldInst + hs.len;\n\n            if (hs.opcode == 0xEB) // isShort jmp\n                dest += (INT8)hs.imm.imm8;\n            else\n                dest += (INT32)hs.imm.imm32;\n\n            // Simply copy an internal jump.\n            if ((ULONG_PTR)ct->pTarget <= dest\n                && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))\n            {\n                if (jmpDest < dest)\n                    jmpDest = dest;\n            }\n            else\n            {\n#if defined(_M_X64) || defined(__x86_64__)\n                jmp.address = dest;\n#else\n                jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));\n#endif\n                pCopySrc = &jmp;\n                copySize = sizeof(jmp);\n\n                // Exit the function If it is not in the branch\n                finished = (pOldInst >= jmpDest);\n            }\n        }\n        else if ((hs.opcode & 0xF0) == 0x70\n            || (hs.opcode & 0xFC) == 0xE0\n            || (hs.opcode2 & 0xF0) == 0x80)\n        {\n            // Direct relative Jcc\n            ULONG_PTR dest = pOldInst + hs.len;\n\n            if ((hs.opcode & 0xF0) == 0x70      // Jcc\n                || (hs.opcode & 0xFC) == 0xE0)  // LOOPNZ/LOOPZ/LOOP/JECXZ\n                dest += (INT8)hs.imm.imm8;\n            else\n                dest += (INT32)hs.imm.imm32;\n\n            // Simply copy an internal jump.\n            if ((ULONG_PTR)ct->pTarget <= dest\n                && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))\n            {\n                if (jmpDest < dest)\n                    jmpDest = dest;\n            }\n            else if ((hs.opcode & 0xFC) == 0xE0)\n            {\n                // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.\n                return FALSE;\n            }\n            else\n            {\n                UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);\n#if defined(_M_X64) || defined(__x86_64__)\n                // Invert the condition in x64 mode to simplify the conditional jump logic.\n                jcc.opcode  = 0x71 ^ cond;\n                jcc.address = dest;\n#else\n                jcc.opcode1 = 0x80 | cond;\n                jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));\n#endif\n                pCopySrc = &jcc;\n                copySize = sizeof(jcc);\n            }\n        }\n        else if ((hs.opcode & 0xFE) == 0xC2)\n        {\n            // RET (C2 or C3)\n\n            // Complete the function if not in a branch.\n            finished = (pOldInst >= jmpDest);\n        }\n\n        // Can't alter the instruction length in a branch.\n        if (pOldInst < jmpDest && copySize != hs.len)\n            return FALSE;\n\n        // Trampoline function is too large.\n        if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)\n            return FALSE;\n\n        // Trampoline function has too many instructions.\n        if (ct->nIP >= ARRAYSIZE(ct->oldIPs))\n            return FALSE;\n\n        ct->oldIPs[ct->nIP] = oldPos;\n        ct->newIPs[ct->nIP] = newPos;\n        ct->nIP++;\n\n        // Avoid using memcpy to reduce the footprint.\n#ifndef _MSC_VER\n        memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);\n#else\n        __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);\n#endif\n        newPos += copySize;\n        oldPos += hs.len;\n    }\n    while (!finished);\n\n    // Is there enough place for a long jump?\n    if (oldPos < sizeof(JMP_REL)\n        && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))\n    {\n        // Is there enough place for a short jump?\n        if (oldPos < sizeof(JMP_REL_SHORT)\n            && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))\n        {\n            return FALSE;\n        }\n\n        // Can we place the long jump above the function?\n        if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))\n            return FALSE;\n\n        if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))\n            return FALSE;\n\n        ct->patchAbove = TRUE;\n    }\n\n#if defined(_M_X64) || defined(__x86_64__)\n    // Create a relay function.\n    jmp.address = (ULONG_PTR)ct->pDetour;\n\n    ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;\n    memcpy(ct->pRelay, &jmp, sizeof(jmp));\n#endif\n\n    return TRUE;\n}\n"
  },
  {
    "path": "SylantStrike/minhook/src/trampoline.h",
    "content": "﻿/*\n *  MinHook - The Minimalistic API Hooking Library for x64/x86\n *  Copyright (C) 2009-2017 Tsuda Kageyu.\n *  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions\n *  are met:\n *\n *   1. Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *   2. Redistributions in binary form must reproduce the above copyright\n *      notice, this list of conditions and the following disclaimer in the\n *      documentation and/or other materials provided with the distribution.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n *  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n#pragma pack(push, 1)\n\n// Structs for writing x86/x64 instructions.\n\n// 8-bit relative jump.\ntypedef struct _JMP_REL_SHORT\n{\n    UINT8  opcode;      // EB xx: JMP +2+xx\n    UINT8  operand;\n} JMP_REL_SHORT, *PJMP_REL_SHORT;\n\n// 32-bit direct relative jump/call.\ntypedef struct _JMP_REL\n{\n    UINT8  opcode;      // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx\n    UINT32 operand;     // Relative destination address\n} JMP_REL, *PJMP_REL, CALL_REL;\n\n// 64-bit indirect absolute jump.\ntypedef struct _JMP_ABS\n{\n    UINT8  opcode0;     // FF25 00000000: JMP [+6]\n    UINT8  opcode1;\n    UINT32 dummy;\n    UINT64 address;     // Absolute destination address\n} JMP_ABS, *PJMP_ABS;\n\n// 64-bit indirect absolute call.\ntypedef struct _CALL_ABS\n{\n    UINT8  opcode0;     // FF15 00000002: CALL [+6]\n    UINT8  opcode1;\n    UINT32 dummy0;\n    UINT8  dummy1;      // EB 08:         JMP +10\n    UINT8  dummy2;\n    UINT64 address;     // Absolute destination address\n} CALL_ABS;\n\n// 32-bit direct relative conditional jumps.\ntypedef struct _JCC_REL\n{\n    UINT8  opcode0;     // 0F8* xxxxxxxx: J** +6+xxxxxxxx\n    UINT8  opcode1;\n    UINT32 operand;     // Relative destination address\n} JCC_REL;\n\n// 64bit indirect absolute conditional jumps that x64 lacks.\ntypedef struct _JCC_ABS\n{\n    UINT8  opcode;      // 7* 0E:         J** +16\n    UINT8  dummy0;\n    UINT8  dummy1;      // FF25 00000000: JMP [+6]\n    UINT8  dummy2;\n    UINT32 dummy3;\n    UINT64 address;     // Absolute destination address\n} JCC_ABS;\n\n#pragma pack(pop)\n\ntypedef struct _TRAMPOLINE\n{\n    LPVOID pTarget;         // [In] Address of the target function.\n    LPVOID pDetour;         // [In] Address of the detour function.\n    LPVOID pTrampoline;     // [In] Buffer address for the trampoline and relay function.\n\n#if defined(_M_X64) || defined(__x86_64__)\n    LPVOID pRelay;          // [Out] Address of the relay function.\n#endif\n    BOOL   patchAbove;      // [Out] Should use the hot patch area?\n    UINT   nIP;             // [Out] Number of the instruction boundaries.\n    UINT8  oldIPs[8];       // [Out] Instruction boundaries of the target function.\n    UINT8  newIPs[8];       // [Out] Instruction boundaries of the trampoline function.\n} TRAMPOLINE, *PTRAMPOLINE;\n\nBOOL CreateTrampolineFunction(PTRAMPOLINE ct);\n"
  },
  {
    "path": "SylantStrike/pch.cpp",
    "content": "// pch.cpp: source file corresponding to the pre-compiled header\n\n#include \"pch.h\"\n\n// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.\n"
  },
  {
    "path": "SylantStrike/pch.h",
    "content": "// pch.h: This is a precompiled header file.\n// Files listed below are compiled only once, improving build performance for future builds.\n// This also affects IntelliSense performance, including code completion and many code browsing features.\n// However, files listed here are ALL re-compiled if any one of them is updated between builds.\n// Do not add files here that you will be updating frequently as this negates the performance advantage.\n\n#ifndef PCH_H\n#define PCH_H\n\n// add headers that you want to pre-compile here\n#include \"framework.h\"\n\n#endif //PCH_H\n"
  },
  {
    "path": "SylantStrike.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SylantStrike\", \"SylantStrike\\SylantStrike.vcxproj\", \"{1DDD15AA-D837-4143-A272-0E08F9ED6C40}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"SylantStrikeInject\", \"SylantStrikeInject\\SylantStrikeInject.csproj\", \"{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.Build.0 = Debug|x64\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.Build.0 = Debug|Win32\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.ActiveCfg = Release|x64\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.Build.0 = Release|x64\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.ActiveCfg = Release|Win32\n\t\t{1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.Build.0 = Release|Win32\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {C38993BA-BB45-4062-BD3E-AC155D4A3C84}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "SylantStrikeInject/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.5\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "SylantStrikeInject/BasicInject.cs",
    "content": "﻿//Based on code from https://codingvision.net/security/c-inject-a-dll-into-a-process-w-createremotethread\n\nusing System;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\npublic class BasicInject {\n    [DllImport(\"kernel32.dll\")]\n    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);\n\n    [DllImport(\"kernel32.dll\", CharSet = CharSet.Auto)]\n    public static extern IntPtr GetModuleHandle(string lpModuleName);\n\n    [DllImport(\"kernel32\", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]\n    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);\n\n    [DllImport(\"kernel32.dll\", SetLastError = true, ExactSpelling = true)]\n    static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,\n        uint dwSize, uint flAllocationType, uint flProtect);\n\n    [DllImport(\"kernel32.dll\", SetLastError = true)]\n    static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);\n\n    [DllImport(\"kernel32.dll\")]\n    static extern IntPtr CreateRemoteThread(IntPtr hProcess,\n        IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\n\n    // privileges\n    const int PROCESS_CREATE_THREAD = 0x0002;\n    const int PROCESS_QUERY_INFORMATION = 0x0400;\n    const int PROCESS_VM_OPERATION = 0x0008;\n    const int PROCESS_VM_WRITE = 0x0020;\n    const int PROCESS_VM_READ = 0x0010;\n\n    // used for memory allocation\n    const uint MEM_COMMIT = 0x00001000;\n    const uint MEM_RESERVE = 0x00002000;\n    const uint PAGE_READWRITE = 4;\n\n    public static int Inject(int pid, string dllName) {\n\n        // geting the handle of the process - with required privileges\n        IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, pid);\n\n        // searching for the address of LoadLibraryA and storing it in a pointer\n        IntPtr loadLibraryAddr = GetProcAddress(GetModuleHandle(\"kernel32.dll\"), \"LoadLibraryA\");\n\n        // alocating some memory on the target process - enough to store the name of the dll\n        // and storing its address in a pointer\n        IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\n\n        // writing the name of the dll there\n        UIntPtr bytesWritten;\n        WriteProcessMemory(procHandle, allocMemAddress, Encoding.ASCII.GetBytes(dllName), (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten);\n\n        // creating a thread that will call LoadLibraryA with allocMemAddress as argument\n        CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);\n\n        return 0;\n    }\n}"
  },
  {
    "path": "SylantStrikeInject/Options.cs",
    "content": "﻿//\n// Options.cs\n//\n// Authors:\n//  Jonathan Pryor <jpryor@novell.com>, <Jonathan.Pryor@microsoft.com>\n//  Federico Di Gregorio <fog@initd.org>\n//  Rolf Bjarne Kvinge <rolf@xamarin.com>\n//\n// Copyright (C) 2008 Novell (http://www.novell.com)\n// Copyright (C) 2009 Federico Di Gregorio.\n// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)\n// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n\n// Compile With:\n//   mcs -debug+ -r:System.Core Options.cs -o:Mono.Options.dll -t:library\n//   mcs -debug+ -d:LINQ -r:System.Core Options.cs -o:Mono.Options.dll -t:library\n//\n// The LINQ version just changes the implementation of\n// OptionSet.Parse(IEnumerable<string>), and confers no semantic changes.\n\n//\n// A Getopt::Long-inspired option parsing library for C#.\n//\n// Mono.Options.OptionSet is built upon a key/value table, where the\n// key is a option format string and the value is a delegate that is \n// invoked when the format string is matched.\n//\n// Option format strings:\n//  Regex-like BNF Grammar: \n//    name: .+\n//    type: [=:]\n//    sep: ( [^{}]+ | '{' .+ '}' )?\n//    aliases: ( name type sep ) ( '|' name type sep )*\n// \n// Each '|'-delimited name is an alias for the associated action.  If the\n// format string ends in a '=', it has a required value.  If the format\n// string ends in a ':', it has an optional value.  If neither '=' or ':'\n// is present, no value is supported.  `=' or `:' need only be defined on one\n// alias, but if they are provided on more than one they must be consistent.\n//\n// Each alias portion may also end with a \"key/value separator\", which is used\n// to split option values if the option accepts > 1 value.  If not specified,\n// it defaults to '=' and ':'.  If specified, it can be any character except\n// '{' and '}' OR the *string* between '{' and '}'.  If no separator should be\n// used (i.e. the separate values should be distinct arguments), then \"{}\"\n// should be used as the separator.\n//\n// Options are extracted either from the current option by looking for\n// the option name followed by an '=' or ':', or is taken from the\n// following option IFF:\n//  - The current option does not contain a '=' or a ':'\n//  - The current option requires a value (i.e. not a Option type of ':')\n//\n// The `name' used in the option format string does NOT include any leading\n// option indicator, such as '-', '--', or '/'.  All three of these are\n// permitted/required on any named option.\n//\n// Option bundling is permitted so long as:\n//   - '-' is used to start the option group\n//   - all of the bundled options are a single character\n//   - at most one of the bundled options accepts a value, and the value\n//     provided starts from the next character to the end of the string.\n//\n// This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value'\n// as '-Dname=value'.\n//\n// Option processing is disabled by specifying \"--\".  All options after \"--\"\n// are returned by OptionSet.Parse() unchanged and unprocessed.\n//\n// Unprocessed options are returned from OptionSet.Parse().\n//\n// Examples:\n//  int verbose = 0;\n//  OptionSet p = new OptionSet ()\n//    .Add (\"v\", v => ++verbose)\n//    .Add (\"name=|value=\", v => Console.WriteLine (v));\n//  p.Parse (new string[]{\"-v\", \"--v\", \"/v\", \"-name=A\", \"/name\", \"B\", \"extra\"});\n//\n// The above would parse the argument string array, and would invoke the\n// lambda expression three times, setting `verbose' to 3 when complete.  \n// It would also print out \"A\" and \"B\" to standard output.\n// The returned array would contain the string \"extra\".\n//\n// C# 3.0 collection initializers are supported and encouraged:\n//  var p = new OptionSet () {\n//    { \"h|?|help\", v => ShowHelp () },\n//  };\n//\n// System.ComponentModel.TypeConverter is also supported, allowing the use of\n// custom data types in the callback type; TypeConverter.ConvertFromString()\n// is used to convert the value option to an instance of the specified\n// type:\n//\n//  var p = new OptionSet () {\n//    { \"foo=\", (Foo f) => Console.WriteLine (f.ToString ()) },\n//  };\n//\n// Random other tidbits:\n//  - Boolean options (those w/o '=' or ':' in the option format string)\n//    are explicitly enabled if they are followed with '+', and explicitly\n//    disabled if they are followed with '-':\n//      string a = null;\n//      var p = new OptionSet () {\n//        { \"a\", s => a = s },\n//      };\n//      p.Parse (new string[]{\"-a\"});   // sets v != null\n//      p.Parse (new string[]{\"-a+\"});  // sets v != null\n//      p.Parse (new string[]{\"-a-\"});  // sets v == null\n//\n\n//\n// Mono.Options.CommandSet allows easily having separate commands and\n// associated command options, allowing creation of a *suite* along the\n// lines of **git**(1), **svn**(1), etc.\n//\n// CommandSet allows intermixing plain text strings for `--help` output,\n// Option values -- as supported by OptionSet -- and Command instances,\n// which have a name, optional help text, and an optional OptionSet.\n//\n//  var suite = new CommandSet (\"suite-name\") {\n//    // Use strings and option values, as with OptionSet\n//    \"usage: suite-name COMMAND [OPTIONS]+\",\n//    { \"v:\", \"verbosity\", (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity+1 },\n//    // Commands may also be specified\n//    new Command (\"command-name\", \"command help\") {\n//      Options = new OptionSet {/*...*/},\n//      Run     = args => { /*...*/},\n//    },\n//    new MyCommandSubclass (),\n//  };\n//  return suite.Run (new string[]{...});\n//\n// CommandSet provides a `help` command, and forwards `help COMMAND`\n// to the registered Command instance by invoking Command.Invoke()\n// with `--help` as an option.\n//\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.ComponentModel;\nusing System.Globalization;\nusing System.IO;\n#if PCL\nusing System.Reflection;\n#else\nusing System.Runtime.Serialization;\nusing System.Security.Permissions;\n#endif\nusing System.Text;\nusing System.Text.RegularExpressions;\n\n#if LINQ\nusing System.Linq;\n#endif\n\n#if TEST\nusing NDesk.Options;\n#endif\n\n#if PCL\nusing MessageLocalizerConverter = System.Func<string, string>;\n#else\nusing MessageLocalizerConverter = System.Converter<string, string>;\n#endif\n\n#if NDESK_OPTIONS\nnamespace NDesk.Options\n#else\nnamespace Mono.Options\n#endif\n{\n    static class StringCoda {\n\n        public static IEnumerable<string> WrappedLines(string self, params int[] widths) {\n            IEnumerable<int> w = widths;\n            return WrappedLines(self, w);\n        }\n\n        public static IEnumerable<string> WrappedLines(string self, IEnumerable<int> widths) {\n            if (widths == null)\n                throw new ArgumentNullException(\"widths\");\n            return CreateWrappedLinesIterator(self, widths);\n        }\n\n        private static IEnumerable<string> CreateWrappedLinesIterator(string self, IEnumerable<int> widths) {\n            if (string.IsNullOrEmpty(self)) {\n                yield return string.Empty;\n                yield break;\n            }\n            using (IEnumerator<int> ewidths = widths.GetEnumerator()) {\n                bool? hw = null;\n                int width = GetNextWidth(ewidths, int.MaxValue, ref hw);\n                int start = 0, end;\n                do {\n                    end = GetLineEnd(start, width, self);\n                    // endCorrection is 1 if the line end is '\\n', and might be 2 if the line end is '\\r\\n'.\n                    int endCorrection = 1;\n                    if (end >= 2 && self.Substring(end - 2, 2).Equals(\"\\r\\n\"))\n                        endCorrection = 2;\n                    char c = self[end - endCorrection];\n                    if (char.IsWhiteSpace(c))\n                        end -= endCorrection;\n                    bool needContinuation = end != self.Length && !IsEolChar(c);\n                    string continuation = \"\";\n                    if (needContinuation) {\n                        --end;\n                        continuation = \"-\";\n                    }\n                    string line = self.Substring(start, end - start) + continuation;\n                    yield return line;\n                    start = end;\n                    if (char.IsWhiteSpace(c))\n                        start += endCorrection;\n                    width = GetNextWidth(ewidths, width, ref hw);\n                } while (start < self.Length);\n            }\n        }\n\n        private static int GetNextWidth(IEnumerator<int> ewidths, int curWidth, ref bool? eValid) {\n            if (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {\n                curWidth = (eValid = ewidths.MoveNext()).Value ? ewidths.Current : curWidth;\n                // '.' is any character, - is for a continuation\n                const string minWidth = \".-\";\n                if (curWidth < minWidth.Length)\n                    throw new ArgumentOutOfRangeException(\"widths\",\n                            string.Format(\"Element must be >= {0}, was {1}.\", minWidth.Length, curWidth));\n                return curWidth;\n            }\n            // no more elements, use the last element.\n            return curWidth;\n        }\n\n        private static bool IsEolChar(char c) {\n            return !char.IsLetterOrDigit(c);\n        }\n\n        private static int GetLineEnd(int start, int length, string description) {\n            int end = System.Math.Min(start + length, description.Length);\n            int sep = -1;\n            for (int i = start; i < end; ++i) {\n                if (i + 2 <= description.Length && description.Substring(i, 2).Equals(\"\\r\\n\"))\n                    return i + 2;\n                if (description[i] == '\\n')\n                    return i + 1;\n                if (IsEolChar(description[i]))\n                    sep = i + 1;\n            }\n            if (sep == -1 || end == description.Length)\n                return end;\n            return sep;\n        }\n    }\n\n    public class OptionValueCollection : IList, IList<string> {\n\n        List<string> values = new List<string>();\n        OptionContext c;\n\n        internal OptionValueCollection(OptionContext c) {\n            this.c = c;\n        }\n\n        #region ICollection\n        void ICollection.CopyTo(Array array, int index) { (values as ICollection).CopyTo(array, index); }\n        bool ICollection.IsSynchronized { get { return (values as ICollection).IsSynchronized; } }\n        object ICollection.SyncRoot { get { return (values as ICollection).SyncRoot; } }\n        #endregion\n\n        #region ICollection<T>\n        public void Add(string item) { values.Add(item); }\n        public void Clear() { values.Clear(); }\n        public bool Contains(string item) { return values.Contains(item); }\n        public void CopyTo(string[] array, int arrayIndex) { values.CopyTo(array, arrayIndex); }\n        public bool Remove(string item) { return values.Remove(item); }\n        public int Count { get { return values.Count; } }\n        public bool IsReadOnly { get { return false; } }\n        #endregion\n\n        #region IEnumerable\n        IEnumerator IEnumerable.GetEnumerator() { return values.GetEnumerator(); }\n        #endregion\n\n        #region IEnumerable<T>\n        public IEnumerator<string> GetEnumerator() { return values.GetEnumerator(); }\n        #endregion\n\n        #region IList\n        int IList.Add(object value) { return (values as IList).Add(value); }\n        bool IList.Contains(object value) { return (values as IList).Contains(value); }\n        int IList.IndexOf(object value) { return (values as IList).IndexOf(value); }\n        void IList.Insert(int index, object value) { (values as IList).Insert(index, value); }\n        void IList.Remove(object value) { (values as IList).Remove(value); }\n        void IList.RemoveAt(int index) { (values as IList).RemoveAt(index); }\n        bool IList.IsFixedSize { get { return false; } }\n        object IList.this[int index] { get { return this[index]; } set { (values as IList)[index] = value; } }\n        #endregion\n\n        #region IList<T>\n        public int IndexOf(string item) { return values.IndexOf(item); }\n        public void Insert(int index, string item) { values.Insert(index, item); }\n        public void RemoveAt(int index) { values.RemoveAt(index); }\n\n        private void AssertValid(int index) {\n            if (c.Option == null)\n                throw new InvalidOperationException(\"OptionContext.Option is null.\");\n            if (index >= c.Option.MaxValueCount)\n                throw new ArgumentOutOfRangeException(\"index\");\n            if (c.Option.OptionValueType == OptionValueType.Required &&\n                    index >= values.Count)\n                throw new OptionException(string.Format(\n                            c.OptionSet.MessageLocalizer(\"Missing required value for option '{0}'.\"), c.OptionName),\n                        c.OptionName);\n        }\n\n        public string this[int index] {\n            get {\n                AssertValid(index);\n                return index >= values.Count ? null : values[index];\n            }\n            set {\n                values[index] = value;\n            }\n        }\n        #endregion\n\n        public List<string> ToList() {\n            return new List<string>(values);\n        }\n\n        public string[] ToArray() {\n            return values.ToArray();\n        }\n\n        public override string ToString() {\n            return string.Join(\", \", values.ToArray());\n        }\n    }\n\n    public class OptionContext {\n        private Option option;\n        private string name;\n        private int index;\n        private OptionSet set;\n        private OptionValueCollection c;\n\n        public OptionContext(OptionSet set) {\n            this.set = set;\n            this.c = new OptionValueCollection(this);\n        }\n\n        public Option Option {\n            get { return option; }\n            set { option = value; }\n        }\n\n        public string OptionName {\n            get { return name; }\n            set { name = value; }\n        }\n\n        public int OptionIndex {\n            get { return index; }\n            set { index = value; }\n        }\n\n        public OptionSet OptionSet {\n            get { return set; }\n        }\n\n        public OptionValueCollection OptionValues {\n            get { return c; }\n        }\n    }\n\n    public enum OptionValueType {\n        None,\n        Optional,\n        Required,\n    }\n\n    public abstract class Option {\n        string prototype, description;\n        string[] names;\n        OptionValueType type;\n        int count;\n        string[] separators;\n        bool hidden;\n\n        protected Option(string prototype, string description)\n            : this(prototype, description, 1, false) {\n        }\n\n        protected Option(string prototype, string description, int maxValueCount)\n            : this(prototype, description, maxValueCount, false) {\n        }\n\n        protected Option(string prototype, string description, int maxValueCount, bool hidden) {\n            if (prototype == null)\n                throw new ArgumentNullException(\"prototype\");\n            if (prototype.Length == 0)\n                throw new ArgumentException(\"Cannot be the empty string.\", \"prototype\");\n            if (maxValueCount < 0)\n                throw new ArgumentOutOfRangeException(\"maxValueCount\");\n\n            this.prototype = prototype;\n            this.description = description;\n            this.count = maxValueCount;\n            this.names = (this is OptionSet.Category)\n                // append GetHashCode() so that \"duplicate\" categories have distinct\n                // names, e.g. adding multiple \"\" categories should be valid.\n                ? new[] { prototype + this.GetHashCode() }\n                : prototype.Split('|');\n\n            if (this is OptionSet.Category || this is CommandOption)\n                return;\n\n            this.type = ParsePrototype();\n            this.hidden = hidden;\n\n            if (this.count == 0 && type != OptionValueType.None)\n                throw new ArgumentException(\n                        \"Cannot provide maxValueCount of 0 for OptionValueType.Required or \" +\n                            \"OptionValueType.Optional.\",\n                        \"maxValueCount\");\n            if (this.type == OptionValueType.None && maxValueCount > 1)\n                throw new ArgumentException(\n                        string.Format(\"Cannot provide maxValueCount of {0} for OptionValueType.None.\", maxValueCount),\n                        \"maxValueCount\");\n            if (Array.IndexOf(names, \"<>\") >= 0 &&\n                    ((names.Length == 1 && this.type != OptionValueType.None) ||\n                     (names.Length > 1 && this.MaxValueCount > 1)))\n                throw new ArgumentException(\n                        \"The default option handler '<>' cannot require values.\",\n                        \"prototype\");\n        }\n\n        public string Prototype { get { return prototype; } }\n        public string Description { get { return description; } }\n        public OptionValueType OptionValueType { get { return type; } }\n        public int MaxValueCount { get { return count; } }\n        public bool Hidden { get { return hidden; } }\n\n        public string[] GetNames() {\n            return (string[])names.Clone();\n        }\n\n        public string[] GetValueSeparators() {\n            if (separators == null)\n                return new string[0];\n            return (string[])separators.Clone();\n        }\n\n        protected static T Parse<T>(string value, OptionContext c) {\n            Type tt = typeof(T);\n#if PCL\n\t\t\tTypeInfo ti = tt.GetTypeInfo ();\n#else\n            Type ti = tt;\n#endif\n            bool nullable =\n                ti.IsValueType &&\n                ti.IsGenericType &&\n                !ti.IsGenericTypeDefinition &&\n                ti.GetGenericTypeDefinition() == typeof(Nullable<>);\n#if PCL\n\t\t\tType targetType = nullable ? tt.GenericTypeArguments [0] : tt;\n#else\n            Type targetType = nullable ? tt.GetGenericArguments()[0] : tt;\n#endif\n            T t = default(T);\n            try {\n                if (value != null) {\n#if PCL\n\t\t\t\t\tif (targetType.GetTypeInfo ().IsEnum)\n\t\t\t\t\t\tt = (T) Enum.Parse (targetType, value, true);\n\t\t\t\t\telse\n\t\t\t\t\t\tt = (T) Convert.ChangeType (value, targetType);\n#else\n                    TypeConverter conv = TypeDescriptor.GetConverter(targetType);\n                    t = (T)conv.ConvertFromString(value);\n#endif\n                }\n            } catch (Exception e) {\n                throw new OptionException(\n                        string.Format(\n                            c.OptionSet.MessageLocalizer(\"Could not convert string `{0}' to type {1} for option `{2}'.\"),\n                            value, targetType.Name, c.OptionName),\n                        c.OptionName, e);\n            }\n            return t;\n        }\n\n        internal string[] Names { get { return names; } }\n        internal string[] ValueSeparators { get { return separators; } }\n\n        static readonly char[] NameTerminator = new char[] { '=', ':' };\n\n        private OptionValueType ParsePrototype() {\n            char type = '\\0';\n            List<string> seps = new List<string>();\n            for (int i = 0; i < names.Length; ++i) {\n                string name = names[i];\n                if (name.Length == 0)\n                    throw new ArgumentException(\"Empty option names are not supported.\", \"prototype\");\n\n                int end = name.IndexOfAny(NameTerminator);\n                if (end == -1)\n                    continue;\n                names[i] = name.Substring(0, end);\n                if (type == '\\0' || type == name[end])\n                    type = name[end];\n                else\n                    throw new ArgumentException(\n                            string.Format(\"Conflicting option types: '{0}' vs. '{1}'.\", type, name[end]),\n                            \"prototype\");\n                AddSeparators(name, end, seps);\n            }\n\n            if (type == '\\0')\n                return OptionValueType.None;\n\n            if (count <= 1 && seps.Count != 0)\n                throw new ArgumentException(\n                        string.Format(\"Cannot provide key/value separators for Options taking {0} value(s).\", count),\n                        \"prototype\");\n            if (count > 1) {\n                if (seps.Count == 0)\n                    this.separators = new string[] { \":\", \"=\" };\n                else if (seps.Count == 1 && seps[0].Length == 0)\n                    this.separators = null;\n                else\n                    this.separators = seps.ToArray();\n            }\n\n            return type == '=' ? OptionValueType.Required : OptionValueType.Optional;\n        }\n\n        private static void AddSeparators(string name, int end, ICollection<string> seps) {\n            int start = -1;\n            for (int i = end + 1; i < name.Length; ++i) {\n                switch (name[i]) {\n                    case '{':\n                        if (start != -1)\n                            throw new ArgumentException(\n                                    string.Format(\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n                                    \"prototype\");\n                        start = i + 1;\n                        break;\n                    case '}':\n                        if (start == -1)\n                            throw new ArgumentException(\n                                    string.Format(\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n                                    \"prototype\");\n                        seps.Add(name.Substring(start, i - start));\n                        start = -1;\n                        break;\n                    default:\n                        if (start == -1)\n                            seps.Add(name[i].ToString());\n                        break;\n                }\n            }\n            if (start != -1)\n                throw new ArgumentException(\n                        string.Format(\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n                        \"prototype\");\n        }\n\n        public void Invoke(OptionContext c) {\n            OnParseComplete(c);\n            c.OptionName = null;\n            c.Option = null;\n            c.OptionValues.Clear();\n        }\n\n        protected abstract void OnParseComplete(OptionContext c);\n\n        internal void InvokeOnParseComplete(OptionContext c) {\n            OnParseComplete(c);\n        }\n\n        public override string ToString() {\n            return Prototype;\n        }\n    }\n\n    public abstract class ArgumentSource {\n\n        protected ArgumentSource() {\n        }\n\n        public abstract string[] GetNames();\n        public abstract string Description { get; }\n        public abstract bool GetArguments(string value, out IEnumerable<string> replacement);\n\n#if !PCL || NETSTANDARD1_3\n        public static IEnumerable<string> GetArgumentsFromFile(string file) {\n            return GetArguments(File.OpenText(file), true);\n        }\n#endif\n\n        public static IEnumerable<string> GetArguments(TextReader reader) {\n            return GetArguments(reader, false);\n        }\n\n        // Cribbed from mcs/driver.cs:LoadArgs(string)\n        static IEnumerable<string> GetArguments(TextReader reader, bool close) {\n            try {\n                StringBuilder arg = new StringBuilder();\n\n                string line;\n                while ((line = reader.ReadLine()) != null) {\n                    int t = line.Length;\n\n                    for (int i = 0; i < t; i++) {\n                        char c = line[i];\n\n                        if (c == '\"' || c == '\\'') {\n                            char end = c;\n\n                            for (i++; i < t; i++) {\n                                c = line[i];\n\n                                if (c == end)\n                                    break;\n                                arg.Append(c);\n                            }\n                        } else if (c == ' ') {\n                            if (arg.Length > 0) {\n                                yield return arg.ToString();\n                                arg.Length = 0;\n                            }\n                        } else\n                            arg.Append(c);\n                    }\n                    if (arg.Length > 0) {\n                        yield return arg.ToString();\n                        arg.Length = 0;\n                    }\n                }\n            } finally {\n                if (close)\n                    reader.Dispose();\n            }\n        }\n    }\n\n#if !PCL || NETSTANDARD1_3\n    internal class ResponseFileSource : ArgumentSource {\n\n        public override string[] GetNames() {\n            return new string[] { \"@file\" };\n        }\n\n        public override string Description {\n            get { return \"Read response file for more options.\"; }\n        }\n\n        public override bool GetArguments(string value, out IEnumerable<string> replacement) {\n            if (string.IsNullOrEmpty(value) || !value.StartsWith(\"@\")) {\n                replacement = null;\n                return false;\n            }\n            replacement = ArgumentSource.GetArgumentsFromFile(value.Substring(1));\n            return true;\n        }\n    }\n#endif\n\n#if !PCL\n    [Serializable]\n#endif\n    internal class OptionException : Exception {\n        private string option;\n\n        public OptionException() {\n        }\n\n        public OptionException(string message, string optionName)\n            : base(message) {\n            this.option = optionName;\n        }\n\n        public OptionException(string message, string optionName, Exception innerException)\n            : base(message, innerException) {\n            this.option = optionName;\n        }\n\n#if !PCL\n        protected OptionException(SerializationInfo info, StreamingContext context)\n            : base(info, context) {\n            this.option = info.GetString(\"OptionName\");\n        }\n#endif\n\n        public string OptionName {\n            get { return this.option; }\n        }\n\n#if !PCL\n#pragma warning disable 618 // SecurityPermissionAttribute is obsolete\n        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]\n#pragma warning restore 618\n        public override void GetObjectData(SerializationInfo info, StreamingContext context) {\n            base.GetObjectData(info, context);\n            info.AddValue(\"OptionName\", option);\n        }\n#endif\n    }\n\n    public delegate void OptionAction<TKey, TValue>(TKey key, TValue value);\n\n    public class OptionSet : KeyedCollection<string, Option> {\n        public OptionSet()\n            : this(null) {\n        }\n\n        public OptionSet(MessageLocalizerConverter localizer) {\n            this.roSources = new ReadOnlyCollection<ArgumentSource>(sources);\n            this.localizer = localizer;\n            if (this.localizer == null) {\n                this.localizer = delegate (string f) {\n                    return f;\n                };\n            }\n        }\n\n        MessageLocalizerConverter localizer;\n\n        public MessageLocalizerConverter MessageLocalizer {\n            get { return localizer; }\n            internal set { localizer = value; }\n        }\n\n        List<ArgumentSource> sources = new List<ArgumentSource>();\n        ReadOnlyCollection<ArgumentSource> roSources;\n\n        public ReadOnlyCollection<ArgumentSource> ArgumentSources {\n            get { return roSources; }\n        }\n\n\n        protected override string GetKeyForItem(Option item) {\n            if (item == null)\n                throw new ArgumentNullException(\"option\");\n            if (item.Names != null && item.Names.Length > 0)\n                return item.Names[0];\n            // This should never happen, as it's invalid for Option to be\n            // constructed w/o any names.\n            throw new InvalidOperationException(\"Option has no names!\");\n        }\n\n        [Obsolete(\"Use KeyedCollection.this[string]\")]\n        protected Option GetOptionForName(string option) {\n            if (option == null)\n                throw new ArgumentNullException(\"option\");\n            try {\n                return base[option];\n            } catch (KeyNotFoundException) {\n                return null;\n            }\n        }\n\n        protected override void InsertItem(int index, Option item) {\n            base.InsertItem(index, item);\n            AddImpl(item);\n        }\n\n        protected override void RemoveItem(int index) {\n            Option p = Items[index];\n            base.RemoveItem(index);\n            // KeyedCollection.RemoveItem() handles the 0th item\n            for (int i = 1; i < p.Names.Length; ++i) {\n                Dictionary.Remove(p.Names[i]);\n            }\n        }\n\n        protected override void SetItem(int index, Option item) {\n            base.SetItem(index, item);\n            AddImpl(item);\n        }\n\n        private void AddImpl(Option option) {\n            if (option == null)\n                throw new ArgumentNullException(\"option\");\n            List<string> added = new List<string>(option.Names.Length);\n            try {\n                // KeyedCollection.InsertItem/SetItem handle the 0th name.\n                for (int i = 1; i < option.Names.Length; ++i) {\n                    Dictionary.Add(option.Names[i], option);\n                    added.Add(option.Names[i]);\n                }\n            } catch (Exception) {\n                foreach (string name in added)\n                    Dictionary.Remove(name);\n                throw;\n            }\n        }\n\n        public OptionSet Add(string header) {\n            if (header == null)\n                throw new ArgumentNullException(\"header\");\n            Add(new Category(header));\n            return this;\n        }\n\n        internal sealed class Category : Option {\n\n            // Prototype starts with '=' because this is an invalid prototype\n            // (see Option.ParsePrototype(), and thus it'll prevent Category\n            // instances from being accidentally used as normal options.\n            public Category(string description)\n                : base(\"=:Category:= \" + description, description) {\n            }\n\n            protected override void OnParseComplete(OptionContext c) {\n                throw new NotSupportedException(\"Category.OnParseComplete should not be invoked.\");\n            }\n        }\n\n\n        public new OptionSet Add(Option option) {\n            base.Add(option);\n            return this;\n        }\n\n        sealed class ActionOption : Option {\n            Action<OptionValueCollection> action;\n\n            public ActionOption(string prototype, string description, int count, Action<OptionValueCollection> action)\n                : this(prototype, description, count, action, false) {\n            }\n\n            public ActionOption(string prototype, string description, int count, Action<OptionValueCollection> action, bool hidden)\n                : base(prototype, description, count, hidden) {\n                if (action == null)\n                    throw new ArgumentNullException(\"action\");\n                this.action = action;\n            }\n\n            protected override void OnParseComplete(OptionContext c) {\n                action(c.OptionValues);\n            }\n        }\n\n        public OptionSet Add(string prototype, Action<string> action) {\n            return Add(prototype, null, action);\n        }\n\n        public OptionSet Add(string prototype, string description, Action<string> action) {\n            return Add(prototype, description, action, false);\n        }\n\n        public OptionSet Add(string prototype, string description, Action<string> action, bool hidden) {\n            if (action == null)\n                throw new ArgumentNullException(\"action\");\n            Option p = new ActionOption(prototype, description, 1,\n                    delegate (OptionValueCollection v) { action(v[0]); }, hidden);\n            base.Add(p);\n            return this;\n        }\n\n        public OptionSet Add(string prototype, OptionAction<string, string> action) {\n            return Add(prototype, null, action);\n        }\n\n        public OptionSet Add(string prototype, string description, OptionAction<string, string> action) {\n            return Add(prototype, description, action, false);\n        }\n\n        public OptionSet Add(string prototype, string description, OptionAction<string, string> action, bool hidden) {\n            if (action == null)\n                throw new ArgumentNullException(\"action\");\n            Option p = new ActionOption(prototype, description, 2,\n                    delegate (OptionValueCollection v) { action(v[0], v[1]); }, hidden);\n            base.Add(p);\n            return this;\n        }\n\n        sealed class ActionOption<T> : Option {\n            Action<T> action;\n\n            public ActionOption(string prototype, string description, Action<T> action)\n                : base(prototype, description, 1) {\n                if (action == null)\n                    throw new ArgumentNullException(\"action\");\n                this.action = action;\n            }\n\n            protected override void OnParseComplete(OptionContext c) {\n                action(Parse<T>(c.OptionValues[0], c));\n            }\n        }\n\n        sealed class ActionOption<TKey, TValue> : Option {\n            OptionAction<TKey, TValue> action;\n\n            public ActionOption(string prototype, string description, OptionAction<TKey, TValue> action)\n                : base(prototype, description, 2) {\n                if (action == null)\n                    throw new ArgumentNullException(\"action\");\n                this.action = action;\n            }\n\n            protected override void OnParseComplete(OptionContext c) {\n                action(\n                        Parse<TKey>(c.OptionValues[0], c),\n                        Parse<TValue>(c.OptionValues[1], c));\n            }\n        }\n\n        public OptionSet Add<T>(string prototype, Action<T> action) {\n            return Add(prototype, null, action);\n        }\n\n        public OptionSet Add<T>(string prototype, string description, Action<T> action) {\n            return Add(new ActionOption<T>(prototype, description, action));\n        }\n\n        public OptionSet Add<TKey, TValue>(string prototype, OptionAction<TKey, TValue> action) {\n            return Add(prototype, null, action);\n        }\n\n        public OptionSet Add<TKey, TValue>(string prototype, string description, OptionAction<TKey, TValue> action) {\n            return Add(new ActionOption<TKey, TValue>(prototype, description, action));\n        }\n\n        public OptionSet Add(ArgumentSource source) {\n            if (source == null)\n                throw new ArgumentNullException(\"source\");\n            sources.Add(source);\n            return this;\n        }\n\n        protected virtual OptionContext CreateOptionContext() {\n            return new OptionContext(this);\n        }\n\n        public List<string> Parse(IEnumerable<string> arguments) {\n            if (arguments == null)\n                throw new ArgumentNullException(\"arguments\");\n            OptionContext c = CreateOptionContext();\n            c.OptionIndex = -1;\n            bool process = true;\n            List<string> unprocessed = new List<string>();\n            Option def = Contains(\"<>\") ? this[\"<>\"] : null;\n            ArgumentEnumerator ae = new ArgumentEnumerator(arguments);\n            foreach (string argument in ae) {\n                ++c.OptionIndex;\n                if (argument == \"--\") {\n                    process = false;\n                    continue;\n                }\n                if (!process) {\n                    Unprocessed(unprocessed, def, c, argument);\n                    continue;\n                }\n                if (AddSource(ae, argument))\n                    continue;\n                if (!Parse(argument, c))\n                    Unprocessed(unprocessed, def, c, argument);\n            }\n            if (c.Option != null)\n                c.Option.Invoke(c);\n            return unprocessed;\n        }\n\n        class ArgumentEnumerator : IEnumerable<string> {\n            List<IEnumerator<string>> sources = new List<IEnumerator<string>>();\n\n            public ArgumentEnumerator(IEnumerable<string> arguments) {\n                sources.Add(arguments.GetEnumerator());\n            }\n\n            public void Add(IEnumerable<string> arguments) {\n                sources.Add(arguments.GetEnumerator());\n            }\n\n            public IEnumerator<string> GetEnumerator() {\n                do {\n                    IEnumerator<string> c = sources[sources.Count - 1];\n                    if (c.MoveNext())\n                        yield return c.Current;\n                    else {\n                        c.Dispose();\n                        sources.RemoveAt(sources.Count - 1);\n                    }\n                } while (sources.Count > 0);\n            }\n\n            IEnumerator IEnumerable.GetEnumerator() {\n                return GetEnumerator();\n            }\n        }\n\n        bool AddSource(ArgumentEnumerator ae, string argument) {\n            foreach (ArgumentSource source in sources) {\n                IEnumerable<string> replacement;\n                if (!source.GetArguments(argument, out replacement))\n                    continue;\n                ae.Add(replacement);\n                return true;\n            }\n            return false;\n        }\n\n        private static bool Unprocessed(ICollection<string> extra, Option def, OptionContext c, string argument) {\n            if (def == null) {\n                extra.Add(argument);\n                return false;\n            }\n            c.OptionValues.Add(argument);\n            c.Option = def;\n            c.Option.Invoke(c);\n            return false;\n        }\n\n        private readonly Regex ValueOption = new Regex(\n            @\"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$\");\n\n        protected bool GetOptionParts(string argument, out string flag, out string name, out string sep, out string value) {\n            if (argument == null)\n                throw new ArgumentNullException(\"argument\");\n\n            flag = name = sep = value = null;\n            Match m = ValueOption.Match(argument);\n            if (!m.Success) {\n                return false;\n            }\n            flag = m.Groups[\"flag\"].Value;\n            name = m.Groups[\"name\"].Value;\n            if (m.Groups[\"sep\"].Success && m.Groups[\"value\"].Success) {\n                sep = m.Groups[\"sep\"].Value;\n                value = m.Groups[\"value\"].Value;\n            }\n            return true;\n        }\n\n        protected virtual bool Parse(string argument, OptionContext c) {\n            if (c.Option != null) {\n                ParseValue(argument, c);\n                return true;\n            }\n\n            string f, n, s, v;\n            if (!GetOptionParts(argument, out f, out n, out s, out v))\n                return false;\n\n            Option p;\n            if (Contains(n)) {\n                p = this[n];\n                c.OptionName = f + n;\n                c.Option = p;\n                switch (p.OptionValueType) {\n                    case OptionValueType.None:\n                        c.OptionValues.Add(n);\n                        c.Option.Invoke(c);\n                        break;\n                    case OptionValueType.Optional:\n                    case OptionValueType.Required:\n                        ParseValue(v, c);\n                        break;\n                }\n                return true;\n            }\n            // no match; is it a bool option?\n            if (ParseBool(argument, n, c))\n                return true;\n            // is it a bundled option?\n            if (ParseBundledValue(f, string.Concat(n + s + v), c))\n                return true;\n\n            return false;\n        }\n\n        private void ParseValue(string option, OptionContext c) {\n            if (option != null)\n                foreach (string o in c.Option.ValueSeparators != null\n                        ? option.Split(c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)\n                        : new string[] { option }) {\n                    c.OptionValues.Add(o);\n                }\n            if (c.OptionValues.Count == c.Option.MaxValueCount ||\n                    c.Option.OptionValueType == OptionValueType.Optional)\n                c.Option.Invoke(c);\n            else if (c.OptionValues.Count > c.Option.MaxValueCount) {\n                throw new OptionException(localizer(string.Format(\n                                \"Error: Found {0} option values when expecting {1}.\",\n                                c.OptionValues.Count, c.Option.MaxValueCount)),\n                        c.OptionName);\n            }\n        }\n\n        private bool ParseBool(string option, string n, OptionContext c) {\n            Option p;\n            string rn;\n            if (n.Length >= 1 && (n[n.Length - 1] == '+' || n[n.Length - 1] == '-') &&\n                    Contains((rn = n.Substring(0, n.Length - 1)))) {\n                p = this[rn];\n                string v = n[n.Length - 1] == '+' ? option : null;\n                c.OptionName = option;\n                c.Option = p;\n                c.OptionValues.Add(v);\n                p.Invoke(c);\n                return true;\n            }\n            return false;\n        }\n\n        private bool ParseBundledValue(string f, string n, OptionContext c) {\n            if (f != \"-\")\n                return false;\n            for (int i = 0; i < n.Length; ++i) {\n                Option p;\n                string opt = f + n[i].ToString();\n                string rn = n[i].ToString();\n                if (!Contains(rn)) {\n                    if (i == 0)\n                        return false;\n                    throw new OptionException(string.Format(localizer(\n                                    \"Cannot use unregistered option '{0}' in bundle '{1}'.\"), rn, f + n), null);\n                }\n                p = this[rn];\n                switch (p.OptionValueType) {\n                    case OptionValueType.None:\n                        Invoke(c, opt, n, p);\n                        break;\n                    case OptionValueType.Optional:\n                    case OptionValueType.Required: {\n                            string v = n.Substring(i + 1);\n                            c.Option = p;\n                            c.OptionName = opt;\n                            ParseValue(v.Length != 0 ? v : null, c);\n                            return true;\n                        }\n                    default:\n                        throw new InvalidOperationException(\"Unknown OptionValueType: \" + p.OptionValueType);\n                }\n            }\n            return true;\n        }\n\n        private static void Invoke(OptionContext c, string name, string value, Option option) {\n            c.OptionName = name;\n            c.Option = option;\n            c.OptionValues.Add(value);\n            option.Invoke(c);\n        }\n\n        private const int OptionWidth = 29;\n        private const int Description_FirstWidth = 80 - OptionWidth;\n        private const int Description_RemWidth = 80 - OptionWidth - 2;\n\n        static readonly string CommandHelpIndentStart = new string(' ', OptionWidth);\n        static readonly string CommandHelpIndentRemaining = new string(' ', OptionWidth + 2);\n\n        public void WriteOptionDescriptions(TextWriter o) {\n            foreach (Option p in this) {\n                int written = 0;\n\n                if (p.Hidden)\n                    continue;\n\n                Category c = p as Category;\n                if (c != null) {\n                    WriteDescription(o, p.Description, \"\", 80, 80);\n                    continue;\n                }\n                CommandOption co = p as CommandOption;\n                if (co != null) {\n                    WriteCommandDescription(o, co.Command, co.CommandName);\n                    continue;\n                }\n\n                if (!WriteOptionPrototype(o, p, ref written))\n                    continue;\n\n                if (written < OptionWidth)\n                    o.Write(new string(' ', OptionWidth - written));\n                else {\n                    o.WriteLine();\n                    o.Write(new string(' ', OptionWidth));\n                }\n\n                WriteDescription(o, p.Description, new string(' ', OptionWidth + 2),\n                        Description_FirstWidth, Description_RemWidth);\n            }\n\n            foreach (ArgumentSource s in sources) {\n                string[] names = s.GetNames();\n                if (names == null || names.Length == 0)\n                    continue;\n\n                int written = 0;\n\n                Write(o, ref written, \"  \");\n                Write(o, ref written, names[0]);\n                for (int i = 1; i < names.Length; ++i) {\n                    Write(o, ref written, \", \");\n                    Write(o, ref written, names[i]);\n                }\n\n                if (written < OptionWidth)\n                    o.Write(new string(' ', OptionWidth - written));\n                else {\n                    o.WriteLine();\n                    o.Write(new string(' ', OptionWidth));\n                }\n\n                WriteDescription(o, s.Description, new string(' ', OptionWidth + 2),\n                        Description_FirstWidth, Description_RemWidth);\n            }\n        }\n\n        internal void WriteCommandDescription(TextWriter o, Command c, string commandName) {\n            var name = new string(' ', 8) + (commandName ?? c.Name);\n            if (name.Length < OptionWidth - 1) {\n                WriteDescription(o, name + new string(' ', OptionWidth - name.Length) + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);\n            } else {\n                WriteDescription(o, name, \"\", 80, 80);\n                WriteDescription(o, CommandHelpIndentStart + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);\n            }\n        }\n\n        void WriteDescription(TextWriter o, string value, string prefix, int firstWidth, int remWidth) {\n            bool indent = false;\n            foreach (string line in GetLines(localizer(GetDescription(value)), firstWidth, remWidth)) {\n                if (indent)\n                    o.Write(prefix);\n                o.WriteLine(line);\n                indent = true;\n            }\n        }\n\n        bool WriteOptionPrototype(TextWriter o, Option p, ref int written) {\n            string[] names = p.Names;\n\n            int i = GetNextOptionIndex(names, 0);\n            if (i == names.Length)\n                return false;\n\n            if (names[i].Length == 1) {\n                Write(o, ref written, \"  -\");\n                Write(o, ref written, names[0]);\n            } else {\n                Write(o, ref written, \"      --\");\n                Write(o, ref written, names[0]);\n            }\n\n            for (i = GetNextOptionIndex(names, i + 1);\n                    i < names.Length; i = GetNextOptionIndex(names, i + 1)) {\n                Write(o, ref written, \", \");\n                Write(o, ref written, names[i].Length == 1 ? \"-\" : \"--\");\n                Write(o, ref written, names[i]);\n            }\n\n            if (p.OptionValueType == OptionValueType.Optional ||\n                    p.OptionValueType == OptionValueType.Required) {\n                if (p.OptionValueType == OptionValueType.Optional) {\n                    Write(o, ref written, localizer(\"[\"));\n                }\n                Write(o, ref written, localizer(\"=\" + GetArgumentName(0, p.MaxValueCount, p.Description)));\n                string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0\n                    ? p.ValueSeparators[0]\n                    : \" \";\n                for (int c = 1; c < p.MaxValueCount; ++c) {\n                    Write(o, ref written, localizer(sep + GetArgumentName(c, p.MaxValueCount, p.Description)));\n                }\n                if (p.OptionValueType == OptionValueType.Optional) {\n                    Write(o, ref written, localizer(\"]\"));\n                }\n            }\n            return true;\n        }\n\n        static int GetNextOptionIndex(string[] names, int i) {\n            while (i < names.Length && names[i] == \"<>\") {\n                ++i;\n            }\n            return i;\n        }\n\n        static void Write(TextWriter o, ref int n, string s) {\n            n += s.Length;\n            o.Write(s);\n        }\n\n        static string GetArgumentName(int index, int maxIndex, string description) {\n            var matches = Regex.Matches(description ?? \"\", @\"(?<=(?<!\\{)\\{)[^{}]*(?=\\}(?!\\}))\"); // ignore double braces \n            string argName = \"\";\n            foreach (Match match in matches) {\n                var parts = match.Value.Split(':');\n                // for maxIndex=1 it can be {foo} or {0:foo}\n                if (maxIndex == 1) {\n                    argName = parts[parts.Length - 1];\n                }\n                // look for {i:foo} if maxIndex > 1\n                if (maxIndex > 1 && parts.Length == 2 &&\n                    parts[0] == index.ToString(CultureInfo.InvariantCulture)) {\n                    argName = parts[1];\n                }\n            }\n\n            if (string.IsNullOrEmpty(argName)) {\n                argName = maxIndex == 1 ? \"VALUE\" : \"VALUE\" + (index + 1);\n            }\n            return argName;\n        }\n\n        private static string GetDescription(string description) {\n            if (description == null)\n                return string.Empty;\n            StringBuilder sb = new StringBuilder(description.Length);\n            int start = -1;\n            for (int i = 0; i < description.Length; ++i) {\n                switch (description[i]) {\n                    case '{':\n                        if (i == start) {\n                            sb.Append('{');\n                            start = -1;\n                        } else if (start < 0)\n                            start = i + 1;\n                        break;\n                    case '}':\n                        if (start < 0) {\n                            if ((i + 1) == description.Length || description[i + 1] != '}')\n                                throw new InvalidOperationException(\"Invalid option description: \" + description);\n                            ++i;\n                            sb.Append(\"}\");\n                        } else {\n                            sb.Append(description.Substring(start, i - start));\n                            start = -1;\n                        }\n                        break;\n                    case ':':\n                        if (start < 0)\n                            goto default;\n                        start = i + 1;\n                        break;\n                    default:\n                        if (start < 0)\n                            sb.Append(description[i]);\n                        break;\n                }\n            }\n            return sb.ToString();\n        }\n\n        private static IEnumerable<string> GetLines(string description, int firstWidth, int remWidth) {\n            return StringCoda.WrappedLines(description, firstWidth, remWidth);\n        }\n    }\n\n    internal class Command {\n        public string Name { get; }\n        public string Help { get; }\n\n        public OptionSet Options { get; set; }\n        public Action<IEnumerable<string>> Run { get; set; }\n\n        public CommandSet CommandSet { get; internal set; }\n\n        public Command(string name, string help = null) {\n            if (string.IsNullOrEmpty(name))\n                throw new ArgumentNullException(nameof(name));\n\n            Name = NormalizeCommandName(name);\n            Help = help;\n        }\n\n        static string NormalizeCommandName(string name) {\n            var value = new StringBuilder(name.Length);\n            var space = false;\n            for (int i = 0; i < name.Length; ++i) {\n                if (!char.IsWhiteSpace(name, i)) {\n                    space = false;\n                    value.Append(name[i]);\n                } else if (!space) {\n                    space = true;\n                    value.Append(' ');\n                }\n            }\n            return value.ToString();\n        }\n\n        public virtual int Invoke(IEnumerable<string> arguments) {\n            var rest = Options?.Parse(arguments) ?? arguments;\n            Run?.Invoke(rest);\n            return 0;\n        }\n    }\n\n    class CommandOption : Option {\n        public Command Command { get; }\n        public string CommandName { get; }\n\n        // Prototype starts with '=' because this is an invalid prototype\n        // (see Option.ParsePrototype(), and thus it'll prevent Category\n        // instances from being accidentally used as normal options.\n        public CommandOption(Command command, string commandName = null, bool hidden = false)\n            : base(\"=:Command:= \" + (commandName ?? command?.Name), (commandName ?? command?.Name), maxValueCount: 0, hidden: hidden) {\n            if (command == null)\n                throw new ArgumentNullException(nameof(command));\n            Command = command;\n            CommandName = commandName ?? command.Name;\n        }\n\n        protected override void OnParseComplete(OptionContext c) {\n            throw new NotSupportedException(\"CommandOption.OnParseComplete should not be invoked.\");\n        }\n    }\n\n    class HelpOption : Option {\n        Option option;\n        CommandSet commands;\n\n        public HelpOption(CommandSet commands, Option d)\n            : base(d.Prototype, d.Description, d.MaxValueCount, d.Hidden) {\n            this.commands = commands;\n            this.option = d;\n        }\n\n        protected override void OnParseComplete(OptionContext c) {\n            commands.showHelp = true;\n\n            option?.InvokeOnParseComplete(c);\n        }\n    }\n\n    class CommandOptionSet : OptionSet {\n        CommandSet commands;\n\n        public CommandOptionSet(CommandSet commands, MessageLocalizerConverter localizer)\n            : base(localizer) {\n            this.commands = commands;\n        }\n\n        protected override void SetItem(int index, Option item) {\n            if (ShouldWrapOption(item)) {\n                base.SetItem(index, new HelpOption(commands, item));\n                return;\n            }\n            base.SetItem(index, item);\n        }\n\n        bool ShouldWrapOption(Option item) {\n            if (item == null)\n                return false;\n            var help = item as HelpOption;\n            if (help != null)\n                return false;\n            foreach (var n in item.Names) {\n                if (n == \"help\")\n                    return true;\n            }\n            return false;\n        }\n\n        protected override void InsertItem(int index, Option item) {\n            if (ShouldWrapOption(item)) {\n                base.InsertItem(index, new HelpOption(commands, item));\n                return;\n            }\n            base.InsertItem(index, item);\n        }\n    }\n\n    internal class CommandSet : KeyedCollection<string, Command> {\n        readonly string suite;\n\n        OptionSet options;\n        TextWriter outWriter;\n        TextWriter errorWriter;\n\n        internal List<CommandSet> NestedCommandSets;\n\n        internal HelpCommand help;\n\n        internal bool showHelp;\n\n        internal OptionSet Options => options;\n\n#if !PCL || NETSTANDARD1_3\n        public CommandSet(string suite, MessageLocalizerConverter localizer = null)\n            : this(suite, Console.Out, Console.Error, localizer) {\n        }\n#endif\n\n        public CommandSet(string suite, TextWriter output, TextWriter error, MessageLocalizerConverter localizer = null) {\n            if (suite == null)\n                throw new ArgumentNullException(nameof(suite));\n            if (output == null)\n                throw new ArgumentNullException(nameof(output));\n            if (error == null)\n                throw new ArgumentNullException(nameof(error));\n\n            this.suite = suite;\n            options = new CommandOptionSet(this, localizer);\n            outWriter = output;\n            errorWriter = error;\n        }\n\n        public string Suite => suite;\n        public TextWriter Out => outWriter;\n        public TextWriter Error => errorWriter;\n        public MessageLocalizerConverter MessageLocalizer => options.MessageLocalizer;\n\n        protected override string GetKeyForItem(Command item) {\n            return item?.Name;\n        }\n\n        public new CommandSet Add(Command value) {\n            if (value == null)\n                throw new ArgumentNullException(nameof(value));\n            AddCommand(value);\n            options.Add(new CommandOption(value));\n            return this;\n        }\n\n        void AddCommand(Command value) {\n            if (value.CommandSet != null && value.CommandSet != this) {\n                throw new ArgumentException(\"Command instances can only be added to a single CommandSet.\", nameof(value));\n            }\n            value.CommandSet = this;\n            if (value.Options != null) {\n                value.Options.MessageLocalizer = options.MessageLocalizer;\n            }\n\n            base.Add(value);\n\n            help = help ?? value as HelpCommand;\n        }\n\n        public CommandSet Add(string header) {\n            options.Add(header);\n            return this;\n        }\n\n        public CommandSet Add(Option option) {\n            options.Add(option);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, Action<string> action) {\n            options.Add(prototype, action);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, string description, Action<string> action) {\n            options.Add(prototype, description, action);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, string description, Action<string> action, bool hidden) {\n            options.Add(prototype, description, action, hidden);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, OptionAction<string, string> action) {\n            options.Add(prototype, action);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, string description, OptionAction<string, string> action) {\n            options.Add(prototype, description, action);\n            return this;\n        }\n\n        public CommandSet Add(string prototype, string description, OptionAction<string, string> action, bool hidden) {\n            options.Add(prototype, description, action, hidden);\n            return this;\n        }\n\n        public CommandSet Add<T>(string prototype, Action<T> action) {\n            options.Add(prototype, null, action);\n            return this;\n        }\n\n        public CommandSet Add<T>(string prototype, string description, Action<T> action) {\n            options.Add(prototype, description, action);\n            return this;\n        }\n\n        public CommandSet Add<TKey, TValue>(string prototype, OptionAction<TKey, TValue> action) {\n            options.Add(prototype, action);\n            return this;\n        }\n\n        public CommandSet Add<TKey, TValue>(string prototype, string description, OptionAction<TKey, TValue> action) {\n            options.Add(prototype, description, action);\n            return this;\n        }\n\n        public CommandSet Add(ArgumentSource source) {\n            options.Add(source);\n            return this;\n        }\n\n        public CommandSet Add(CommandSet nestedCommands) {\n            if (nestedCommands == null)\n                throw new ArgumentNullException(nameof(nestedCommands));\n\n            if (NestedCommandSets == null) {\n                NestedCommandSets = new List<CommandSet>();\n            }\n\n            if (!AlreadyAdded(nestedCommands)) {\n                NestedCommandSets.Add(nestedCommands);\n                foreach (var o in nestedCommands.options) {\n                    if (o is CommandOption c) {\n                        options.Add(new CommandOption(c.Command, $\"{nestedCommands.Suite} {c.CommandName}\"));\n                    } else {\n                        options.Add(o);\n                    }\n                }\n            }\n\n            nestedCommands.options = this.options;\n            nestedCommands.outWriter = this.outWriter;\n            nestedCommands.errorWriter = this.errorWriter;\n\n            return this;\n        }\n\n        bool AlreadyAdded(CommandSet value) {\n            if (value == this)\n                return true;\n            if (NestedCommandSets == null)\n                return false;\n            foreach (var nc in NestedCommandSets) {\n                if (nc.AlreadyAdded(value))\n                    return true;\n            }\n            return false;\n        }\n\n        public IEnumerable<string> GetCompletions(string prefix = null) {\n            string rest;\n            ExtractToken(ref prefix, out rest);\n\n            foreach (var command in this) {\n                if (command.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {\n                    yield return command.Name;\n                }\n            }\n\n            if (NestedCommandSets == null)\n                yield break;\n\n            foreach (var subset in NestedCommandSets) {\n                if (subset.Suite.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {\n                    foreach (var c in subset.GetCompletions(rest)) {\n                        yield return $\"{subset.Suite} {c}\";\n                    }\n                }\n            }\n        }\n\n        static void ExtractToken(ref string input, out string rest) {\n            rest = \"\";\n            input = input ?? \"\";\n\n            int top = input.Length;\n            for (int i = 0; i < top; i++) {\n                if (char.IsWhiteSpace(input[i]))\n                    continue;\n\n                for (int j = i; j < top; j++) {\n                    if (char.IsWhiteSpace(input[j])) {\n                        rest = input.Substring(j).Trim();\n                        input = input.Substring(i, j).Trim();\n                        return;\n                    }\n                }\n                rest = \"\";\n                if (i != 0)\n                    input = input.Substring(i).Trim();\n                return;\n            }\n        }\n\n        public int Run(IEnumerable<string> arguments) {\n            if (arguments == null)\n                throw new ArgumentNullException(nameof(arguments));\n\n            this.showHelp = false;\n            if (help == null) {\n                help = new HelpCommand();\n                AddCommand(help);\n            }\n            Action<string> setHelp = v => showHelp = v != null;\n            if (!options.Contains(\"help\")) {\n                options.Add(\"help\", \"\", setHelp, hidden: true);\n            }\n            if (!options.Contains(\"?\")) {\n                options.Add(\"?\", \"\", setHelp, hidden: true);\n            }\n            var extra = options.Parse(arguments);\n            if (extra.Count == 0) {\n                if (showHelp) {\n                    return help.Invoke(extra);\n                }\n                Out.WriteLine(options.MessageLocalizer($\"Use `{Suite} help` for usage.\"));\n                return 1;\n            }\n            var command = GetCommand(extra);\n            if (command == null) {\n                help.WriteUnknownCommand(extra[0]);\n                return 1;\n            }\n            if (showHelp) {\n                if (command.Options?.Contains(\"help\") ?? true) {\n                    extra.Add(\"--help\");\n                    return command.Invoke(extra);\n                }\n                command.Options.WriteOptionDescriptions(Out);\n                return 0;\n            }\n            return command.Invoke(extra);\n        }\n\n        internal Command GetCommand(List<string> extra) {\n            return TryGetLocalCommand(extra) ?? TryGetNestedCommand(extra);\n        }\n\n        Command TryGetLocalCommand(List<string> extra) {\n            var name = extra[0];\n            if (Contains(name)) {\n                extra.RemoveAt(0);\n                return this[name];\n            }\n            for (int i = 1; i < extra.Count; ++i) {\n                name = name + \" \" + extra[i];\n                if (!Contains(name))\n                    continue;\n                extra.RemoveRange(0, i + 1);\n                return this[name];\n            }\n            return null;\n        }\n\n        Command TryGetNestedCommand(List<string> extra) {\n            if (NestedCommandSets == null)\n                return null;\n\n            var nestedCommands = NestedCommandSets.Find(c => c.Suite == extra[0]);\n            if (nestedCommands == null)\n                return null;\n\n            var extraCopy = new List<string>(extra);\n            extraCopy.RemoveAt(0);\n            if (extraCopy.Count == 0)\n                return null;\n\n            var command = nestedCommands.GetCommand(extraCopy);\n            if (command != null) {\n                extra.Clear();\n                extra.AddRange(extraCopy);\n                return command;\n            }\n            return null;\n        }\n    }\n\n    internal class HelpCommand : Command {\n        public HelpCommand()\n            : base(\"help\", help: \"Show this message and exit\") {\n        }\n\n        public override int Invoke(IEnumerable<string> arguments) {\n            var extra = new List<string>(arguments ?? new string[0]);\n            var _ = CommandSet.Options.MessageLocalizer;\n            if (extra.Count == 0) {\n                CommandSet.Options.WriteOptionDescriptions(CommandSet.Out);\n                return 0;\n            }\n            var command = CommandSet.GetCommand(extra);\n            if (command == this || extra.Contains(\"--help\")) {\n                CommandSet.Out.WriteLine(_($\"Usage: {CommandSet.Suite} COMMAND [OPTIONS]\"));\n                CommandSet.Out.WriteLine(_($\"Use `{CommandSet.Suite} help COMMAND` for help on a specific command.\"));\n                CommandSet.Out.WriteLine();\n                CommandSet.Out.WriteLine(_($\"Available commands:\"));\n                CommandSet.Out.WriteLine();\n                var commands = GetCommands();\n                commands.Sort((x, y) => string.Compare(x.Key, y.Key, StringComparison.OrdinalIgnoreCase));\n                foreach (var c in commands) {\n                    if (c.Key == \"help\") {\n                        continue;\n                    }\n                    CommandSet.Options.WriteCommandDescription(CommandSet.Out, c.Value, c.Key);\n                }\n                CommandSet.Options.WriteCommandDescription(CommandSet.Out, CommandSet.help, \"help\");\n                return 0;\n            }\n            if (command == null) {\n                WriteUnknownCommand(extra[0]);\n                return 1;\n            }\n            if (command.Options != null) {\n                command.Options.WriteOptionDescriptions(CommandSet.Out);\n                return 0;\n            }\n            return command.Invoke(new[] { \"--help\" });\n        }\n\n        List<KeyValuePair<string, Command>> GetCommands() {\n            var commands = new List<KeyValuePair<string, Command>>();\n\n            foreach (var c in CommandSet) {\n                commands.Add(new KeyValuePair<string, Command>(c.Name, c));\n            }\n\n            if (CommandSet.NestedCommandSets == null)\n                return commands;\n\n            foreach (var nc in CommandSet.NestedCommandSets) {\n                AddNestedCommands(commands, \"\", nc);\n            }\n\n            return commands;\n        }\n\n        void AddNestedCommands(List<KeyValuePair<string, Command>> commands, string outer, CommandSet value) {\n            foreach (var v in value) {\n                commands.Add(new KeyValuePair<string, Command>($\"{outer}{value.Suite} {v.Name}\", v));\n            }\n            if (value.NestedCommandSets == null)\n                return;\n            foreach (var nc in value.NestedCommandSets) {\n                AddNestedCommands(commands, $\"{outer}{value.Suite} \", nc);\n            }\n        }\n\n        internal void WriteUnknownCommand(string unknownCommand) {\n            CommandSet.Error.WriteLine(CommandSet.Options.MessageLocalizer($\"{CommandSet.Suite}: Unknown command: {unknownCommand}\"));\n            CommandSet.Error.WriteLine(CommandSet.Options.MessageLocalizer($\"{CommandSet.Suite}: Use `{CommandSet.Suite} help` for usage.\"));\n        }\n    }\n}\n"
  },
  {
    "path": "SylantStrikeInject/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Management;\nusing System.Runtime.InteropServices;\nusing System.Security.Principal;\nusing System.Threading;\nusing Mono.Options;\n\nnamespace SylantStrikeInject {\n\n    class Program\n    {\n        private static List<string> processList = new List<string>();\n        private static string dllPath;\n\n        static void Main(string[] args)\n        {\n\n            RunThisAsAdmin(string.Join(\" \", args));\n\n            OptionSet option_set = new OptionSet()\n            {\n                {\"p=|process=\", \"Process name to protect with CylantStrike\", v => { processList.Add(v.ToLower()); }},\n                {\"d=|dll=\", \"Path to CylantStrike protection DLL\", v => { dllPath = v; }}\n            };\n\n            try\n            {\n                option_set.Parse(args);\n\n                new Thread(WaitForProcess) {IsBackground = true, Name = \"worker\"}.Start();\n                Console.WriteLine(\"Waiting for process events\");\n                do\n                {\n                    Thread.Sleep(5000);\n                } while (true);\n\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine($\"Failed to setup injector ${e.Message}\");\n            }\n        }\n\n        private static void RunThisAsAdmin(string args)\n        {\n            if (!IsAdministrator())\n            {\n                var exe = Process.GetCurrentProcess().MainModule.FileName;\n                var startInfo = new ProcessStartInfo(exe, args)\n                {\n                    UseShellExecute = true,\n                    Verb = \"runas\",\n                    WindowStyle = ProcessWindowStyle.Normal,\n                    CreateNoWindow = false,\n\n                };\n                Process.Start(startInfo);\n                Process.GetCurrentProcess().Kill();\n            }\n        }\n\n        private static bool IsAdministrator()\n        {\n            var identity = WindowsIdentity.GetCurrent();\n            var principal = new WindowsPrincipal(identity);\n            return principal.IsInRole(WindowsBuiltInRole.Administrator);\n        }\n\n        static void WaitForProcess()\n        {\n            try\n            {\n                var startWatch = new ManagementEventWatcher(new WqlEventQuery(\"SELECT * FROM Win32_ProcessStartTrace\"));\n                startWatch.EventArrived += new EventArrivedEventHandler(startWatch_EventArrived);\n                startWatch.Start();\n                Console.ForegroundColor = ConsoleColor.Green;\n                Console.WriteLine($\"+ Listening for the following processes: {string.Join(\" \", processList)}\\n\");\n            }\n            catch (Exception ex)\n            {\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.WriteLine(ex);\n            }\n        }\n\n        static void startWatch_EventArrived(object sender, EventArrivedEventArgs e)\n        {\n            try\n            {\n                var proc = GetProcessInfo(e);\n                if (processList.Contains(proc.ProcessName.ToLower()))\n                {\n                    Console.ForegroundColor = ConsoleColor.Green;\n                    Console.WriteLine($\" Injecting process {proc.ProcessName}({proc.PID}) with DLL {dllPath}\");\n                    BasicInject.Inject(proc.PID, dllPath);\n                }\n            }\n            catch (Exception ex)\n            {\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.WriteLine(ex);\n            }\n        }\n\n        static ProcessInfo GetProcessInfo(EventArrivedEventArgs e)\n        {\n            var p = new ProcessInfo();\n            var pid = 0;\n            int.TryParse(e.NewEvent.Properties[\"ProcessID\"].Value.ToString(), out pid);\n            p.PID = pid;\n            p.ProcessName = e.NewEvent.Properties[\"ProcessName\"].Value.ToString();\n            return p;\n        }\n\n        internal class ProcessInfo\n        {\n            public string ProcessName { get; set; }\n            public int PID { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "SylantStrikeInject/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"CylantStrikeInject\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"CylantStrikeInject\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2020\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"1accf54a-57a0-4dd3-bf6d-d06ac450947b\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "SylantStrikeInject/SylantStrikeInject.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{1ACCF54A-57A0-4DD3-BF6D-D06AC450947B}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>SylantStrikeInject</RootNamespace>\n    <AssemblyName>SylantStrikeInject</AssemblyName>\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <Deterministic>true</Deterministic>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>..\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>..\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Management\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"BasicInject.cs\" />\n    <Compile Include=\"Options.cs\" />\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  }
]