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 |