This also adds some error tracking stuff to Doorstoppull/46/head
@ -0,0 +1,325 @@ | |||||
## Ignore Visual Studio temporary files, build results, and | |||||
## files generated by popular Visual Studio add-ons. | |||||
## | |||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore | |||||
# Prerequisites | |||||
*.d | |||||
# Compiled Object files | |||||
*.slo | |||||
*.lo | |||||
*.o | |||||
*.obj | |||||
# Precompiled Headers | |||||
*.gch | |||||
*.pch | |||||
# Compiled Dynamic libraries | |||||
*.so | |||||
*.dylib | |||||
*.dll | |||||
# Fortran module files | |||||
*.mod | |||||
*.smod | |||||
# Compiled Static libraries | |||||
*.lai | |||||
*.la | |||||
*.a | |||||
*.lib | |||||
# Executables | |||||
*.exe | |||||
*.out | |||||
*.app | |||||
# User-specific files | |||||
*.suo | |||||
*.user | |||||
*.userosscache | |||||
*.sln.docstates | |||||
# User-specific files (MonoDevelop/Xamarin Studio) | |||||
*.userprefs | |||||
# Build folder | |||||
Build/ | |||||
# Build results | |||||
[Dd]ebug/ | |||||
[Dd]ebugPublic/ | |||||
[Rr]elease/ | |||||
[Rr]eleases/ | |||||
x64/ | |||||
x86/ | |||||
bld/ | |||||
[Bb]in/ | |||||
[Oo]bj/ | |||||
[Ll]og/ | |||||
.vscode/ | |||||
# Visual Studio 2015 cache/options directory | |||||
.vs/ | |||||
# Uncomment if you have tasks that create the project's static files in wwwroot | |||||
#wwwroot/ | |||||
# MSTest test Results | |||||
[Tt]est[Rr]esult*/ | |||||
[Bb]uild[Ll]og.* | |||||
# NUNIT | |||||
*.VisualState.xml | |||||
TestResult.xml | |||||
# Build Results of an ATL Project | |||||
[Dd]ebugPS/ | |||||
[Rr]eleasePS/ | |||||
dlldata.c | |||||
# .NET Core | |||||
project.lock.json | |||||
project.fragment.lock.json | |||||
artifacts/ | |||||
**/Properties/launchSettings.json | |||||
*_i.c | |||||
*_p.c | |||||
*_i.h | |||||
*.ilk | |||||
*.meta | |||||
*.obj | |||||
*.pch | |||||
*.pdb | |||||
*.pgc | |||||
*.pgd | |||||
*.rsp | |||||
*.sbr | |||||
*.tlb | |||||
*.tli | |||||
*.tlh | |||||
*.tmp | |||||
*.tmp_proj | |||||
*.log | |||||
*.vspscc | |||||
*.vssscc | |||||
.builds | |||||
*.pidb | |||||
*.svclog | |||||
*.scc | |||||
# Chutzpah Test files | |||||
_Chutzpah* | |||||
# Visual C++ cache files | |||||
ipch/ | |||||
*.aps | |||||
*.ncb | |||||
*.opendb | |||||
*.opensdf | |||||
*.sdf | |||||
*.cachefile | |||||
*.VC.db | |||||
*.VC.VC.opendb | |||||
# Visual Studio profiler | |||||
*.psess | |||||
*.vsp | |||||
*.vspx | |||||
*.sap | |||||
# TFS 2012 Local Workspace | |||||
$tf/ | |||||
# Guidance Automation Toolkit | |||||
*.gpState | |||||
# ReSharper is a .NET coding add-in | |||||
_ReSharper*/ | |||||
*.[Rr]e[Ss]harper | |||||
*.DotSettings.user | |||||
# JustCode is a .NET coding add-in | |||||
.JustCode | |||||
# TeamCity is a build add-in | |||||
_TeamCity* | |||||
# DotCover is a Code Coverage Tool | |||||
*.dotCover | |||||
# Visual Studio code coverage results | |||||
*.coverage | |||||
*.coveragexml | |||||
# NCrunch | |||||
_NCrunch_* | |||||
.*crunch*.local.xml | |||||
nCrunchTemp_* | |||||
# MightyMoose | |||||
*.mm.* | |||||
AutoTest.Net/ | |||||
# Web workbench (sass) | |||||
.sass-cache/ | |||||
# Installshield output folder | |||||
[Ee]xpress/ | |||||
# DocProject is a documentation generator add-in | |||||
DocProject/buildhelp/ | |||||
DocProject/Help/*.HxT | |||||
DocProject/Help/*.HxC | |||||
DocProject/Help/*.hhc | |||||
DocProject/Help/*.hhk | |||||
DocProject/Help/*.hhp | |||||
DocProject/Help/Html2 | |||||
DocProject/Help/html | |||||
# Click-Once directory | |||||
publish/ | |||||
# Publish Web Output | |||||
*.[Pp]ublish.xml | |||||
*.azurePubxml | |||||
# TODO: Comment the next line if you want to checkin your web deploy settings | |||||
# but database connection strings (with potential passwords) will be unencrypted | |||||
*.pubxml | |||||
*.publishproj | |||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to | |||||
# checkin your Azure Web App publish settings, but sensitive information contained | |||||
# in these scripts will be unencrypted | |||||
PublishScripts/ | |||||
# NuGet Packages | |||||
*.nupkg | |||||
# The packages folder can be ignored because of Package Restore | |||||
**/packages/* | |||||
# except build/, which is used as an MSBuild target. | |||||
!**/packages/build/ | |||||
# Uncomment if necessary however generally it will be regenerated when needed | |||||
#!**/packages/repositories.config | |||||
# NuGet v3's project.json files produces more ignorable files | |||||
*.nuget.props | |||||
*.nuget.targets | |||||
# Microsoft Azure Build Output | |||||
csx/ | |||||
*.build.csdef | |||||
# Microsoft Azure Emulator | |||||
ecf/ | |||||
rcf/ | |||||
# Windows Store app package directories and files | |||||
AppPackages/ | |||||
BundleArtifacts/ | |||||
Package.StoreAssociation.xml | |||||
_pkginfo.txt | |||||
# Visual Studio cache files | |||||
# files ending in .cache can be ignored | |||||
*.[Cc]ache | |||||
# but keep track of directories ending in .cache | |||||
!*.[Cc]ache/ | |||||
# Others | |||||
ClientBin/ | |||||
~$* | |||||
*~ | |||||
*.dbmdl | |||||
*.dbproj.schemaview | |||||
*.jfm | |||||
*.pfx | |||||
*.publishsettings | |||||
orleans.codegen.cs | |||||
# Since there are multiple workflows, uncomment next line to ignore bower_components | |||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) | |||||
#bower_components/ | |||||
# RIA/Silverlight projects | |||||
Generated_Code/ | |||||
# Backup & report files from converting an old project file | |||||
# to a newer Visual Studio version. Backup files are not needed, | |||||
# because we have git ;-) | |||||
_UpgradeReport_Files/ | |||||
Backup*/ | |||||
UpgradeLog*.XML | |||||
UpgradeLog*.htm | |||||
# SQL Server files | |||||
*.mdf | |||||
*.ldf | |||||
*.ndf | |||||
# Business Intelligence projects | |||||
*.rdl.data | |||||
*.bim.layout | |||||
*.bim_*.settings | |||||
# Microsoft Fakes | |||||
FakesAssemblies/ | |||||
# GhostDoc plugin setting file | |||||
*.GhostDoc.xml | |||||
# Node.js Tools for Visual Studio | |||||
.ntvs_analysis.dat | |||||
node_modules/ | |||||
# Typescript v1 declaration files | |||||
typings/ | |||||
# Visual Studio 6 build log | |||||
*.plg | |||||
# Visual Studio 6 workspace options file | |||||
*.opt | |||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) | |||||
*.vbw | |||||
# Visual Studio LightSwitch build output | |||||
**/*.HTMLClient/GeneratedArtifacts | |||||
**/*.DesktopClient/GeneratedArtifacts | |||||
**/*.DesktopClient/ModelManifest.xml | |||||
**/*.Server/GeneratedArtifacts | |||||
**/*.Server/ModelManifest.xml | |||||
_Pvt_Extensions | |||||
# Paket dependency manager | |||||
.paket/paket.exe | |||||
paket-files/ | |||||
# FAKE - F# Make | |||||
.fake/ | |||||
# JetBrains Rider | |||||
.idea/ | |||||
*.sln.iml | |||||
# CodeRush | |||||
.cr/ | |||||
# Python Tools for Visual Studio (PTVS) | |||||
__pycache__/ | |||||
*.pyc | |||||
# Cake - Uncomment if you are using it | |||||
# tools/** | |||||
# !tools/packages.config | |||||
# Telerik's JustMock configuration file | |||||
*.jmconfig | |||||
# BizTalk build output | |||||
*.btp.cs | |||||
*.btm.cs | |||||
*.odx.cs | |||||
*.xsd.cs |
@ -0,0 +1,58 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}</ProjectGuid> | |||||
<OutputType>Library</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>Doorstop</RootNamespace> | |||||
<AssemblyName>Doorstop</AssemblyName> | |||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup> | |||||
<StartupObject /> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'"> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<OutputPath>bin\Verbose\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<DebugType>full</DebugType> | |||||
<PlatformTarget>AnyCPU</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose_Release|AnyCPU'"> | |||||
<OutputPath>bin\Verbose_Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<Optimize>true</Optimize> | |||||
<DebugType>pdbonly</DebugType> | |||||
<PlatformTarget>AnyCPU</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Compile Include="Loader.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
</Project> |
@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.IO; | |||||
namespace Doorstop | |||||
{ | |||||
public static class Loader | |||||
{ | |||||
public static void Main(string[] args) | |||||
{ | |||||
using (TextWriter tw = File.CreateText("doorstop_is_alive.txt")) | |||||
{ | |||||
tw.WriteLine($"Hello! This text file was generated by Doorstop on {DateTime.Now:R}!"); | |||||
tw.WriteLine($"I was called with {args.Length} params!"); | |||||
for (int i = 0; i < args.Length; i++) | |||||
tw.WriteLine($"{i} => {args[i]}"); | |||||
tw.WriteLine("Replace this DLL with a custom-made one to do whatever you want!"); | |||||
tw.Flush(); | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,36 @@ | |||||
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// General Information about an assembly is controlled through the following | |||||
// set of attributes. Change these attribute values to modify the information | |||||
// associated with an assembly. | |||||
[assembly: AssemblyTitle("PatchLoader")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("PatchLoader")] | |||||
[assembly: AssemblyCopyright("Copyright © 2018")] | |||||
[assembly: AssemblyTrademark("")] | |||||
[assembly: AssemblyCulture("")] | |||||
// Setting ComVisible to false makes the types in this assembly not visible | |||||
// to COM components. If you need to access a type in this assembly from | |||||
// COM, set the ComVisible attribute to true on that type. | |||||
[assembly: ComVisible(false)] | |||||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||||
[assembly: Guid("62b61ccc-0775-4cf4-b37a-eb5e33cbd08c")] | |||||
// Version information for an assembly consists of the following four values: | |||||
// | |||||
// Major Version | |||||
// Minor Version | |||||
// Build Number | |||||
// Revision | |||||
// | |||||
// You can specify all the values or you can default the Build and Revision Numbers | |||||
// by using the '*' as shown below: | |||||
// [assembly: AssemblyVersion("1.0.*")] | |||||
[assembly: AssemblyVersion("1.0.0.0")] | |||||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@ -0,0 +1,116 @@ | |||||
CC0 1.0 Universal | |||||
Statement of Purpose | |||||
The laws of most jurisdictions throughout the world automatically confer | |||||
exclusive Copyright and Related Rights (defined below) upon the creator and | |||||
subsequent owner(s) (each and all, an "owner") of an original work of | |||||
authorship and/or a database (each, a "Work"). | |||||
Certain owners wish to permanently relinquish those rights to a Work for the | |||||
purpose of contributing to a commons of creative, cultural and scientific | |||||
works ("Commons") that the public can reliably and without fear of later | |||||
claims of infringement build upon, modify, incorporate in other works, reuse | |||||
and redistribute as freely as possible in any form whatsoever and for any | |||||
purposes, including without limitation commercial purposes. These owners may | |||||
contribute to the Commons to promote the ideal of a free culture and the | |||||
further production of creative, cultural and scientific works, or to gain | |||||
reputation or greater distribution for their Work in part through the use and | |||||
efforts of others. | |||||
For these and/or other purposes and motivations, and without any expectation | |||||
of additional consideration or compensation, the person associating CC0 with a | |||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright | |||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work | |||||
and publicly distribute the Work under its terms, with knowledge of his or her | |||||
Copyright and Related Rights in the Work and the meaning and intended legal | |||||
effect of CC0 on those rights. | |||||
1. Copyright and Related Rights. A Work made available under CC0 may be | |||||
protected by copyright and related or neighboring rights ("Copyright and | |||||
Related Rights"). Copyright and Related Rights include, but are not limited | |||||
to, the following: | |||||
i. the right to reproduce, adapt, distribute, perform, display, communicate, | |||||
and translate a Work; | |||||
ii. moral rights retained by the original author(s) and/or performer(s); | |||||
iii. publicity and privacy rights pertaining to a person's image or likeness | |||||
depicted in a Work; | |||||
iv. rights protecting against unfair competition in regards to a Work, | |||||
subject to the limitations in paragraph 4(a), below; | |||||
v. rights protecting the extraction, dissemination, use and reuse of data in | |||||
a Work; | |||||
vi. database rights (such as those arising under Directive 96/9/EC of the | |||||
European Parliament and of the Council of 11 March 1996 on the legal | |||||
protection of databases, and under any national implementation thereof, | |||||
including any amended or successor version of such directive); and | |||||
vii. other similar, equivalent or corresponding rights throughout the world | |||||
based on applicable law or treaty, and any national implementations thereof. | |||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, | |||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and | |||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright | |||||
and Related Rights and associated claims and causes of action, whether now | |||||
known or unknown (including existing as well as future claims and causes of | |||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum | |||||
duration provided by applicable law or treaty (including future time | |||||
extensions), (iii) in any current or future medium and for any number of | |||||
copies, and (iv) for any purpose whatsoever, including without limitation | |||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes | |||||
the Waiver for the benefit of each member of the public at large and to the | |||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver | |||||
shall not be subject to revocation, rescission, cancellation, termination, or | |||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work | |||||
by the public as contemplated by Affirmer's express Statement of Purpose. | |||||
3. Public License Fallback. Should any part of the Waiver for any reason be | |||||
judged legally invalid or ineffective under applicable law, then the Waiver | |||||
shall be preserved to the maximum extent permitted taking into account | |||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver | |||||
is so judged Affirmer hereby grants to each affected person a royalty-free, | |||||
non transferable, non sublicensable, non exclusive, irrevocable and | |||||
unconditional license to exercise Affirmer's Copyright and Related Rights in | |||||
the Work (i) in all territories worldwide, (ii) for the maximum duration | |||||
provided by applicable law or treaty (including future time extensions), (iii) | |||||
in any current or future medium and for any number of copies, and (iv) for any | |||||
purpose whatsoever, including without limitation commercial, advertising or | |||||
promotional purposes (the "License"). The License shall be deemed effective as | |||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the | |||||
License for any reason be judged legally invalid or ineffective under | |||||
applicable law, such partial invalidity or ineffectiveness shall not | |||||
invalidate the remainder of the License, and in such case Affirmer hereby | |||||
affirms that he or she will not (i) exercise any of his or her remaining | |||||
Copyright and Related Rights in the Work or (ii) assert any associated claims | |||||
and causes of action with respect to the Work, in either case contrary to | |||||
Affirmer's express Statement of Purpose. | |||||
4. Limitations and Disclaimers. | |||||
a. No trademark or patent rights held by Affirmer are waived, abandoned, | |||||
surrendered, licensed or otherwise affected by this document. | |||||
b. Affirmer offers the Work as-is and makes no representations or warranties | |||||
of any kind concerning the Work, express, implied, statutory or otherwise, | |||||
including without limitation warranties of title, merchantability, fitness | |||||
for a particular purpose, non infringement, or the absence of latent or | |||||
other defects, accuracy, or the present or absence of errors, whether or not | |||||
discoverable, all to the greatest extent permissible under applicable law. | |||||
c. Affirmer disclaims responsibility for clearing rights of other persons | |||||
that may apply to the Work or any use thereof, including without limitation | |||||
any person's Copyright and Related Rights in the Work. Further, Affirmer | |||||
disclaims responsibility for obtaining any necessary consents, permissions | |||||
or other rights required for any use of the Work. | |||||
d. Affirmer understands and acknowledges that Creative Commons is not a | |||||
party to this document and has no duty or obligation with respect to this | |||||
CC0 or use of the Work. | |||||
For more information, please see | |||||
<http://creativecommons.org/publicdomain/zero/1.0/> |
@ -0,0 +1,190 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<ItemGroup Label="ProjectConfigurations"> | |||||
<ProjectConfiguration Include="Release|Win32"> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>Win32</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Release|x64"> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>x64</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Verbose_Release|Win32"> | |||||
<Configuration>Verbose_Release</Configuration> | |||||
<Platform>Win32</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Verbose_Release|x64"> | |||||
<Configuration>Verbose_Release</Configuration> | |||||
<Platform>x64</Platform> | |||||
</ProjectConfiguration> | |||||
</ItemGroup> | |||||
<PropertyGroup Label="Globals"> | |||||
<ProjectGuid>{88609E16-731F-46C9-8139-6B1A7A83240D}</ProjectGuid> | |||||
<Keyword>Win32Proj</Keyword> | |||||
<RootNamespace>proxy</RootNamespace> | |||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |||||
<ProjectName>proxy</ProjectName> | |||||
</PropertyGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |||||
<ConfigurationType>DynamicLibrary</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>Unicode</CharacterSet> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'" Label="Configuration"> | |||||
<ConfigurationType>DynamicLibrary</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>Unicode</CharacterSet> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||||
<ConfigurationType>DynamicLibrary</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>Unicode</CharacterSet> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'" Label="Configuration"> | |||||
<ConfigurationType>DynamicLibrary</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>Unicode</CharacterSet> | |||||
</PropertyGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |||||
<ImportGroup Label="Shared"> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'" Label="PropertySheets"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'" Label="PropertySheets"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<PropertyGroup Label="UserMacros" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
<LinkIncremental>false</LinkIncremental> | |||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir> | |||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'"> | |||||
<LinkIncremental>false</LinkIncremental> | |||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir> | |||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
<LinkIncremental>false</LinkIncremental> | |||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir> | |||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'"> | |||||
<LinkIncremental>false</LinkIncremental> | |||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir> | |||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir> | |||||
</PropertyGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='Debug'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<PrecompiledHeader> | |||||
</PrecompiledHeader> | |||||
<Optimization>MinSpace</Optimization> | |||||
<FunctionLevelLinking>true</FunctionLevelLinking> | |||||
<IntrinsicFunctions>false</IntrinsicFunctions> | |||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;NOGDI;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<CLanguageStandard>c11</CLanguageStandard> | |||||
<CompileAs>CompileAsC</CompileAs> | |||||
<PrecompiledHeaderCompileAs>CompileAsC</PrecompiledHeaderCompileAs> | |||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||||
<WholeProgramOptimization>false</WholeProgramOptimization> | |||||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||||
<ExceptionHandling>false</ExceptionHandling> | |||||
<SupportJustMyCode>false</SupportJustMyCode> | |||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MultiThreadedDLL</RuntimeLibrary> | |||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MultiThreadedDLL</RuntimeLibrary> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Windows</SubSystem> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
<OptimizeReferences>true</OptimizeReferences> | |||||
<ModuleDefinitionFile>$(MSBuildProjectDirectory)\proxy.def</ModuleDefinitionFile> | |||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> | |||||
<DelayLoadDLLs> | |||||
</DelayLoadDLLs> | |||||
<EntryPointSymbol>DllMain</EntryPointSymbol> | |||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> | |||||
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ImageHasSafeExceptionHandlers> | |||||
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ImageHasSafeExceptionHandlers> | |||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalOptions)</AdditionalOptions> | |||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalOptions)</AdditionalOptions> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Verbose_Release' Or '$(Configuration)'=='Verbose'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<PrecompiledHeader> | |||||
</PrecompiledHeader> | |||||
<Optimization>MinSpace</Optimization> | |||||
<FunctionLevelLinking>true</FunctionLevelLinking> | |||||
<IntrinsicFunctions>false</IntrinsicFunctions> | |||||
<PreprocessorDefinitions>_VERBOSE;NDEBUG;_WINDOWS;_USRDLL;NOGDI;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<CLanguageStandard>c11</CLanguageStandard> | |||||
<CompileAs>CompileAsC</CompileAs> | |||||
<PrecompiledHeaderCompileAs>CompileAsC</PrecompiledHeaderCompileAs> | |||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||||
<WholeProgramOptimization>false</WholeProgramOptimization> | |||||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||||
<ExceptionHandling>false</ExceptionHandling> | |||||
<SupportJustMyCode>false</SupportJustMyCode> | |||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'">MultiThreadedDLL</RuntimeLibrary> | |||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'">MultiThreadedDLL</RuntimeLibrary> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Windows</SubSystem> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
<OptimizeReferences>true</OptimizeReferences> | |||||
<ModuleDefinitionFile>$(MSBuildProjectDirectory)\proxy.def</ModuleDefinitionFile> | |||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> | |||||
<DelayLoadDLLs> | |||||
</DelayLoadDLLs> | |||||
<EntryPointSymbol>DllMain</EntryPointSymbol> | |||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> | |||||
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'">false</ImageHasSafeExceptionHandlers> | |||||
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'">false</ImageHasSafeExceptionHandlers> | |||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|Win32'">%(AdditionalOptions)</AdditionalOptions> | |||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Verbose_Release|x64'">%(AdditionalOptions)</AdditionalOptions> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemGroup> | |||||
<ClCompile Include="main.c" /> | |||||
<ClCompile Include="proxy.c" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClInclude Include="assert_util.h" /> | |||||
<ClInclude Include="config.h" /> | |||||
<ClInclude Include="crt.h" /> | |||||
<ClInclude Include="hook.h" /> | |||||
<ClInclude Include="mono.h" /> | |||||
<ClInclude Include="proxy.h" /> | |||||
<ClInclude Include="winapi_util.h" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ResourceCompile Include="proxy.rc" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="proxy.def" /> | |||||
</ItemGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||||
<Target Name="AfterBuild"> | |||||
<Exec Command="$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine($(MSBuildProjectDirectory), '..', 'BuildUtils', 'ducible.exe')))) $(OutDir)$(MSBuildProjectName).dll $(OutDir)$(MSBuildProjectName).pdb" /> | |||||
</Target> | |||||
</Project> |
@ -0,0 +1,61 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<ItemGroup> | |||||
<Filter Include="Source Files"> | |||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | |||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | |||||
</Filter> | |||||
<Filter Include="Header Files"> | |||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | |||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> | |||||
</Filter> | |||||
<Filter Include="Resource Files"> | |||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | |||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |||||
</Filter> | |||||
<Filter Include="Other"> | |||||
<UniqueIdentifier>{384fe73e-c79a-42c8-8d61-73dc2f7e7432}</UniqueIdentifier> | |||||
</Filter> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClCompile Include="main.c"> | |||||
<Filter>Source Files</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="proxy.c"> | |||||
<Filter>Source Files</Filter> | |||||
</ClCompile> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClInclude Include="mono.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="hook.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="assert_util.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="proxy.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="config.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="winapi_util.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="crt.h"> | |||||
<Filter>Header Files</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ResourceCompile Include="proxy.rc"> | |||||
<Filter>Resource Files</Filter> | |||||
</ResourceCompile> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="proxy.def"> | |||||
<Filter>Other</Filter> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> |
@ -0,0 +1,63 @@ | |||||
#pragma once | |||||
#ifdef _VERBOSE | |||||
#pragma comment(lib, "ucrt.lib") | |||||
#include <windows.h> | |||||
#include <stdio.h> | |||||
static HANDLE log_handle; | |||||
char buffer[8192]; | |||||
wchar_t bufferW[8192]; | |||||
inline void init_logger() | |||||
{ | |||||
log_handle = CreateFileA("doorstop.log", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, | |||||
NULL); | |||||
} | |||||
inline void free_logger() | |||||
{ | |||||
CloseHandle(log_handle); | |||||
} | |||||
#define LOG(message, ...) \ | |||||
{ \ | |||||
int len = _snprintf_s(buffer, sizeof(buffer)/sizeof(char), _TRUNCATE, message, __VA_ARGS__); \ | |||||
WriteFile(log_handle, buffer, len, NULL, NULL); \ | |||||
} | |||||
#else | |||||
inline void init_logger() | |||||
{ | |||||
} | |||||
inline void free_logger() | |||||
{ | |||||
} | |||||
#define LOG(message, ...) | |||||
#endif | |||||
#define ASSERT_F(test, message, ...) \ | |||||
if(!(test)) \ | |||||
{ \ | |||||
_snwprintf_s(bufferW, sizeof(bufferW)/sizeof(wchar_t), _TRUNCATE, message, __VA_ARGS__); \ | |||||
MessageBoxW(NULL, bufferW, L"Doorstop: Fatal", MB_OK | MB_ICONERROR); \ | |||||
ExitProcess(EXIT_FAILURE); \ | |||||
} | |||||
// A helper for cleaner error logging | |||||
#define ASSERT(test, message) \ | |||||
if(!(test)) \ | |||||
{ \ | |||||
MessageBoxW(NULL, message, L"Doorstop: Fatal", MB_OK | MB_ICONERROR); \ | |||||
ExitProcess(EXIT_FAILURE); \ | |||||
} | |||||
#define ASSERT_SOFT(test, ...) \ | |||||
if(!(test)) \ | |||||
{ \ | |||||
return __VA_ARGS__; \ | |||||
} |
@ -0,0 +1,137 @@ | |||||
#pragma once | |||||
#pragma warning( disable : 4267 ) | |||||
#include <Windows.h> | |||||
#include <shellapi.h> | |||||
#include "winapi_util.h" | |||||
#include "assert_util.h" | |||||
#include "crt.h" | |||||
#define CONFIG_NAME L"doorstop_config" | |||||
#define DEFAULT_TARGET_ASSEMBLY L"Doorstop.dll" | |||||
#define EXE_EXTENSION_LENGTH 4 | |||||
BOOL enabled = FALSE; | |||||
BOOL debug = FALSE; | |||||
BOOL debug_server = FALSE; | |||||
BOOL debug_info = FALSE; | |||||
wchar_t *targetAssembly = NULL; | |||||
#define STR_EQUAL(str1, str2) (lstrcmpiW(str1, str2) == 0) | |||||
inline void initConfigFile() | |||||
{ | |||||
enabled = TRUE; | |||||
WIN32_FIND_DATAW findData; | |||||
HANDLE findHandle = FindFirstFileW(L"*_Data", &findData); | |||||
if (findHandle == INVALID_HANDLE_VALUE) | |||||
{ | |||||
MessageBoxW(NULL, L"Could not locate game being injected!", L"No files found in current directory matching '*_Data'", | |||||
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL | MB_TOPMOST | MB_SETFOREGROUND); | |||||
ExitProcess(GetLastError()); | |||||
} | |||||
do | |||||
{ | |||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |||||
{ // must be a directory | |||||
wchar_t* target = memalloc(MAX_PATH * sizeof(wchar_t)); | |||||
const int EXIT_FAILURE = 1; | |||||
ASSERT(target != NULL, L"Address returned by memalloc was NULL!"); | |||||
wmemset(target, 0, MAX_PATH); | |||||
wmemcpy(target, findData.cFileName, wcslen(findData.cFileName)); | |||||
wmemcpy(target + wcslen(target), L"/Managed/IPA.Injector.dll", 26); | |||||
targetAssembly = target; | |||||
FindClose(findHandle); | |||||
break; | |||||
} | |||||
} | |||||
while (FindNextFileW(findHandle, &findData) != 0); | |||||
if (targetAssembly == NULL) | |||||
{ | |||||
MessageBoxW(NULL, L"Could not locate game being injected!", L"No valid directories matching '*_Data'", | |||||
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL | MB_TOPMOST | MB_SETFOREGROUND); | |||||
ExitProcess(GetLastError()); | |||||
} | |||||
} | |||||
inline void initCmdArgs() | |||||
{ | |||||
wchar_t *args = GetCommandLineW(); | |||||
int argc = 0; | |||||
wchar_t **argv = CommandLineToArgvW(args, &argc); | |||||
#define IS_ARGUMENT(arg_name) STR_EQUAL(arg, arg_name) && i < argc | |||||
for (int i = 0; i < argc; i++) | |||||
{ | |||||
wchar_t *arg = argv[i]; | |||||
/*if (IS_ARGUMENT(L"--doorstop-enable")) | |||||
{ | |||||
wchar_t *par = argv[++i]; | |||||
if (STR_EQUAL(par, L"true")) | |||||
enabled = TRUE; | |||||
else if (STR_EQUAL(par, L"false")) | |||||
enabled = FALSE; | |||||
} | |||||
else if (IS_ARGUMENT(L"--doorstop-target")) | |||||
{ | |||||
if (targetAssembly != NULL) | |||||
memfree(targetAssembly); | |||||
const size_t len = wcslen(argv[i + 1]) + 1; | |||||
targetAssembly = memalloc(sizeof(wchar_t) * len); | |||||
lstrcpynW(targetAssembly, argv[++i], len); | |||||
LOG("Args; Target assembly: %S\n", targetAssembly); | |||||
} | |||||
else */if (IS_ARGUMENT(L"--mono-debug")) | |||||
{ | |||||
debug = TRUE; | |||||
debug_info = TRUE; | |||||
LOG("Enabled debugging\n"); | |||||
} | |||||
else if (IS_ARGUMENT(L"--debug")) | |||||
{ | |||||
debug_info = TRUE; | |||||
LOG("Enabled loading of debug info\n"); | |||||
} | |||||
else if (IS_ARGUMENT(L"--server")) | |||||
{ | |||||
debug_server = TRUE; | |||||
LOG("Server-mode debugging enabled\n"); | |||||
} | |||||
} | |||||
LocalFree(argv); | |||||
} | |||||
inline void initEnvVars() | |||||
{ | |||||
if (GetEnvironmentVariableW(L"DOORSTOP_DISABLE", NULL, 0) != 0) | |||||
{ | |||||
LOG("DOORSTOP_DISABLE is set! Disabling Doorstop!\n"); | |||||
enabled = FALSE; | |||||
} | |||||
} | |||||
inline void loadConfig() | |||||
{ | |||||
initConfigFile(); | |||||
initCmdArgs(); | |||||
initEnvVars(); | |||||
} | |||||
inline void cleanupConfig() | |||||
{ | |||||
if (targetAssembly != NULL) | |||||
memfree(targetAssembly); | |||||
} |
@ -0,0 +1,65 @@ | |||||
#pragma once | |||||
#pragma warning( disable : 4028 28251 6001 ) | |||||
#include <debugapi.h> | |||||
HANDLE hHeap; | |||||
#define memalloc(size) HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, size) | |||||
#define memcalloc(size) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, size) | |||||
#define memfree(mem) HeapFree(hHeap, 0, mem) | |||||
#define STR_LEN(str) (sizeof(str) / sizeof(str[0])) | |||||
#define DEBUG_BREAK { if (IsDebuggerPresent()) { __debugbreak(); } } | |||||
inline void *wmemcpy(wchar_t *dst, const wchar_t *src, size_t n) | |||||
{ | |||||
wchar_t *d = dst; | |||||
const wchar_t *s = src; | |||||
while (n--) | |||||
*d++ = *s++; | |||||
return dst; | |||||
} | |||||
inline void *wmemset(wchar_t *dst, wchar_t c, size_t n) | |||||
{ | |||||
wchar_t *d = dst; | |||||
while (n--) | |||||
*(d++) = c; | |||||
return dst; | |||||
} | |||||
void *memset(void *dst, char c, int n) | |||||
{ | |||||
char *d = dst; | |||||
while (n--) | |||||
*d = c; | |||||
return dst; | |||||
} | |||||
inline void *memcpy(void *dst, const void *src, int n) | |||||
{ | |||||
char *d = dst; | |||||
const char *s = src; | |||||
while (n--) | |||||
*d++ = *s++; | |||||
return dst; | |||||
} | |||||
inline size_t wcslen(wchar_t const *str) | |||||
{ | |||||
size_t result = 0; | |||||
while (*str++) | |||||
result++; | |||||
return result; | |||||
} | |||||
inline size_t strlen(char const *str) | |||||
{ | |||||
size_t result = 0; | |||||
while (*str++) | |||||
result++; | |||||
return result; | |||||
} |
@ -0,0 +1,64 @@ | |||||
EXPORTS | |||||
SvchostPushServiceGlobals | |||||
WinHttpAddRequestHeaders | |||||
WinHttpAutoProxySvcMain | |||||
WinHttpCheckPlatform | |||||
WinHttpCloseHandle | |||||
WinHttpConnect | |||||
WinHttpConnectionDeletePolicyEntries | |||||
WinHttpConnectionDeleteProxyInfo | |||||
WinHttpConnectionFreeNameList | |||||
WinHttpConnectionFreeProxyInfo | |||||
WinHttpConnectionFreeProxyList | |||||
WinHttpConnectionGetNameList | |||||
WinHttpConnectionGetProxyInfo | |||||
WinHttpConnectionGetProxyList | |||||
WinHttpConnectionSetPolicyEntries | |||||
WinHttpConnectionSetProxyInfo | |||||
WinHttpConnectionUpdateIfIndexTable | |||||
WinHttpCrackUrl | |||||
WinHttpCreateProxyResolver | |||||
WinHttpCreateUrl | |||||
WinHttpDetectAutoProxyConfigUrl | |||||
WinHttpFreeProxyResult | |||||
WinHttpFreeProxyResultEx | |||||
WinHttpFreeProxySettings | |||||
WinHttpGetDefaultProxyConfiguration | |||||
WinHttpGetIEProxyConfigForCurrentUser | |||||
WinHttpGetProxyForUrl | |||||
WinHttpGetProxyForUrlEx | |||||
WinHttpGetProxyForUrlEx2 | |||||
WinHttpGetProxyForUrlHvsi | |||||
WinHttpGetProxyResult | |||||
WinHttpGetProxyResultEx | |||||
WinHttpGetProxySettingsVersion | |||||
WinHttpGetTunnelSocket | |||||
WinHttpOpen | |||||
WinHttpOpenRequest | |||||
WinHttpProbeConnectivity | |||||
WinHttpQueryAuthSchemes | |||||
WinHttpQueryDataAvailable | |||||
WinHttpQueryHeaders | |||||
WinHttpQueryOption | |||||
WinHttpReadData | |||||
WinHttpReadProxySettings | |||||
WinHttpReadProxySettingsHvsi | |||||
WinHttpReceiveResponse | |||||
WinHttpResetAutoProxy | |||||
WinHttpSaveProxyCredentials | |||||
WinHttpSendRequest | |||||
WinHttpSetCredentials | |||||
WinHttpSetDefaultProxyConfiguration | |||||
WinHttpSetOption | |||||
WinHttpSetStatusCallback | |||||
WinHttpSetTimeouts | |||||
WinHttpTimeFromSystemTime | |||||
WinHttpTimeToSystemTime | |||||
WinHttpWebSocketClose | |||||
WinHttpWebSocketCompleteUpgrade | |||||
WinHttpWebSocketQueryCloseStatus | |||||
WinHttpWebSocketReceive | |||||
WinHttpWebSocketSend | |||||
WinHttpWebSocketShutdown | |||||
WinHttpWriteData | |||||
WinHttpWriteProxySettings |
@ -0,0 +1,162 @@ | |||||
/* | |||||
* EAT-based hooking for x86/x64. | |||||
* | |||||
* Big thanks to ez (https://github.com/ezdiy/) for making this! | |||||
* | |||||
* Creates "hooks" by modifying the module's export address table. | |||||
* The procedure works in three main parts: | |||||
* | |||||
* 1. Reading the module's PE file and getting all exported functions. | |||||
* 2. Finding the right function to "hook" by simple address lookup | |||||
* 3. Modify the entry to point to the hook. | |||||
* | |||||
* The idea is based on the fact that the export table allows forwarding imports: | |||||
* | |||||
* https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#Forwarding | |||||
* | |||||
* You can also find some reference material on the same page to understand this code better. | |||||
* | |||||
*/ | |||||
#pragma once | |||||
#pragma warning( disable : 4267 90 ) | |||||
#include <windows.h> | |||||
// PE format uses RVAs (Relative Virtual Addresses) to save addresses relative to the base of the module | |||||
// More info: https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#Relative_Virtual_Addressing_(RVA) | |||||
// | |||||
// This helper macro converts the saved RVA to a fully valid pointer to the data in the PE file | |||||
#define RVA2PTR(t,base,rva) ((t)(((PCHAR) base) + rva)) | |||||
// A helper function to write into protected memory | |||||
inline int vpmemcpy(void *dst, void *src, size_t sz) | |||||
{ | |||||
DWORD oldp; | |||||
// Make the memory page writeable | |||||
if (!VirtualProtect(dst, sz, PAGE_READWRITE, &oldp)) | |||||
return 1; | |||||
memcpy(dst, src, sz); | |||||
// Restore the protection level | |||||
VirtualProtect(dst, sz, oldp, &oldp); | |||||
return 0; | |||||
} | |||||
/** | |||||
* \brief Replaces the specified function entry in the EAT with a forward to a custom one, thus creating the "hook" effect. | |||||
* \param hostDll The address of the module to hook. | |||||
* \param originalFunction Address of the original function. | |||||
* \param forwardFunctionEntry Name of the function to add a forward to. Must be of form `dll.API`. | |||||
* \return TRUE, if hooking succeeded, otherwise, FALSE. | |||||
*/ | |||||
inline BOOL ezHook(HMODULE hostDll, void *originalFunction, char *forwardFunctionEntry) | |||||
{ | |||||
/* | |||||
* Note that we are not doing any trampoline magic or editing the assembly! | |||||
* | |||||
* Instead, we are reading the module's PE file, find the original function's entry in the export address table (EAT), | |||||
* and replace it with a forward import. | |||||
* | |||||
* This ultimately will fool the game/executable to call our hook, while keeping original function intact. | |||||
* | |||||
* Thus, in order to work, the proxy DLL has to export the hook, because we are essentially | |||||
* asking the game to call our hook without ever going to the original function (unlike with trampolines). | |||||
*/ | |||||
size_t fwdlen = strlen(forwardFunctionEntry); | |||||
// The module always starts with a DOS (or "MZ") header | |||||
IMAGE_DOS_HEADER *mz = (PIMAGE_DOS_HEADER)hostDll; | |||||
// Next, get the NT headers. The offset to them is saved in e_lfanew | |||||
IMAGE_NT_HEADERS *nt = RVA2PTR(PIMAGE_NT_HEADERS, mz, mz->e_lfanew); | |||||
// Get the pointer to the data directory of the exports | |||||
IMAGE_DATA_DIRECTORY *edirp = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; | |||||
IMAGE_DATA_DIRECTORY edir = *edirp; | |||||
// Finally, the virtual address in the data direcotry tells the location of the exports table | |||||
IMAGE_EXPORT_DIRECTORY *exports = RVA2PTR(PIMAGE_EXPORT_DIRECTORY, mz, edir.VirtualAddress); | |||||
// Read the addrress of the function list and the address of function names | |||||
DWORD *addrs = RVA2PTR(DWORD*, mz, exports->AddressOfFunctions); | |||||
// DWORD* names = RVA2PTR(DWORD*, mz, exports->AddressOfNames); | |||||
// Iterate through all functions | |||||
for (unsigned i = 0; i < exports->NumberOfFunctions; i++) | |||||
{ | |||||
//char* name = RVA2PTR(char*, mz, names[i]); // Name of the exported function | |||||
void *addr = RVA2PTR(void*, mz, addrs[i]); // Address of the exported function | |||||
// Check if we have the function we need to modify | |||||
if (addr == originalFunction) | |||||
{ | |||||
DWORD fptr = edir.VirtualAddress + edir.Size; | |||||
int err = 0; | |||||
// Update the entry to go the the last entry (which we will populate in the next memcpy) | |||||
err |= vpmemcpy(&addrs[i], &fptr, sizeof(fptr)); | |||||
// Add the forwarding import to our function at the end of the EAT | |||||
err |= vpmemcpy(((char*)exports + edir.Size), forwardFunctionEntry, fwdlen); | |||||
// Increment the size of the export data directory | |||||
// and write the new export data directory | |||||
edir.Size += fwdlen + 1; | |||||
err |= vpmemcpy(edirp, &edir, sizeof(edir)); | |||||
return err == 0; | |||||
} | |||||
} | |||||
return FALSE; | |||||
} | |||||
/** | |||||
* \brief Hooks the given function through the Import Address Table | |||||
* \param dll Module to hook | |||||
* \param targetFunction Address of the target function to hook | |||||
* \param detourFunction Address of the detour function | |||||
* \return TRUE if successful, otherwise FALSE | |||||
*/ | |||||
inline BOOL iat_hook(HMODULE dll, char const* targetDLL, void *targetFunction, void *detourFunction) | |||||
{ | |||||
IMAGE_DOS_HEADER *mz = (PIMAGE_DOS_HEADER)dll; | |||||
IMAGE_NT_HEADERS *nt = RVA2PTR(PIMAGE_NT_HEADERS, mz, mz->e_lfanew); | |||||
IMAGE_IMPORT_DESCRIPTOR *imports = RVA2PTR(PIMAGE_IMPORT_DESCRIPTOR, mz, nt->OptionalHeader.DataDirectory[ | |||||
IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); | |||||
for (int i = 0; imports[i].Characteristics; i++) | |||||
{ | |||||
char *name = RVA2PTR(char*, mz, imports[i].Name); | |||||
if(lstrcmpiA(name, targetDLL) != 0) | |||||
continue; | |||||
void **thunk = RVA2PTR(void**, mz, imports[i].FirstThunk); | |||||
void **nextThunk = RVA2PTR(void**, mz, imports[i+1].FirstThunk); | |||||
for (; thunk && thunk < nextThunk; thunk++) | |||||
{ | |||||
void *import = *thunk; | |||||
if (import != targetFunction) | |||||
continue; | |||||
DWORD oldState; | |||||
if (!VirtualProtect(thunk, sizeof(void*), PAGE_READWRITE, &oldState)) | |||||
return FALSE; | |||||
*thunk = (void*)detourFunction; | |||||
VirtualProtect(thunk, sizeof(void*), oldState, &oldState); | |||||
return TRUE; | |||||
} | |||||
} | |||||
return FALSE; | |||||
} |
@ -0,0 +1,462 @@ | |||||
/* | |||||
* main.cpp -- The main "entry point" and the main logic of the DLL. | |||||
* | |||||
* Here, we define and initialize struct Main that contains the main code of this DLL. | |||||
* | |||||
* The main procedure goes as follows: | |||||
* 1. The loader checks that PatchLoader.dll and mono.dll exist | |||||
* 2. mono.dll is loaded into memory and some of its functions are looked up | |||||
* 3. mono_jit_init_version is hooked with the help of MinHook | |||||
* | |||||
* Then, the loader waits until Unity creates its root domain for mono (which is done with mono_jit_init_version). | |||||
* | |||||
* Inside mono_jit_init_version hook: | |||||
* 1. Call the original mono_jit_init_version to get the Unity root domain | |||||
* 2. Load PatchLoader.dll into the root domain | |||||
* 3. Find and invoke PatchLoader.Loader.Run() | |||||
* | |||||
* Rest of the work is done on the managed side. | |||||
* | |||||
*/ | |||||
#pragma warning( disable : 4267 100 152 6387 4456 6011 ) | |||||
#include "winapi_util.h" | |||||
#include <Windows.h> | |||||
#include "config.h" | |||||
#include "mono.h" | |||||
#include "hook.h" | |||||
#include "assert_util.h" | |||||
#include "proxy.h" | |||||
#include <synchapi.h> | |||||
#include <intrin.h> | |||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase; // This is provided by MSVC with the infomration about this DLL | |||||
HANDLE unhandledMutex; | |||||
void ownMonoJitParseOptions(int argc, char * argv[]); | |||||
BOOL setOptions = FALSE; | |||||
void unhandledException(void* exc, void* data) | |||||
{ | |||||
WaitForSingleObject(unhandledMutex, INFINITE); | |||||
void* exception = NULL; | |||||
void* mstr = mono_object_to_string(exc, &exception); | |||||
if (exception != NULL) | |||||
{ | |||||
#ifdef _VERBOSE | |||||
void* monostr = mono_object_to_string(exception, &exception); | |||||
if (exception != NULL) | |||||
{ | |||||
DEBUG_BREAK; | |||||
LOG("An error occurred while stringifying uncaught error, but the error could not be stringified.\n"); | |||||
ASSERT(FALSE, L"Uncaught exception; could not stringify"); | |||||
} | |||||
else | |||||
{ | |||||
char* str = mono_string_to_utf8(monostr); | |||||
DEBUG_BREAK; | |||||
LOG("An error occurred stringifying uncaught error: %s\n", str); | |||||
size_t len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); | |||||
wchar_t* wstr = memalloc(sizeof(wchar_t) * len); | |||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len); | |||||
ASSERT_F(FALSE, L"Uncaught exception; stringify failed: %s", wstr); | |||||
memfree(wstr); | |||||
mono_free(str); | |||||
} | |||||
#else | |||||
ASSERT(FALSE, L"Could not stringify uncaught exception"); | |||||
#endif | |||||
} | |||||
char* str = mono_string_to_utf8(mstr); | |||||
DEBUG_BREAK; | |||||
LOG("Uncaught exception: %s\n", str); | |||||
size_t len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); | |||||
wchar_t* wstr = memalloc(sizeof(wchar_t) * len); | |||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len); | |||||
#ifdef _VERBOSE | |||||
ASSERT(FALSE, L"Uncaught exception; see doorstop.log for details"); | |||||
#else | |||||
ASSERT_F(FALSE, L"Uncaught exception: %s", wstr); | |||||
#endif | |||||
memfree(wstr); | |||||
mono_free(str); | |||||
ReleaseMutex(unhandledMutex); | |||||
} | |||||
// The hook for mono_jit_init_version | |||||
// We use this since it will always be called once to initialize Mono's JIT | |||||
void *ownMonoJitInitVersion(const char *root_domain_name, const char *runtime_version) | |||||
{ | |||||
// Call the original mono_jit_init_version to initialize the Unity Root Domain | |||||
if (debug) { | |||||
char* opts[1]; | |||||
opts[0] = ""; | |||||
ownMonoJitParseOptions(0, opts); | |||||
} | |||||
#ifdef WIN32 | |||||
if (debug_info) { | |||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO); | |||||
} | |||||
#endif | |||||
void *domain = mono_jit_init_version(root_domain_name, runtime_version); | |||||
if (debug_info) { | |||||
#ifdef WIN64 | |||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO); | |||||
#endif | |||||
mono_debug_domain_create(domain); | |||||
} | |||||
size_t len = WideCharToMultiByte(CP_UTF8, 0, targetAssembly, -1, NULL, 0, NULL, NULL); | |||||
char *dll_path = memalloc(sizeof(char) * len); | |||||
WideCharToMultiByte(CP_UTF8, 0, targetAssembly, -1, dll_path, len, NULL, NULL); | |||||
LOG("Loading assembly: %s\n", dll_path); | |||||
// Load our custom assembly into the domain | |||||
void *assembly = mono_domain_assembly_open(domain, dll_path); | |||||
if (assembly == NULL) | |||||
LOG("Failed to load assembly\n"); | |||||
memfree(dll_path); | |||||
ASSERT_SOFT(assembly != NULL, domain); | |||||
// Get assembly's image that contains CIL code | |||||
void *image = mono_assembly_get_image(assembly); | |||||
ASSERT_SOFT(image != NULL, domain); | |||||
// Note: we use the runtime_invoke route since jit_exec will not work on DLLs | |||||
// Create a descriptor for a random Main method | |||||
void *desc = mono_method_desc_new("*:Main", FALSE); | |||||
// Find the first possible Main method in the assembly | |||||
void *method = mono_method_desc_search_in_image(desc, image); | |||||
ASSERT_SOFT(method != NULL, domain); | |||||
void *signature = mono_method_signature(method); | |||||
// Get the number of parameters in the signature | |||||
UINT32 params = mono_signature_get_param_count(signature); | |||||
void **args = NULL; | |||||
wchar_t *app_path = NULL; | |||||
if (params == 1) | |||||
{ | |||||
// If there is a parameter, it's most likely a string[]. | |||||
// Populate it as follows | |||||
// 0 => path to the game's executable | |||||
// 1 => --doorstop-invoke | |||||
get_module_path(NULL, &app_path, NULL, 0); | |||||
void *exe_path = MONO_STRING(app_path); | |||||
void *doorstop_handle = MONO_STRING(L"--doorstop-invoke"); | |||||
void *args_array = mono_array_new(domain, mono_get_string_class(), 2); | |||||
SET_ARRAY_REF(args_array, 0, exe_path); | |||||
SET_ARRAY_REF(args_array, 1, doorstop_handle); | |||||
args = memalloc(sizeof(void*) * 1); | |||||
_ASSERTE(args != nullptr); | |||||
args[0] = args_array; | |||||
} | |||||
LOG("Installing uncaught exception handler\n"); | |||||
mono_install_unhandled_exception_hook(unhandledException, NULL); | |||||
unhandledMutex = CreateMutexW(NULL, FALSE, NULL); | |||||
LOG("Invoking method!\n"); | |||||
void* exception = NULL; | |||||
mono_runtime_invoke(method, NULL, args, &exception); | |||||
WaitForSingleObject(unhandledMutex, INFINITE); // if the EH is triggered, wait for it | |||||
if (args != NULL) | |||||
{ | |||||
memfree(app_path); | |||||
memfree(args); | |||||
NULL; | |||||
} | |||||
#ifdef _VERBOSE | |||||
if (exception != NULL) | |||||
{ | |||||
void* monostr = mono_object_to_string(exception, &exception); | |||||
if (exception != NULL) | |||||
LOG("An error occurred while invoking the injector, but the error could not be stringified.\n") | |||||
else | |||||
{ | |||||
char* str = mono_string_to_utf8(monostr); | |||||
LOG("An error occurred invoking the injector: %s\n", str); | |||||
mono_free(str); | |||||
} | |||||
} | |||||
#endif | |||||
cleanupConfig(); | |||||
free_logger(); | |||||
ReleaseMutex(unhandledMutex); | |||||
return domain; | |||||
} | |||||
void ownMonoJitParseOptions(int argc, char * argv[]) | |||||
{ | |||||
setOptions = TRUE; | |||||
int size = argc; | |||||
#ifdef WIN64 | |||||
if (debug) size += 2; | |||||
#elif defined(WIN32) | |||||
if (debug) size += 1; | |||||
#endif | |||||
char** arguments = memalloc(sizeof(char*) * size); | |||||
_ASSERTE(arguments != nullptr); | |||||
memcpy(arguments, argv, sizeof(char*) * argc); | |||||
if (debug) { | |||||
//arguments[argc++] = "--debug"; | |||||
#ifdef WIN64 | |||||
arguments[argc++] = "--soft-breakpoints"; | |||||
#endif | |||||
if (debug_server) | |||||
arguments[argc] = "--debugger-agent=transport=dt_socket,address=0.0.0.0:10000,server=y"; | |||||
else | |||||
arguments[argc] = "--debugger-agent=transport=dt_socket,address=127.0.0.1:10000,server=n"; | |||||
} | |||||
mono_jit_parse_options(size, arguments); | |||||
memfree(arguments); | |||||
} | |||||
BOOL initialized = FALSE; | |||||
void init(HMODULE module) | |||||
{ | |||||
if (!initialized) | |||||
{ | |||||
initialized = TRUE; | |||||
LOG("Got mono.dll at %p\n", module); | |||||
loadMonoFunctions(module); | |||||
} | |||||
} | |||||
void * WINAPI hookGetProcAddress(HMODULE module, char const *name) | |||||
{ | |||||
if (lstrcmpA(name, "mono_jit_init_version") == 0) | |||||
{ | |||||
init(module); | |||||
return (void*)&ownMonoJitInitVersion; | |||||
} | |||||
if (lstrcmpA(name, "mono_jit_parse_options") == 0 && debug) | |||||
{ | |||||
init(module); | |||||
return (void*)&ownMonoJitParseOptions; | |||||
} | |||||
return (void*)GetProcAddress(module, name); | |||||
} | |||||
BOOL hookGetMessage( | |||||
BOOL isW, | |||||
LPMSG msg, | |||||
HWND hwnd, | |||||
UINT wMsgFilterMin, | |||||
UINT wMsgFilterMax | |||||
); | |||||
BOOL WINAPI hookGetMessageA(LPMSG msg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax) | |||||
{ | |||||
return hookGetMessage(FALSE, msg, hwnd, wMsgFilterMin, wMsgFilterMax); | |||||
} | |||||
BOOL WINAPI hookGetMessageW(LPMSG msg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax) | |||||
{ | |||||
return hookGetMessage(TRUE, msg, hwnd, wMsgFilterMin, wMsgFilterMax); | |||||
} | |||||
typedef BOOL(*GetMessageHook)(BOOL isW, BOOL result, LPMSG msg, HWND hwnd, UINT filterMin, UINT filterMax); | |||||
GetMessageHook getMessageHook = NULL; | |||||
__declspec(dllexport) void __stdcall SetGetMessageHook(GetMessageHook hook) { | |||||
getMessageHook = hook; | |||||
} | |||||
BOOL hookGetMessage( | |||||
BOOL isW, | |||||
LPMSG msg, | |||||
HWND hwnd, | |||||
UINT wMsgFilterMin, | |||||
UINT wMsgFilterMax | |||||
) | |||||
{ | |||||
BOOL loop = FALSE; | |||||
BOOL result; | |||||
do { | |||||
if (isW) { | |||||
result = GetMessageW(msg, hwnd, wMsgFilterMin, wMsgFilterMax); | |||||
} else { | |||||
result = GetMessageA(msg, hwnd, wMsgFilterMin, wMsgFilterMax); | |||||
} | |||||
if (getMessageHook) { | |||||
loop = getMessageHook(isW, result, msg, hwnd, wMsgFilterMin, wMsgFilterMax); | |||||
} | |||||
} while (loop); | |||||
return result; | |||||
} | |||||
BOOL hookPeekMessage( | |||||
BOOL isW, | |||||
LPMSG msg, | |||||
HWND hwnd, | |||||
UINT wMsgFilterMin, | |||||
UINT wMsgFilterMax, | |||||
UINT wRemoveMsg | |||||
); | |||||
BOOL WINAPI hookPeekMessageA(LPMSG msg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) | |||||
{ | |||||
return hookPeekMessage(FALSE, msg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); | |||||
} | |||||
BOOL WINAPI hookPeekMessageW(LPMSG msg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) | |||||
{ | |||||
return hookPeekMessage(TRUE, msg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); | |||||
} | |||||
typedef BOOL(*PeekMessageHook)(BOOL isW, BOOL result, LPMSG msg, HWND hwnd, UINT filterMin, UINT filterMax, UINT* wRemoveMsg); | |||||
PeekMessageHook peekMessageHook = NULL; | |||||
__declspec(dllexport) void __stdcall SetPeekMessageHook(PeekMessageHook hook) { | |||||
peekMessageHook = hook; | |||||
} | |||||
BOOL hookPeekMessage( | |||||
BOOL isW, | |||||
LPMSG msg, | |||||
HWND hwnd, | |||||
UINT wMsgFilterMin, | |||||
UINT wMsgFilterMax, | |||||
UINT wRemoveMsg | |||||
) | |||||
{ | |||||
BOOL loop = FALSE; | |||||
BOOL result; | |||||
do { | |||||
if (isW) { | |||||
result = PeekMessageW(msg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); | |||||
} | |||||
else { | |||||
result = PeekMessageA(msg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); | |||||
} | |||||
if (peekMessageHook) { | |||||
loop = peekMessageHook(isW, result, msg, hwnd, wMsgFilterMin, wMsgFilterMax, &wRemoveMsg); | |||||
} | |||||
} while (loop); | |||||
return result; | |||||
} | |||||
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reasonForDllLoad, LPVOID reserved) | |||||
{ | |||||
if (reasonForDllLoad != DLL_PROCESS_ATTACH) | |||||
return TRUE; | |||||
hHeap = GetProcessHeap(); | |||||
init_logger(); | |||||
LOG("Doorstop started!\n"); | |||||
wchar_t *dll_path = NULL; | |||||
size_t dll_path_len = get_module_path((HINSTANCE)&__ImageBase, &dll_path, NULL, 0); | |||||
LOG("DLL Path: %S\n", dll_path); | |||||
wchar_t *dll_name = get_file_name_no_ext(dll_path, dll_path_len); | |||||
LOG("Doorstop DLL Name: %S\n", dll_name); | |||||
loadProxy(dll_name); | |||||
loadConfig(); | |||||
// If the loader is disabled, don't inject anything. | |||||
if (enabled) | |||||
{ | |||||
LOG("Doorstop enabled!\n"); | |||||
ASSERT_SOFT(GetFileAttributesW(targetAssembly) != INVALID_FILE_ATTRIBUTES, TRUE); | |||||
HMODULE targetModule = GetModuleHandleA("UnityPlayer"); | |||||
if(targetModule == NULL) | |||||
{ | |||||
LOG("No UnityPlayer.dll; using EXE as the hook target."); | |||||
targetModule = GetModuleHandleA(NULL); | |||||
} | |||||
LOG("Installing IAT hook\n"); | |||||
if (!iat_hook(targetModule, "kernel32.dll", &GetProcAddress, &hookGetProcAddress)) | |||||
{ | |||||
LOG("Failed to install IAT hook!\n"); | |||||
free_logger(); | |||||
} | |||||
LOG("Hook installed!\n"); | |||||
LOG("Attempting to install GetMessageA and GetMessageW hooks\n"); | |||||
if (!iat_hook(targetModule, "user32.dll", &GetMessageA, &hookGetMessageA)) { | |||||
LOG("Could not hook GetMessageA! (not an error)\n"); | |||||
} | |||||
if (!iat_hook(targetModule, "user32.dll", &GetMessageW, &hookGetMessageW)) { | |||||
LOG("Could not hook GetMessageW! (not an error)\n"); | |||||
} | |||||
LOG("Attempting to install PeekMessageA and PeekMessageW hooks\n"); | |||||
if (!iat_hook(targetModule, "user32.dll", &PeekMessageA, &hookPeekMessageA)) { | |||||
LOG("Could not hook PeekMessageA! (not an error)\n"); | |||||
} | |||||
if (!iat_hook(targetModule, "user32.dll", &PeekMessageW, &hookPeekMessageW)) { | |||||
LOG("Could not hook PeekMessageW! (not an error)\n"); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
LOG("Doorstop disabled! memfreeing resources\n"); | |||||
free_logger(); | |||||
} | |||||
memfree(dll_name); | |||||
memfree(dll_path); | |||||
return TRUE; | |||||
} |
@ -0,0 +1,105 @@ | |||||
/* | |||||
* mono.h -- Definitions for Mono C API functions. | |||||
* | |||||
* The file contains definitions for some of functions provided by Mono C API. | |||||
* | |||||
* Note: Since we don't use any mono headers, all pointers to mono-related structs are | |||||
* replaced with void *. | |||||
*/ | |||||
#pragma once | |||||
#pragma warning( disable : 4152 ) | |||||
#include <windows.h> | |||||
// Creates a MonoString based from a C wide string | |||||
#define MONO_STRING(str) mono_string_new_utf16(domain, str, wcslen(str)) | |||||
// Set MonoArray's index to a reference type value (i.e. string) | |||||
#define SET_ARRAY_REF(arr, index, refVal) \ | |||||
{ \ | |||||
void **p = (void**) mono_array_addr_with_size(arr, sizeof(void*), index); \ | |||||
mono_gc_wbarrier_set_arrayref(arr, p, refVal); \ | |||||
} | |||||
// Here we define the pointers to some functions within mono.dll | |||||
// Note to C learners: these are not signature definitions, but rather "variable" | |||||
// definitions with the function pointer type. | |||||
// Note: we use void* instead of the real intented structs defined in mono API | |||||
// This way we don't need to include or define any of Mono's structs, which saves space | |||||
// This, obviously, comes with a drawback of not being able to easily access the contents of the structs | |||||
typedef enum { | |||||
MONO_DEBUG_FORMAT_NONE, | |||||
MONO_DEBUG_FORMAT_MONO, | |||||
/* Deprecated, the mdb debugger is not longer supported. */ | |||||
MONO_DEBUG_FORMAT_DEBUGGER | |||||
} MonoDebugFormat; | |||||
void (*mono_jit_parse_options)(int argc, char * argv[]); | |||||
void (*mono_debug_init)(MonoDebugFormat format); | |||||
void(*mono_debug_domain_create)(void*); | |||||
void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); | |||||
void *(*mono_domain_assembly_open)(void *domain, const char *name); | |||||
void *(*mono_assembly_get_image)(void *assembly); | |||||
void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); | |||||
void *(*mono_method_desc_new)(const char *name, int include_namespace); | |||||
void *(*mono_method_desc_search_in_image)(void *desc, void *image); | |||||
void *(*mono_method_signature)(void *method); | |||||
UINT32 (*mono_signature_get_param_count)(void *sig); | |||||
void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); | |||||
void (*mono_gc_wbarrier_set_arrayref)(void *arr, void *slot_ptr, void *value); | |||||
char *(*mono_array_addr_with_size)(void *arr, int size, uintptr_t idx); | |||||
void *(*mono_get_string_class)(); | |||||
void *(*mono_string_new_utf16)(void *domain, const wchar_t *text, INT32 len); | |||||
void* (*mono_object_to_string)(void* obj, void** exc); | |||||
char* (*mono_string_to_utf8)(void* str); | |||||
void (*mono_free)(void*); | |||||
/* Installs a function which is called when the runtime encounters an unhandled exception. | |||||
* This hook isn't expected to return. | |||||
* If no hook has been installed, the runtime will print a message before aborting. | |||||
*/ | |||||
typedef void (*MonoUnhandledExceptionFunc)(void* exc, void* user_data); | |||||
void (*mono_install_unhandled_exception_hook)(MonoUnhandledExceptionFunc func, void* user_data); | |||||
/** | |||||
* \brief Loads Mono C API function pointers so that the above definitions can be called. | |||||
* \param monoLib Mono.dll module. | |||||
*/ | |||||
inline void loadMonoFunctions(HMODULE monoLib) | |||||
{ | |||||
// Enjoy the fact that C allows such sloppy casting | |||||
// In C++ you would have to cast to the precise function pointer type | |||||
#define GET_MONO_PROC(name) name = (void*)GetProcAddress(monoLib, #name) | |||||
// Find and assign all our functions that we are going to use | |||||
GET_MONO_PROC(mono_debug_domain_create); | |||||
GET_MONO_PROC(mono_domain_assembly_open); | |||||
GET_MONO_PROC(mono_assembly_get_image); | |||||
GET_MONO_PROC(mono_runtime_invoke); | |||||
GET_MONO_PROC(mono_debug_init); | |||||
GET_MONO_PROC(mono_jit_init_version); | |||||
GET_MONO_PROC(mono_jit_parse_options); | |||||
GET_MONO_PROC(mono_method_desc_new); | |||||
GET_MONO_PROC(mono_method_desc_search_in_image); | |||||
GET_MONO_PROC(mono_method_signature); | |||||
GET_MONO_PROC(mono_signature_get_param_count); | |||||
GET_MONO_PROC(mono_array_new); | |||||
GET_MONO_PROC(mono_get_string_class); | |||||
GET_MONO_PROC(mono_string_new_utf16); | |||||
GET_MONO_PROC(mono_gc_wbarrier_set_arrayref); | |||||
GET_MONO_PROC(mono_array_addr_with_size); | |||||
GET_MONO_PROC(mono_object_to_string); | |||||
GET_MONO_PROC(mono_string_to_utf8); | |||||
GET_MONO_PROC(mono_free); | |||||
GET_MONO_PROC(mono_install_unhandled_exception_hook); | |||||
} |
@ -0,0 +1,133 @@ | |||||
/* ================================== | |||||
* COMPUTER GENERATED -- DO NOT EDIT | |||||
* ================================== | |||||
* | |||||
* This file contains the definitions for all proxy functions this DLL supports. | |||||
* | |||||
* The proxies are very simple functions that should be optimizied into a | |||||
* single JMP instruction without editing the stack at all. | |||||
* | |||||
* NOTE: While this works, this is a somewhat hackish approach that is based on how | |||||
* the compiler optimizes the code. That said, the proxy will not work on Debug build currently | |||||
* (that can be fixed by changing the appropriate compile flag that I am yet to locate). | |||||
*/ | |||||
#pragma warning( disable : 4244 ) | |||||
#include <windows.h> | |||||
#define ADD_ORIGINAL(i, name) originalFunctions[i] = GetProcAddress(dll, #name) | |||||
#define PROXY(i, name) \ | |||||
__declspec(dllexport) ULONG __stdcall name() \ | |||||
{ \ | |||||
return originalFunctions[i](); \ | |||||
} | |||||
FARPROC originalFunctions[50] = {0}; | |||||
void loadFunctions(HMODULE dll) | |||||
{ | |||||
ADD_ORIGINAL(0, WinHttpAddRequestHeaders); | |||||
ADD_ORIGINAL(1, WinHttpAutoProxySvcMain); | |||||
ADD_ORIGINAL(2, WinHttpCheckPlatform); | |||||
ADD_ORIGINAL(3, WinHttpCloseHandle); | |||||
ADD_ORIGINAL(4, WinHttpConnect); | |||||
ADD_ORIGINAL(5, WinHttpConnectionDeleteProxyInfo); | |||||
ADD_ORIGINAL(6, WinHttpConnectionFreeNameList); | |||||
ADD_ORIGINAL(7, WinHttpConnectionFreeProxyInfo); | |||||
ADD_ORIGINAL(8, WinHttpConnectionFreeProxyList); | |||||
ADD_ORIGINAL(9, WinHttpConnectionGetNameList); | |||||
ADD_ORIGINAL(10, WinHttpConnectionGetProxyInfo); | |||||
ADD_ORIGINAL(11, WinHttpConnectionGetProxyList); | |||||
ADD_ORIGINAL(12, WinHttpConnectionSetProxyInfo); | |||||
ADD_ORIGINAL(13, WinHttpCrackUrl); | |||||
ADD_ORIGINAL(14, WinHttpCreateProxyResolver); | |||||
ADD_ORIGINAL(15, WinHttpCreateUrl); | |||||
ADD_ORIGINAL(16, WinHttpDetectAutoProxyConfigUrl); | |||||
ADD_ORIGINAL(17, WinHttpFreeProxyResult); | |||||
ADD_ORIGINAL(18, WinHttpGetDefaultProxyConfiguration); | |||||
ADD_ORIGINAL(19, WinHttpGetIEProxyConfigForCurrentUser); | |||||
ADD_ORIGINAL(20, WinHttpGetProxyForUrl); | |||||
ADD_ORIGINAL(21, WinHttpGetProxyForUrlEx); | |||||
ADD_ORIGINAL(22, WinHttpGetProxyResult); | |||||
ADD_ORIGINAL(23, WinHttpGetTunnelSocket); | |||||
ADD_ORIGINAL(24, WinHttpOpen); | |||||
ADD_ORIGINAL(25, WinHttpOpenRequest); | |||||
ADD_ORIGINAL(26, WinHttpProbeConnectivity); | |||||
ADD_ORIGINAL(27, WinHttpQueryAuthSchemes); | |||||
ADD_ORIGINAL(28, WinHttpQueryDataAvailable); | |||||
ADD_ORIGINAL(29, WinHttpQueryHeaders); | |||||
ADD_ORIGINAL(30, WinHttpQueryOption); | |||||
ADD_ORIGINAL(31, WinHttpReadData); | |||||
ADD_ORIGINAL(32, WinHttpReceiveResponse); | |||||
ADD_ORIGINAL(33, WinHttpResetAutoProxy); | |||||
ADD_ORIGINAL(34, WinHttpSaveProxyCredentials); | |||||
ADD_ORIGINAL(35, WinHttpSendRequest); | |||||
ADD_ORIGINAL(36, WinHttpSetCredentials); | |||||
ADD_ORIGINAL(37, WinHttpSetDefaultProxyConfiguration); | |||||
ADD_ORIGINAL(38, WinHttpSetOption); | |||||
ADD_ORIGINAL(39, WinHttpSetStatusCallback); | |||||
ADD_ORIGINAL(40, WinHttpSetTimeouts); | |||||
ADD_ORIGINAL(41, WinHttpTimeFromSystemTime); | |||||
ADD_ORIGINAL(42, WinHttpTimeToSystemTime); | |||||
ADD_ORIGINAL(43, WinHttpWebSocketClose); | |||||
ADD_ORIGINAL(44, WinHttpWebSocketCompleteUpgrade); | |||||
ADD_ORIGINAL(45, WinHttpWebSocketQueryCloseStatus); | |||||
ADD_ORIGINAL(46, WinHttpWebSocketReceive); | |||||
ADD_ORIGINAL(47, WinHttpWebSocketSend); | |||||
ADD_ORIGINAL(48, WinHttpWebSocketShutdown); | |||||
ADD_ORIGINAL(49, WinHttpWriteData); | |||||
} | |||||
PROXY(0, WinHttpAddRequestHeaders); | |||||
PROXY(1, WinHttpAutoProxySvcMain); | |||||
PROXY(2, WinHttpCheckPlatform); | |||||
PROXY(3, WinHttpCloseHandle); | |||||
PROXY(4, WinHttpConnect); | |||||
PROXY(5, WinHttpConnectionDeleteProxyInfo); | |||||
PROXY(6, WinHttpConnectionFreeNameList); | |||||
PROXY(7, WinHttpConnectionFreeProxyInfo); | |||||
PROXY(8, WinHttpConnectionFreeProxyList); | |||||
PROXY(9, WinHttpConnectionGetNameList); | |||||
PROXY(10, WinHttpConnectionGetProxyInfo); | |||||
PROXY(11, WinHttpConnectionGetProxyList); | |||||
PROXY(12, WinHttpConnectionSetProxyInfo); | |||||
PROXY(13, WinHttpCrackUrl); | |||||
PROXY(14, WinHttpCreateProxyResolver); | |||||
PROXY(15, WinHttpCreateUrl); | |||||
PROXY(16, WinHttpDetectAutoProxyConfigUrl); | |||||
PROXY(17, WinHttpFreeProxyResult); | |||||
PROXY(18, WinHttpGetDefaultProxyConfiguration); | |||||
PROXY(19, WinHttpGetIEProxyConfigForCurrentUser); | |||||
PROXY(20, WinHttpGetProxyForUrl); | |||||
PROXY(21, WinHttpGetProxyForUrlEx); | |||||
PROXY(22, WinHttpGetProxyResult); | |||||
PROXY(23, WinHttpGetTunnelSocket); | |||||
PROXY(24, WinHttpOpen); | |||||
PROXY(25, WinHttpOpenRequest); | |||||
PROXY(26, WinHttpProbeConnectivity); | |||||
PROXY(27, WinHttpQueryAuthSchemes); | |||||
PROXY(28, WinHttpQueryDataAvailable); | |||||
PROXY(29, WinHttpQueryHeaders); | |||||
PROXY(30, WinHttpQueryOption); | |||||
PROXY(31, WinHttpReadData); | |||||
PROXY(32, WinHttpReceiveResponse); | |||||
PROXY(33, WinHttpResetAutoProxy); | |||||
PROXY(34, WinHttpSaveProxyCredentials); | |||||
PROXY(35, WinHttpSendRequest); | |||||
PROXY(36, WinHttpSetCredentials); | |||||
PROXY(37, WinHttpSetDefaultProxyConfiguration); | |||||
PROXY(38, WinHttpSetOption); | |||||
PROXY(39, WinHttpSetStatusCallback); | |||||
PROXY(40, WinHttpSetTimeouts); | |||||
PROXY(41, WinHttpTimeFromSystemTime); | |||||
PROXY(42, WinHttpTimeToSystemTime); | |||||
PROXY(43, WinHttpWebSocketClose); | |||||
PROXY(44, WinHttpWebSocketCompleteUpgrade); | |||||
PROXY(45, WinHttpWebSocketQueryCloseStatus); | |||||
PROXY(46, WinHttpWebSocketReceive); | |||||
PROXY(47, WinHttpWebSocketSend); | |||||
PROXY(48, WinHttpWebSocketShutdown); | |||||
PROXY(49, WinHttpWriteData); |
@ -0,0 +1,54 @@ | |||||
LIBRARY proxy.dll | |||||
EXPORTS | |||||
WinHttpAddRequestHeaders @1 | |||||
WinHttpAutoProxySvcMain @2 | |||||
WinHttpCheckPlatform @3 | |||||
WinHttpCloseHandle @4 | |||||
WinHttpConnect @5 | |||||
WinHttpConnectionDeleteProxyInfo @6 | |||||
WinHttpConnectionFreeNameList @7 | |||||
WinHttpConnectionFreeProxyInfo @8 | |||||
WinHttpConnectionFreeProxyList @9 | |||||
WinHttpConnectionGetNameList @10 | |||||
WinHttpConnectionGetProxyInfo @11 | |||||
WinHttpConnectionGetProxyList @12 | |||||
WinHttpConnectionSetProxyInfo @13 | |||||
WinHttpCrackUrl @14 | |||||
WinHttpCreateProxyResolver @15 | |||||
WinHttpCreateUrl @16 | |||||
WinHttpDetectAutoProxyConfigUrl @17 | |||||
WinHttpFreeProxyResult @18 | |||||
WinHttpGetDefaultProxyConfiguration @19 | |||||
WinHttpGetIEProxyConfigForCurrentUser @20 | |||||
WinHttpGetProxyForUrl @21 | |||||
WinHttpGetProxyForUrlEx @22 | |||||
WinHttpGetProxyResult @23 | |||||
WinHttpGetTunnelSocket @24 | |||||
WinHttpOpen @25 | |||||
WinHttpOpenRequest @26 | |||||
WinHttpProbeConnectivity @27 | |||||
WinHttpQueryAuthSchemes @28 | |||||
WinHttpQueryDataAvailable @29 | |||||
WinHttpQueryHeaders @30 | |||||
WinHttpQueryOption @31 | |||||
WinHttpReadData @32 | |||||
WinHttpReceiveResponse @33 | |||||
WinHttpResetAutoProxy @34 | |||||
WinHttpSaveProxyCredentials @35 | |||||
WinHttpSendRequest @36 | |||||
WinHttpSetCredentials @37 | |||||
WinHttpSetDefaultProxyConfiguration @38 | |||||
WinHttpSetOption @39 | |||||
WinHttpSetStatusCallback @40 | |||||
WinHttpSetTimeouts @41 | |||||
WinHttpTimeFromSystemTime @42 | |||||
WinHttpTimeToSystemTime @43 | |||||
WinHttpWebSocketClose @44 | |||||
WinHttpWebSocketCompleteUpgrade @45 | |||||
WinHttpWebSocketQueryCloseStatus @46 | |||||
WinHttpWebSocketReceive @47 | |||||
WinHttpWebSocketSend @48 | |||||
WinHttpWebSocketShutdown @49 | |||||
WinHttpWriteData @50 | |||||
SetGetMessageHook @51 | |||||
SetPeekMessageHook @52 |
@ -0,0 +1,74 @@ | |||||
/* | |||||
* Proxy.h -- Definitions for proxy-related functionality | |||||
* | |||||
* The proxy works roughly as follows: | |||||
* - We define our exports in proxy.c (computer generated) | |||||
* - loadProxy initializes the proxy: | |||||
* 1. Look up the name of this DLL | |||||
* 2. Find the original DLL with the same name | |||||
* 3. Load the original DLL | |||||
* 4. Load all functions into originalFunctions array | |||||
* | |||||
* For more information, refer to proxy.c | |||||
*/ | |||||
#pragma once | |||||
#pragma warning( disable : 4267 6387 6386 ) | |||||
#include <Windows.h> | |||||
#include <Shlwapi.h> | |||||
#include "assert_util.h" | |||||
#include <crtdbg.h> | |||||
#define ALT_POSTFIX L"_alt.dll" | |||||
#define DLL_POSTFIX L".dll" | |||||
extern FARPROC originalFunctions[]; | |||||
extern void loadFunctions(HMODULE dll); | |||||
// Load the proxy functions into memory | |||||
inline void loadProxy(wchar_t *moduleName) | |||||
{ | |||||
size_t module_name_len = wcslen(moduleName); | |||||
size_t alt_name_len = module_name_len + STR_LEN(ALT_POSTFIX); | |||||
wchar_t *alt_name = memalloc(sizeof(wchar_t) * alt_name_len); | |||||
wmemcpy(alt_name, moduleName, module_name_len); | |||||
wmemcpy(alt_name + module_name_len, ALT_POSTFIX, STR_LEN(ALT_POSTFIX)); | |||||
wchar_t *dll_path = NULL; // The final DLL path | |||||
const int alt_full_path_len = GetFullPathNameW(alt_name, 0, NULL, NULL); | |||||
wchar_t *alt_full_path = memalloc(sizeof(wchar_t) * alt_full_path_len); | |||||
GetFullPathNameW(alt_name, alt_full_path_len, alt_full_path, NULL); | |||||
memfree(alt_name); | |||||
LOG("Looking for original DLL from %S\n", alt_full_path); | |||||
// Try to look for the alternative first in the same directory. | |||||
HMODULE handle = LoadLibrary(alt_full_path); | |||||
if (handle == NULL) | |||||
{ | |||||
size_t system_dir_len = GetSystemDirectoryW(NULL, 0); | |||||
dll_path = memalloc(sizeof(wchar_t) * (system_dir_len + module_name_len + STR_LEN(DLL_POSTFIX))); | |||||
_ASSERTE(dll_path != nullptr); | |||||
GetSystemDirectoryW(dll_path, system_dir_len); | |||||
dll_path[system_dir_len - 1] = L'\\'; | |||||
wmemcpy(dll_path + system_dir_len, moduleName, module_name_len); | |||||
wmemcpy(dll_path + system_dir_len + module_name_len, DLL_POSTFIX, STR_LEN(DLL_POSTFIX)); | |||||
LOG("Looking for original DLL from %S\n", dll_path); | |||||
handle = LoadLibraryW(dll_path); | |||||
} | |||||
ASSERT_F(handle != NULL, L"Unable to load the original %s.dll (looked from system directory and from %s_alt.dll)!", | |||||
moduleName, moduleName); | |||||
memfree(alt_full_path); | |||||
memfree(dll_path); | |||||
loadFunctions(handle); | |||||
} |
@ -0,0 +1,63 @@ | |||||
SvchostPushServiceGlobals | |||||
WinHttpAddRequestHeaders | |||||
WinHttpAutoProxySvcMain | |||||
WinHttpCheckPlatform | |||||
WinHttpCloseHandle | |||||
WinHttpConnect | |||||
WinHttpConnectionDeletePolicyEntries | |||||
WinHttpConnectionDeleteProxyInfo | |||||
WinHttpConnectionFreeNameList | |||||
WinHttpConnectionFreeProxyInfo | |||||
WinHttpConnectionFreeProxyList | |||||
WinHttpConnectionGetNameList | |||||
WinHttpConnectionGetProxyInfo | |||||
WinHttpConnectionGetProxyList | |||||
WinHttpConnectionSetPolicyEntries | |||||
WinHttpConnectionSetProxyInfo | |||||
WinHttpConnectionUpdateIfIndexTable | |||||
WinHttpCrackUrl | |||||
WinHttpCreateProxyResolver | |||||
WinHttpCreateUrl | |||||
WinHttpDetectAutoProxyConfigUrl | |||||
WinHttpFreeProxyResult | |||||
WinHttpFreeProxyResultEx | |||||
WinHttpFreeProxySettings | |||||
WinHttpGetDefaultProxyConfiguration | |||||
WinHttpGetIEProxyConfigForCurrentUser | |||||
WinHttpGetProxyForUrl | |||||
WinHttpGetProxyForUrlEx | |||||
WinHttpGetProxyForUrlEx2 | |||||
WinHttpGetProxyForUrlHvsi | |||||
WinHttpGetProxyResult | |||||
WinHttpGetProxyResultEx | |||||
WinHttpGetProxySettingsVersion | |||||
WinHttpGetTunnelSocket | |||||
WinHttpOpen | |||||
WinHttpOpenRequest | |||||
WinHttpProbeConnectivity | |||||
WinHttpQueryAuthSchemes | |||||
WinHttpQueryDataAvailable | |||||
WinHttpQueryHeaders | |||||
WinHttpQueryOption | |||||
WinHttpReadData | |||||
WinHttpReadProxySettings | |||||
WinHttpReadProxySettingsHvsi | |||||
WinHttpReceiveResponse | |||||
WinHttpResetAutoProxy | |||||
WinHttpSaveProxyCredentials | |||||
WinHttpSendRequest | |||||
WinHttpSetCredentials | |||||
WinHttpSetDefaultProxyConfiguration | |||||
WinHttpSetOption | |||||
WinHttpSetStatusCallback | |||||
WinHttpSetTimeouts | |||||
WinHttpTimeFromSystemTime | |||||
WinHttpTimeToSystemTime | |||||
WinHttpWebSocketClose | |||||
WinHttpWebSocketCompleteUpgrade | |||||
WinHttpWebSocketQueryCloseStatus | |||||
WinHttpWebSocketReceive | |||||
WinHttpWebSocketSend | |||||
WinHttpWebSocketShutdown | |||||
WinHttpWriteData | |||||
WinHttpWriteProxySettings |
@ -0,0 +1,65 @@ | |||||
#pragma once | |||||
#pragma warning( disable : 4267 6387 ) | |||||
#include <windows.h> | |||||
#include "crt.h" | |||||
inline size_t get_module_path(HMODULE module, wchar_t **result, size_t *size, size_t free_space) | |||||
{ | |||||
size_t i = 0; | |||||
size_t len, s; | |||||
*result = NULL; | |||||
do | |||||
{ | |||||
if (*result != NULL) | |||||
memfree(*result); | |||||
i++; | |||||
s = i * MAX_PATH + 1; | |||||
*result = memalloc(sizeof(wchar_t) * s); | |||||
len = GetModuleFileNameW(module, *result, s); | |||||
} | |||||
while (GetLastError() == ERROR_INSUFFICIENT_BUFFER && s - len >= free_space); | |||||
if (size != NULL) | |||||
*size = s; | |||||
return len; | |||||
} | |||||
inline wchar_t *get_ini_entry(const wchar_t *config_file, const wchar_t *section, const wchar_t *key, | |||||
const wchar_t *default_val) | |||||
{ | |||||
size_t i = 0; | |||||
size_t size, read; | |||||
wchar_t *result = NULL; | |||||
do | |||||
{ | |||||
if (result != NULL) | |||||
memfree(result); | |||||
i++; | |||||
size = i * MAX_PATH + 1; | |||||
result = memalloc(sizeof(wchar_t) * size); | |||||
read = GetPrivateProfileStringW(section, key, default_val, result, size, config_file); | |||||
} | |||||
while (read == size - 1); | |||||
return result; | |||||
} | |||||
inline wchar_t *get_file_name_no_ext(wchar_t *str, size_t len) | |||||
{ | |||||
size_t ext_index = len; | |||||
size_t i; | |||||
for (i = len; i > 0; i--) | |||||
{ | |||||
wchar_t c = *(str + i); | |||||
if (c == L'.' && ext_index == len) | |||||
ext_index = i; | |||||
else if (c == L'\\') | |||||
break; | |||||
} | |||||
size_t result_len = ext_index - i; | |||||
wchar_t *result = memcalloc(sizeof(wchar_t) * result_len); | |||||
wmemcpy(result, str + i + 1, result_len - 1); | |||||
return result; | |||||
} |
@ -0,0 +1,47 @@ | |||||
<p align="center"> | |||||
<img src="https://raw.githubusercontent.com/NeighTools/UnityDoorstop/master/docs/logo_sm.png"/> | |||||
</p> | |||||
![Github All Releases](https://img.shields.io/github/downloads/NeighTools/UnityDoorstop/total.svg) | |||||
![GitHub release](https://img.shields.io/github/release/NeighTools/UnityDoorstop.svg) | |||||
![license](https://img.shields.io/github/license/NeighTools/UnityDoorstop.svg) | |||||
*Run managed code before Unity does!* | |||||
# Unity Doorstop | |||||
Doorstop is a tool to execute managed assemblies inside Unity as early as possible! | |||||
This repository is indented mainly for developers! | |||||
Developers should package Doorstop into their applications for the end-users. | |||||
## Features | |||||
* **Runs first**: Doorstop runs its own code before Unity has an ability to do so. | |||||
* **Configurable**: A very basic configuration file allows to specify your own assembly to execute! | |||||
* **Public domain!** You are fully free to embed Doorstop into your application! | |||||
## Guides for users and developers on [the wiki](https://github.com/NeighTools/UnityDoorstop/wiki) | |||||
## Building | |||||
To build, you will need: | |||||
* Visual Studio 2017 (2015 might work as well with some modifications) | |||||
* Visual C++ Toolset v140 | |||||
* .NET Framework 3.5 or newer (only for the example, not used by the proxy) | |||||
* Python (only to generate proxy functions; not needed to build) | |||||
Clone, open in Visual Studio, select the platform (x86/x64) and build. | |||||
#### Custom proxy functions | |||||
Doorstop's proxy is flexible and allows to be load as different DLLs. | |||||
You can modify which functions you want to proxy by adding/removing function names in `Proxy/proxydefs.txt` and running `proxygen/proxy_gen.py ../Proxy/proxydefs.txt` to generate an appropriate proxy functions. | |||||
The current set up allows to use the proxy for the following DLLs: | |||||
* `winhttp.dll` (All exports) | |||||
* `iphlpapi.dll` (Only `GetIpAddrTable`) | |||||
(WIP: Currently all build results are placed in separate folders; will be changed later) |
@ -0,0 +1,77 @@ | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio 15 | |||||
VisualStudioVersion = 15.0.27428.2043 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | |||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proxy", "Proxy\Proxy.vcxproj", "{88609E16-731F-46C9-8139-6B1A7A83240D}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoorstopTest", "DoorstopTest\DoorstopTest.csproj", "{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x64 = Debug|x64 | |||||
Debug|x86 = Debug|x86 | |||||
Release|Any CPU = Release|Any CPU | |||||
Release|x64 = Release|x64 | |||||
Release|x86 = Release|x86 | |||||
Verbose_Release|Any CPU = Verbose_Release|Any CPU | |||||
Verbose_Release|x64 = Verbose_Release|x64 | |||||
Verbose_Release|x86 = Verbose_Release|x86 | |||||
Verbose|Any CPU = Verbose|Any CPU | |||||
Verbose|x64 = Verbose|x64 | |||||
Verbose|x86 = Verbose|x86 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Debug|Any CPU.ActiveCfg = Debug|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Debug|x64.ActiveCfg = Debug|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Debug|x64.Build.0 = Debug|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Debug|x86.ActiveCfg = Debug|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Debug|x86.Build.0 = Debug|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Release|Any CPU.ActiveCfg = Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Release|x64.ActiveCfg = Release|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Release|x64.Build.0 = Release|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Release|x86.ActiveCfg = Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Release|x86.Build.0 = Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose_Release|Any CPU.ActiveCfg = Verbose_Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose_Release|x64.ActiveCfg = Verbose_Release|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose_Release|x64.Build.0 = Verbose_Release|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose_Release|x86.ActiveCfg = Verbose_Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose_Release|x86.Build.0 = Verbose_Release|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose|Any CPU.ActiveCfg = Verbose|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose|x64.ActiveCfg = Verbose|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose|x64.Build.0 = Verbose|x64 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose|x86.ActiveCfg = Verbose|Win32 | |||||
{88609E16-731F-46C9-8139-6B1A7A83240D}.Verbose|x86.Build.0 = Verbose|Win32 | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|x64.Build.0 = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Release|x86.Build.0 = Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|Any CPU.ActiveCfg = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|Any CPU.Build.0 = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|x64.ActiveCfg = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|x64.Build.0 = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|x86.ActiveCfg = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose_Release|x86.Build.0 = Verbose_Release|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|Any CPU.ActiveCfg = Verbose|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|Any CPU.Build.0 = Verbose|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|x64.ActiveCfg = Verbose|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|x64.Build.0 = Verbose|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|x86.ActiveCfg = Verbose|Any CPU | |||||
{62B61CCC-0775-4CF4-B37A-EB5E33CBD08C}.Verbose|x86.Build.0 = Verbose|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {4EF47C82-18DC-4E9E-A878-8C003FFB303D} | |||||
EndGlobalSection | |||||
EndGlobal |
@ -0,0 +1,52 @@ | |||||
import sys | |||||
import os | |||||
#import pefile | |||||
import io | |||||
import string | |||||
def main(): | |||||
path = os.path.dirname(os.path.realpath(sys.argv[0])) | |||||
file = sys.argv[1] | |||||
proxies = io.StringIO() | |||||
proxy_add = io.StringIO() | |||||
proxy_def = io.StringIO() | |||||
proxy_def_file = io.StringIO() | |||||
count = 0 | |||||
""" for dll in dlls: | |||||
pe = pefile.PE(dll, fast_load=True) | |||||
pe.parse_data_directories() | |||||
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: | |||||
name = exp.name.decode() | |||||
proxies.write("%s\n" % name) | |||||
proxy_add.write("ADD_ORIGINAL(%d, %s);\n" % (count, name)) | |||||
proxy_def.write("PROXY(%d, %s);\n" % (count, name)) | |||||
count = count + 1 """ | |||||
with open(file, "r") as includes: | |||||
names = includes.readlines() | |||||
for name in names: | |||||
name = name.strip() | |||||
proxies.write(f"{name}\n") | |||||
proxy_add.write(f"ADD_ORIGINAL({count}, {name});\n") | |||||
proxy_def.write(f"PROXY({count}, {name});\n") | |||||
proxy_def_file.write(f" {name} @{count+1}\n") | |||||
count = count + 1 | |||||
with open(f"{path}\\templates\\proxy_template.c", "r") as proxy_file: | |||||
new_proxy = string.Template(proxy_file.read()).safe_substitute(proxy_count=count, proxy_add=proxy_add.getvalue(), proxy_def=proxy_def.getvalue()) | |||||
with open(f"{path}\\..\\Proxy\\proxy.c", "w") as proxy_c_file: | |||||
proxy_c_file.write(new_proxy) | |||||
with open(f"{path}\\templates\\proxy_template.def", "r") as proxy_file: | |||||
new_proxy_def = string.Template(proxy_file.read()).safe_substitute(proxy_exports=proxy_def_file.getvalue()) | |||||
with open(f"{path}\\..\\Proxy\\proxy.def", "w") as proxy_def_file: | |||||
proxy_def_file.write(new_proxy_def) | |||||
if __name__ == "__main__": | |||||
main() |
@ -0,0 +1,34 @@ | |||||
/* ================================== | |||||
* COMPUTER GENERATED -- DO NOT EDIT | |||||
* ================================== | |||||
* | |||||
* This file contains the definitions for all proxy functions this DLL supports. | |||||
* | |||||
* The proxies are very simple functions that should be optimizied into a | |||||
* single JMP instruction without editing the stack at all. | |||||
* | |||||
* NOTE: While this works, this is a somewhat hackish approach that is based on how | |||||
* the compiler optimizes the code. That said, the proxy will not work on Debug build currently | |||||
* (that can be fixed by changing the appropriate compile flag that I am yet to locate). | |||||
*/ | |||||
#pragma warning( disable : 4244 ) | |||||
#include <windows.h> | |||||
#define ADD_ORIGINAL(i, name) originalFunctions[i] = GetProcAddress(dll, #name) | |||||
#define PROXY(i, name) \ | |||||
__declspec(dllexport) ULONG __stdcall name() \ | |||||
{ \ | |||||
return originalFunctions[i](); \ | |||||
} | |||||
FARPROC originalFunctions[${proxy_count}] = {0}; | |||||
void loadFunctions(HMODULE dll) | |||||
{ | |||||
${proxy_add} | |||||
} | |||||
${proxy_def} |
@ -0,0 +1,3 @@ | |||||
LIBRARY proxy.dll | |||||
EXPORTS | |||||
${proxy_exports} |
@ -0,0 +1,50 @@ | |||||
WinHttpAddRequestHeaders | |||||
WinHttpAutoProxySvcMain | |||||
WinHttpCheckPlatform | |||||
WinHttpCloseHandle | |||||
WinHttpConnect | |||||
WinHttpConnectionDeleteProxyInfo | |||||
WinHttpConnectionFreeNameList | |||||
WinHttpConnectionFreeProxyInfo | |||||
WinHttpConnectionFreeProxyList | |||||
WinHttpConnectionGetNameList | |||||
WinHttpConnectionGetProxyInfo | |||||
WinHttpConnectionGetProxyList | |||||
WinHttpConnectionSetProxyInfo | |||||
WinHttpCrackUrl | |||||
WinHttpCreateProxyResolver | |||||
WinHttpCreateUrl | |||||
WinHttpDetectAutoProxyConfigUrl | |||||
WinHttpFreeProxyResult | |||||
WinHttpGetDefaultProxyConfiguration | |||||
WinHttpGetIEProxyConfigForCurrentUser | |||||
WinHttpGetProxyForUrl | |||||
WinHttpGetProxyForUrlEx | |||||
WinHttpGetProxyResult | |||||
WinHttpGetTunnelSocket | |||||
WinHttpOpen | |||||
WinHttpOpenRequest | |||||
WinHttpProbeConnectivity | |||||
WinHttpQueryAuthSchemes | |||||
WinHttpQueryDataAvailable | |||||
WinHttpQueryHeaders | |||||
WinHttpQueryOption | |||||
WinHttpReadData | |||||
WinHttpReceiveResponse | |||||
WinHttpResetAutoProxy | |||||
WinHttpSaveProxyCredentials | |||||
WinHttpSendRequest | |||||
WinHttpSetCredentials | |||||
WinHttpSetDefaultProxyConfiguration | |||||
WinHttpSetOption | |||||
WinHttpSetStatusCallback | |||||
WinHttpSetTimeouts | |||||
WinHttpTimeFromSystemTime | |||||
WinHttpTimeToSystemTime | |||||
WinHttpWebSocketClose | |||||
WinHttpWebSocketCompleteUpgrade | |||||
WinHttpWebSocketQueryCloseStatus | |||||
WinHttpWebSocketReceive | |||||
WinHttpWebSocketSend | |||||
WinHttpWebSocketShutdown | |||||
WinHttpWriteData |