├── .gitmodules ├── License.txt ├── README.md ├── art ├── bang.afdesign └── bang.png ├── build └── VStudio │ ├── .gitignore │ ├── bang.dll.vcxproj │ ├── bang.dll.vcxproj.filters │ ├── bang.exe.vcxproj │ ├── bang.exe.vcxproj.filters │ ├── bang.sln │ └── testing │ ├── hook-test.vcxproj │ └── hook-test.vcxproj.filters ├── ext ├── include │ ├── detours.h │ └── detver.h └── lib │ ├── x64 │ ├── detours.lib │ └── detours.pdb │ └── x86 │ ├── detours.lib │ └── detours.pdb ├── src ├── dll │ ├── bang.c │ ├── bang.i │ ├── hookcp.c │ ├── hooksh.c │ ├── library.c │ ├── library.def │ └── library.h └── exe │ └── program.c ├── tools ├── build.bat ├── nmake-detours.bat └── vcvarsall.bat └── tst └── hook-test └── hook-test.c /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/detours"] 2 | path = ext/detours 3 | url = https://github.com/microsoft/Detours.git 4 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bill Zissimopoulos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | Bang - #! script execution for Windows 5 |

6 | 7 | 8 | Bang adds to Windows programs the ability to execute interpreter scripts. Such scripts start with the `#!` character sequence, sometimes referred to as "hash-bang" or "she-bang". 9 | 10 | A demonstration follows: 11 | 12 | - Create a simple Python script: 13 | 14 | ``` 15 | billziss@xps ⟩ ~ ⟩ Set-Content -Encoding ascii prargs.test 16 | 17 | cmdlet Set-Content at command pipeline position 1 18 | Supply values for the following parameters: 19 | Value[0]: #!/usr/bin/env python 20 | Value[1]: import sys; print(sys.argv) 21 | Value[2]: 22 | ``` 23 | 24 | - Attempt to execute: 25 | 26 | ``` 27 | billziss@xps ⟩ ~ ⟩ Start-Process .\prargs.test "10 20" -NoNewWindow -Wait 28 | Start-Process : This command cannot be run due to the error: %1 is not a valid Win32 application. 29 | At line:1 char:1 30 | + Start-Process .\prargs.test "10 20" -NoNewWindow -Wait 31 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | + CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException 33 | + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcess 34 | Command 35 | ``` 36 | 37 | - Start Bang and now it works: 38 | 39 | ``` 40 | billziss@xps ⟩ ~ ⟩ .\Projects\bang\build\VStudio\build\Release\bang64.exe -p -1 41 | billziss@xps ⟩ ~ ⟩ Start-Process .\prargs.test "10 20" -NoNewWindow -Wait 42 | ['C:\\Users\\billziss\\prargs.test', '10', '20'] 43 | ``` 44 | 45 | - Works in child processes as well: 46 | 47 | ``` 48 | billziss@xps ⟩ ~ ⟩ cmd 49 | Microsoft Windows [Version 10.0.22621.963] 50 | (c) Microsoft Corporation. All rights reserved. 51 | 52 | C:\Users\billziss>.\prargs.test 10 20 53 | ['.\\prargs.test', '10', '20'] 54 | ``` 55 | 56 | ## How to use 57 | 58 | From a shell prompt execute the command `bang64 -p -1` (or `bang32` on a 32-bit system). Your shell (and its children) will now have the "Bang" ability to execute interpreter scripts! 59 | 60 | Bang is a command line utility with the following usage: 61 | 62 | ``` 63 | usage: 64 | bang [-p -1|PID] 65 | bang COMMAND [ARG ...] 66 | ``` 67 | 68 | - The `-p PID` option is used to add the Bang ability to an existing process with ID `PID`. `PID` can be `-1` in which case the ability is added to Bang's parent process and any new processes started from that process. 69 | 70 | - Bang can also be used to start a new process `COMMAND` with arguments `ARG ...`. The new process and any processes started from that process will have the Bang ability. 71 | 72 | ## Script magic 73 | 74 | Bang supports two different character sequences for interpreter scripts: 75 | 76 | - **`#!/`**: This is the standard hash-bang sequence from Unix. For example: 77 | 78 | ``` 79 | #!/usr/bin/env python 80 | import sys; print(sys.argv) 81 | ``` 82 | 83 | A command line `.\script arguments-from-command-line` for a script with an interpreter line of `#!/interpreter optional-arguments`, results in executing `/interpreter` with the command line `.\script optional-arguments arguments-from-command-line`. 84 | 85 | - **`///`**: Languages such as C use `//` for line comments. Furthermore Unix shells will often attempt to interpret a file as a shell script if the file does not contain an executable header or the `#!` sequence. Sometimes this is used to make a C/C++/etc. program executable: 86 | 87 | ``` 88 | ///usr/bin/env gcc "$0"; exit 89 | int main() { return 0; } 90 | ``` 91 | 92 | (The 3-slash convention originated on Unix-like environments (like Cygwin) that treat 2 slashes specially.) 93 | 94 | Bang supports a very limited form of this syntax. It does not understand any of the Unix shell syntax although it knows to strip the terminating `; exit`. It also supports variables `$0`-`$9` and the `$@` and `"$@"` incantations with a meaning similar (but not the same) to the one in the Unix shell. (In particular note that Bang treats quotes and backslashes as normal characters, except for the special case of `"$@"`.) 95 | 96 | Bang uses a "Pathmap" to translate Unix-like interpreter paths to Windows-like interpreter paths. This Pathmap is configurable (see the Configuration section) but there is an internal default "Pathmap" that provides reasonable defaults: 97 | 98 | - `/usr/bin/env COMMAND`: Instructs Bang to look for `COMMAND` in the `PATH`. 99 | 100 | - `/usr/bin/COMMAND`: Instructs Bang to look for `COMMAND` in the `%SYSTEMROOT%\System32` directory (usually `C:\Windows\system32`). 101 | 102 | ## Configuration 103 | 104 | Bang can be configured via the registry key `HKEY_CURRENT_USER\Software\Bang`. (The `HKEY_CURRENT_USER` key is specific to a particular user.) The following settings are available. All settings are of type "String" (`REG_SZ`) or "Expandable String" (`REG_EXPAND_SZ`). 105 | 106 | - `Pathmap`: Controls the mapping of Unix-like paths to Windows-like paths. The syntax is `UnixPath*[WindowsPath][;...]` where `UnixPath` is a Unix-like path (e.g. `/usr/bin/`) and `WindowsPath` is a Windows-like path (e.g. `C:\Windows\System32\`). 107 | 108 | - The mappings specified in the Pathmap are attempted in order. 109 | 110 | - If `WindowsPath` is missing then searches are performed according to the `PATH` environment variable. 111 | 112 | - If `UnixPath` ends in slash `/` then it refers to a directory and matches against it are performed using prefix-matching. In this case `WindowsPath` must end in a backslash `\` and the `UnixPath` will be replaced by the `WindowsPath`. For example, the Pathmap `/usr/bin/*C:\Windows\System32\` will map `/usr/bin/cmd` to `C:\Windows\System32\cmd.exe` and the Pathmap `/usr/bin/*` will map `/usr/bin/cmd` to the `cmd.exe` file found by a `PATH` search. 113 | 114 | - If `UnixPath` does not end in slash then behavior depends: - If `WindowsPath` is missing then Bang will use the first optional argument in the intepreter line as the program to find by a `PATH` search. For example, the Pathmap `/usr/bin/env*` will map the interpreter line `#!/usr/bin/env cmd` to the `cmd.exe` file found by a `PATH` search. - If `WindowsPath` is present then Bang will simply substitute the `WindowsPath` in place of the `UnixPath`. For example, the Pathmap `/usr/bin/cmd*C:\Windows\System32\cmd.exe` will perform the obvious substitution. 115 | 116 | - The internal default Pathmap is the following: 117 | 118 | ``` 119 | /usr/bin/env*;/usr/bin/*%SYSTEMROOT%\System32\;/bin/*%SYSTEMROOT%\System32\ 120 | ``` 121 | 122 | - `Directories`: Controls the directory trees within which interpreter scripts must reside in order to be executable by Bang. The syntax is: `WindowsPath[;...]` and any specified `WindowsPath` must end in a backslash `\`. If the `Directories` setting is missing (the default) all scripts are executable by Bang regardless of location. 123 | 124 | - For example, the following setting will allow execution of scripts from the `.bin` and `Projects` directory subtrees only: 125 | 126 | ``` 127 | %USERPROFILE%\.bin\;%USERPROFILE%\Projects\ 128 | ``` 129 | 130 | - `Programs`: Controls the programs that can inherit the Bang ability. The syntax is: `WindowsPath[;...]`. The specified `WindowsPath` may be a fully qualified path such as `C:\Windows\System32\cmd.exe` or it may be a base file name such as `cmd.exe`. If the `Programs` setting is missing (the default) all programs can inherit the Bang ability. 131 | 132 | - For example, the following setting will allow only `cmd.exe` and `powershell.exe` to inherit the Bang ability: 133 | 134 | ``` 135 | C:\Windows\System32\cmd.exe;powershell.exe 136 | ``` 137 | 138 | ## How it works 139 | 140 | Bang consists of a command line utility (EXE) and a dynamic link library (DLL). When Bang "injects" its DLL into a process, that process acquires the Bang ability. Any new process started from a process that has the Bang ability is also bestowed the Bang ability (but see the Configuration section for how to control which processes inherit the Bang ability). 141 | 142 | The Bang DLL uses the Microsoft [Detours](https://github.com/microsoft/Detours) library to intercept calls to the `CreateProcess` and `ShellExecute` API's, which are used to create new processes on Windows. When Bang receives an intercepted `CreateProcess` call, it examines the executed file to see if it starts with one of the character sequences `#!/` or `///`. If either sequence is found, then the file is treated as an interpreter script and the `CreateProcess` call is altered accordingly. 143 | 144 | ## Security 145 | 146 | There are two main security concerns: 147 | 148 | - Bang enables any text file to become executable by simply adding the `#!/` or `///` script magic. To mitigate this risk use the `Directories` configuration setting to control the directory trees where scripts can reside. 149 | 150 | - Bang injects its DLL into other processes. This DLL represents foreign code to these processes and has an associated risk. To mitigate this risk use the `Programs` configuration setting to control which processes inherit the Bang ability. 151 | 152 | ## Limitations 153 | 154 | Although a process with the Bang ability can execute interpreter scripts, some processes do not always know what to do with their newfound ability. 155 | 156 | For example, Powershell with the Bang ability does not know that it is able to execute non-EXE files. Consequently it treats them as document files and attempts to open them via `ShellExecute`. This still works because Bang also intercepts `ShellExecute`, but the experience is not quite the same as with native programs. 157 | 158 | ``` 159 | billziss@xps ⟩ ~ ⟩ .\prargs.test | sort 160 | Cannot run a document in the middle of a pipeline: C:\Users\billziss\prargs.test. 161 | At line:1 char:1 162 | + .\prargs.test | sort 163 | + ~~~~~~~~~~~~~ 164 | + CategoryInfo : InvalidOperation: (C:\Users\billziss\prargs.test:String) [], Runtime 165 | Exception 166 | + FullyQualifiedErrorId : CantActivateDocumentInPipeline 167 | 168 | billziss@xps ⟩ ~ ⟩ Start-Process .\prargs.test -NoNewWindow -Wait | sort 169 | ['C:\\Users\\billziss\\prargs.test'] 170 | ``` 171 | 172 | There is work-in-progress to improve this experience. One trick that works is to place your script's extension in the `PATHEXT` environment variable or to simply name your script with a `.exe` extension! 173 | 174 | ``` 175 | billziss@xps ⟩ ~ ⟩ mv .\prargs.test .\prargs.exe 176 | billziss@xps ⟩ ~ ⟩ .\prargs.exe | sort 177 | ['C:\\Users\\billziss\\prargs.exe'] 178 | ``` 179 | -------------------------------------------------------------------------------- /art/bang.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/art/bang.afdesign -------------------------------------------------------------------------------- /art/bang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/art/bang.png -------------------------------------------------------------------------------- /build/VStudio/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.ncb 3 | *.suo 4 | *.vcproj.* 5 | *.vcxproj.user 6 | *.csproj.user 7 | *.VC.db 8 | *.VC.opendb 9 | .vs 10 | -------------------------------------------------------------------------------- /build/VStudio/bang.dll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 16.0 36 | Win32Proj 37 | {4bfa19e8-7eec-4cc7-aed6-3b9fa906daae} 38 | bangdll 39 | $(LatestTargetPlatformVersion) 40 | 41 | 42 | 43 | DynamicLibrary 44 | true 45 | $(DefaultPlatformToolset) 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | $(DefaultPlatformToolset) 52 | true 53 | Unicode 54 | 55 | 56 | DynamicLibrary 57 | true 58 | $(DefaultPlatformToolset) 59 | Unicode 60 | 61 | 62 | DynamicLibrary 63 | false 64 | $(DefaultPlatformToolset) 65 | true 66 | Unicode 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | false 88 | $(SolutionDir)build\$(Configuration)\ 89 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 90 | $(SolutionName)$(PlatformArchitecture) 91 | 92 | 93 | false 94 | $(SolutionDir)build\$(Configuration)\ 95 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 96 | $(SolutionName)$(PlatformArchitecture) 97 | 98 | 99 | false 100 | $(SolutionDir)build\$(Configuration)\ 101 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 102 | $(SolutionName)$(PlatformArchitecture) 103 | 104 | 105 | false 106 | $(SolutionDir)build\$(Configuration)\ 107 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 108 | $(SolutionName)$(PlatformArchitecture) 109 | 110 | 111 | 112 | Level3 113 | WIN32;_DEBUG;BANG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 114 | ..\..\src;..\..\ext\include 115 | ProgramDatabase 116 | Default 117 | MultiThreaded 118 | false 119 | 120 | 121 | Windows 122 | true 123 | false 124 | ..\..\ext\lib\$(PlatformTarget)\detours.lib;%(AdditionalDependencies) 125 | ..\..\src\dll\library.def 126 | $(OutDir)$(TargetFileName).pdb 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | WIN32;NDEBUG;BANG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 135 | ..\..\src;..\..\ext\include 136 | MultiThreaded 137 | false 138 | 139 | 140 | Windows 141 | true 142 | true 143 | true 144 | false 145 | ..\..\ext\lib\$(PlatformTarget)\detours.lib;%(AdditionalDependencies) 146 | ..\..\src\dll\library.def 147 | $(OutDir)$(TargetFileName).pdb 148 | 149 | 150 | 151 | 152 | Level3 153 | _DEBUG;BANG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 154 | ..\..\src;..\..\ext\include 155 | ProgramDatabase 156 | Default 157 | MultiThreaded 158 | false 159 | 160 | 161 | Windows 162 | true 163 | false 164 | ..\..\ext\lib\$(PlatformTarget)\detours.lib;%(AdditionalDependencies) 165 | ..\..\src\dll\library.def 166 | $(OutDir)$(TargetFileName).pdb 167 | 168 | 169 | 170 | 171 | Level3 172 | true 173 | true 174 | NDEBUG;BANG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 175 | ..\..\src;..\..\ext\include 176 | MultiThreaded 177 | false 178 | 179 | 180 | Windows 181 | true 182 | true 183 | true 184 | false 185 | ..\..\ext\lib\$(PlatformTarget)\detours.lib;%(AdditionalDependencies) 186 | ..\..\src\dll\library.def 187 | $(OutDir)$(TargetFileName).pdb 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /build/VStudio/bang.dll.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source 12 | 13 | 14 | Source 15 | 16 | 17 | Source 18 | 19 | 20 | Source 21 | 22 | 23 | 24 | 25 | Source 26 | 27 | 28 | Source 29 | 30 | 31 | 32 | 33 | Source 34 | 35 | 36 | -------------------------------------------------------------------------------- /build/VStudio/bang.exe.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 16.0 26 | Win32Proj 27 | {f9291315-85bc-41d5-8d2c-fa387fd23ffd} 28 | bangexe 29 | $(LatestTargetPlatformVersion) 30 | 31 | 32 | 33 | Application 34 | true 35 | $(DefaultPlatformToolset) 36 | Unicode 37 | 38 | 39 | Application 40 | false 41 | $(DefaultPlatformToolset) 42 | true 43 | Unicode 44 | 45 | 46 | Application 47 | true 48 | $(DefaultPlatformToolset) 49 | Unicode 50 | 51 | 52 | Application 53 | false 54 | $(DefaultPlatformToolset) 55 | true 56 | Unicode 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | $(SolutionDir)build\$(Configuration)\ 78 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 79 | $(SolutionName)$(PlatformArchitecture) 80 | 81 | 82 | $(SolutionDir)build\$(Configuration)\ 83 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 84 | $(SolutionName)$(PlatformArchitecture) 85 | 86 | 87 | $(SolutionDir)build\$(Configuration)\ 88 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 89 | $(SolutionName)$(PlatformArchitecture) 90 | 91 | 92 | $(SolutionDir)build\$(Configuration)\ 93 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 94 | $(SolutionName)$(PlatformArchitecture) 95 | 96 | 97 | 98 | Level3 99 | _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 100 | ProgramDatabase 101 | Default 102 | MultiThreaded 103 | false 104 | 105 | 106 | Console 107 | true 108 | $(OutDir)$(TargetFileName).pdb 109 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;ntdll.lib;%(AdditionalDependencies) 110 | 111 | 112 | 113 | 114 | Level3 115 | true 116 | true 117 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | MultiThreaded 119 | false 120 | MinSpace 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | $(OutDir)$(TargetFileName).pdb 128 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;ntdll.lib;%(AdditionalDependencies) 129 | 130 | 131 | 132 | 133 | Level3 134 | _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | ProgramDatabase 136 | Default 137 | MultiThreaded 138 | false 139 | 140 | 141 | Console 142 | true 143 | $(OutDir)$(TargetFileName).pdb 144 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;ntdll.lib;%(AdditionalDependencies) 145 | 146 | 147 | 148 | 149 | Level3 150 | true 151 | true 152 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 153 | MultiThreaded 154 | false 155 | MinSpace 156 | 157 | 158 | Console 159 | true 160 | true 161 | true 162 | $(OutDir)$(TargetFileName).pdb 163 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;ntdll.lib;%(AdditionalDependencies) 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /build/VStudio/bang.exe.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source 12 | 13 | 14 | -------------------------------------------------------------------------------- /build/VStudio/bang.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33205.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bang.exe", "bang.exe.vcxproj", "{F9291315-85BC-41D5-8D2C-FA387FD23FFD}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE} = {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bang.dll", "bang.dll.vcxproj", "{4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hook-test", "testing\hook-test.vcxproj", "{90E03F99-8643-439E-BBE4-0D8895743BAA}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE} = {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE} 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Debug|x64.ActiveCfg = Debug|x64 27 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Debug|x64.Build.0 = Debug|x64 28 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Debug|x86.ActiveCfg = Debug|Win32 29 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Debug|x86.Build.0 = Debug|Win32 30 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Release|x64.ActiveCfg = Release|x64 31 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Release|x64.Build.0 = Release|x64 32 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Release|x86.ActiveCfg = Release|Win32 33 | {4BFA19E8-7EEC-4CC7-AED6-3B9FA906DAAE}.Release|x86.Build.0 = Release|Win32 34 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Debug|x64.ActiveCfg = Debug|x64 35 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Debug|x64.Build.0 = Debug|x64 36 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Debug|x86.ActiveCfg = Debug|Win32 37 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Debug|x86.Build.0 = Debug|Win32 38 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Release|x64.ActiveCfg = Release|x64 39 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Release|x64.Build.0 = Release|x64 40 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Release|x86.ActiveCfg = Release|Win32 41 | {90E03F99-8643-439E-BBE4-0D8895743BAA}.Release|x86.Build.0 = Release|Win32 42 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Debug|x64.ActiveCfg = Debug|x64 43 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Debug|x64.Build.0 = Debug|x64 44 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Debug|x86.ActiveCfg = Debug|Win32 45 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Debug|x86.Build.0 = Debug|Win32 46 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Release|x64.ActiveCfg = Release|x64 47 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Release|x64.Build.0 = Release|x64 48 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Release|x86.ActiveCfg = Release|Win32 49 | {F9291315-85BC-41D5-8D2C-FA387FD23FFD}.Release|x86.Build.0 = Release|Win32 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | GlobalSection(ExtensibilityGlobals) = postSolution 55 | SolutionGuid = {FA594EE9-476F-4993-B838-B20CA7E15CE1} 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /build/VStudio/testing/hook-test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 16.0 26 | Win32Proj 27 | {90e03f99-8643-439e-bbe4-0d8895743baa} 28 | hooktest 29 | $(LatestTargetPlatformVersion) 30 | 31 | 32 | 33 | Application 34 | true 35 | $(DefaultPlatformToolset) 36 | Unicode 37 | 38 | 39 | Application 40 | false 41 | $(DefaultPlatformToolset) 42 | true 43 | Unicode 44 | 45 | 46 | Application 47 | true 48 | $(DefaultPlatformToolset) 49 | Unicode 50 | 51 | 52 | Application 53 | false 54 | $(DefaultPlatformToolset) 55 | true 56 | Unicode 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | $(SolutionDir)build\$(Configuration)\ 78 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 79 | $(ProjectName)$(PlatformArchitecture) 80 | false 81 | 82 | 83 | $(SolutionDir)build\$(Configuration)\ 84 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 85 | $(ProjectName)$(PlatformArchitecture) 86 | false 87 | 88 | 89 | $(SolutionDir)build\$(Configuration)\ 90 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 91 | $(ProjectName)$(PlatformArchitecture) 92 | false 93 | 94 | 95 | $(SolutionDir)build\$(Configuration)\ 96 | $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(MyProductFileArch)\ 97 | $(ProjectName)$(PlatformArchitecture) 98 | false 99 | 100 | 101 | 102 | Level3 103 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | ProgramDatabase 105 | Default 106 | MultiThreaded 107 | false 108 | 109 | 110 | Console 111 | true 112 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;%(AdditionalDependencies) 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | MultiThreaded 122 | false 123 | 124 | 125 | Console 126 | true 127 | true 128 | true 129 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;%(AdditionalDependencies) 130 | 131 | 132 | 133 | 134 | Level3 135 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | ProgramDatabase 137 | Default 138 | MultiThreaded 139 | false 140 | 141 | 142 | Console 143 | true 144 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;%(AdditionalDependencies) 145 | 146 | 147 | 148 | 149 | Level3 150 | true 151 | true 152 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 153 | MultiThreaded 154 | false 155 | 156 | 157 | Console 158 | true 159 | true 160 | true 161 | $(SolutionDir)build\$(Configuration)\$(SolutionName)$(PlatformArchitecture).lib;%(AdditionalDependencies) 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /build/VStudio/testing/hook-test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source 12 | 13 | 14 | -------------------------------------------------------------------------------- /ext/include/detours.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Core Detours Functionality (detours.h of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #pragma once 11 | #ifndef _DETOURS_H_ 12 | #define _DETOURS_H_ 13 | 14 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | // 18 | 19 | #undef DETOURS_X64 20 | #undef DETOURS_X86 21 | #undef DETOURS_IA64 22 | #undef DETOURS_ARM 23 | #undef DETOURS_ARM64 24 | #undef DETOURS_BITS 25 | #undef DETOURS_32BIT 26 | #undef DETOURS_64BIT 27 | 28 | #if defined(_X86_) 29 | #define DETOURS_X86 30 | #define DETOURS_OPTION_BITS 64 31 | 32 | #elif defined(_AMD64_) 33 | #define DETOURS_X64 34 | #define DETOURS_OPTION_BITS 32 35 | 36 | #elif defined(_IA64_) 37 | #define DETOURS_IA64 38 | #define DETOURS_OPTION_BITS 32 39 | 40 | #elif defined(_ARM_) 41 | #define DETOURS_ARM 42 | 43 | #elif defined(_ARM64_) 44 | #define DETOURS_ARM64 45 | 46 | #else 47 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 48 | #endif 49 | 50 | #ifdef _WIN64 51 | #undef DETOURS_32BIT 52 | #define DETOURS_64BIT 1 53 | #define DETOURS_BITS 64 54 | // If all 64bit kernels can run one and only one 32bit architecture. 55 | //#define DETOURS_OPTION_BITS 32 56 | #else 57 | #define DETOURS_32BIT 1 58 | #undef DETOURS_64BIT 59 | #define DETOURS_BITS 32 60 | // If all 64bit kernels can run one and only one 32bit architecture. 61 | //#define DETOURS_OPTION_BITS 32 62 | #endif 63 | 64 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 65 | 66 | ////////////////////////////////////////////////////////////////////////////// 67 | // 68 | 69 | #if (_MSC_VER < 1299) 70 | typedef LONG LONG_PTR; 71 | typedef ULONG ULONG_PTR; 72 | #endif 73 | 74 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 75 | // 76 | // These definitions are include so that Detours will build even if the 77 | // compiler doesn't have full SAL 2.0 support. 78 | // 79 | #ifndef DETOURS_DONT_REMOVE_SAL_20 80 | 81 | #ifdef DETOURS_TEST_REMOVE_SAL_20 82 | #undef _Analysis_assume_ 83 | #undef _Benign_race_begin_ 84 | #undef _Benign_race_end_ 85 | #undef _Field_range_ 86 | #undef _Field_size_ 87 | #undef _In_ 88 | #undef _In_bytecount_ 89 | #undef _In_count_ 90 | #undef _In_opt_ 91 | #undef _In_opt_bytecount_ 92 | #undef _In_opt_count_ 93 | #undef _In_opt_z_ 94 | #undef _In_range_ 95 | #undef _In_reads_ 96 | #undef _In_reads_bytes_ 97 | #undef _In_reads_opt_ 98 | #undef _In_reads_opt_bytes_ 99 | #undef _In_reads_or_z_ 100 | #undef _In_z_ 101 | #undef _Inout_ 102 | #undef _Inout_opt_ 103 | #undef _Inout_z_count_ 104 | #undef _Out_ 105 | #undef _Out_opt_ 106 | #undef _Out_writes_ 107 | #undef _Outptr_result_maybenull_ 108 | #undef _Readable_bytes_ 109 | #undef _Success_ 110 | #undef _Writable_bytes_ 111 | #undef _Pre_notnull_ 112 | #endif 113 | 114 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 115 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 116 | #endif 117 | 118 | #if defined(_In_count_) && !defined(_In_reads_) 119 | #define _In_reads_(x) _In_count_(x) 120 | #endif 121 | 122 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 123 | #define _In_reads_opt_(x) _In_opt_count_(x) 124 | #endif 125 | 126 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 127 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 128 | #endif 129 | 130 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 131 | #define _In_reads_bytes_(x) _In_bytecount_(x) 132 | #endif 133 | 134 | #ifndef _In_ 135 | #define _In_ 136 | #endif 137 | 138 | #ifndef _In_bytecount_ 139 | #define _In_bytecount_(x) 140 | #endif 141 | 142 | #ifndef _In_count_ 143 | #define _In_count_(x) 144 | #endif 145 | 146 | #ifndef _In_opt_ 147 | #define _In_opt_ 148 | #endif 149 | 150 | #ifndef _In_opt_bytecount_ 151 | #define _In_opt_bytecount_(x) 152 | #endif 153 | 154 | #ifndef _In_opt_count_ 155 | #define _In_opt_count_(x) 156 | #endif 157 | 158 | #ifndef _In_opt_z_ 159 | #define _In_opt_z_ 160 | #endif 161 | 162 | #ifndef _In_range_ 163 | #define _In_range_(x,y) 164 | #endif 165 | 166 | #ifndef _In_reads_ 167 | #define _In_reads_(x) 168 | #endif 169 | 170 | #ifndef _In_reads_bytes_ 171 | #define _In_reads_bytes_(x) 172 | #endif 173 | 174 | #ifndef _In_reads_opt_ 175 | #define _In_reads_opt_(x) 176 | #endif 177 | 178 | #ifndef _In_reads_opt_bytes_ 179 | #define _In_reads_opt_bytes_(x) 180 | #endif 181 | 182 | #ifndef _In_reads_or_z_ 183 | #define _In_reads_or_z_ 184 | #endif 185 | 186 | #ifndef _In_z_ 187 | #define _In_z_ 188 | #endif 189 | 190 | #ifndef _Inout_ 191 | #define _Inout_ 192 | #endif 193 | 194 | #ifndef _Inout_opt_ 195 | #define _Inout_opt_ 196 | #endif 197 | 198 | #ifndef _Inout_z_count_ 199 | #define _Inout_z_count_(x) 200 | #endif 201 | 202 | #ifndef _Out_ 203 | #define _Out_ 204 | #endif 205 | 206 | #ifndef _Out_opt_ 207 | #define _Out_opt_ 208 | #endif 209 | 210 | #ifndef _Out_writes_ 211 | #define _Out_writes_(x) 212 | #endif 213 | 214 | #ifndef _Outptr_result_maybenull_ 215 | #define _Outptr_result_maybenull_ 216 | #endif 217 | 218 | #ifndef _Writable_bytes_ 219 | #define _Writable_bytes_(x) 220 | #endif 221 | 222 | #ifndef _Readable_bytes_ 223 | #define _Readable_bytes_(x) 224 | #endif 225 | 226 | #ifndef _Success_ 227 | #define _Success_(x) 228 | #endif 229 | 230 | #ifndef _Pre_notnull_ 231 | #define _Pre_notnull_ 232 | #endif 233 | 234 | #ifdef DETOURS_INTERNAL 235 | 236 | #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) 237 | 238 | #ifndef _Benign_race_begin_ 239 | #define _Benign_race_begin_ 240 | #endif 241 | 242 | #ifndef _Benign_race_end_ 243 | #define _Benign_race_end_ 244 | #endif 245 | 246 | #ifndef _Field_size_ 247 | #define _Field_size_(x) 248 | #endif 249 | 250 | #ifndef _Field_range_ 251 | #define _Field_range_(x,y) 252 | #endif 253 | 254 | #ifndef _Analysis_assume_ 255 | #define _Analysis_assume_(x) 256 | #endif 257 | 258 | #endif // DETOURS_INTERNAL 259 | #endif // DETOURS_DONT_REMOVE_SAL_20 260 | 261 | ////////////////////////////////////////////////////////////////////////////// 262 | // 263 | #ifndef GUID_DEFINED 264 | #define GUID_DEFINED 265 | typedef struct _GUID 266 | { 267 | DWORD Data1; 268 | WORD Data2; 269 | WORD Data3; 270 | BYTE Data4[ 8 ]; 271 | } GUID; 272 | 273 | #ifdef INITGUID 274 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 275 | const GUID name \ 276 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 277 | #else 278 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 279 | const GUID name 280 | #endif // INITGUID 281 | #endif // !GUID_DEFINED 282 | 283 | #if defined(__cplusplus) 284 | #ifndef _REFGUID_DEFINED 285 | #define _REFGUID_DEFINED 286 | #define REFGUID const GUID & 287 | #endif // !_REFGUID_DEFINED 288 | #else // !__cplusplus 289 | #ifndef _REFGUID_DEFINED 290 | #define _REFGUID_DEFINED 291 | #define REFGUID const GUID * const 292 | #endif // !_REFGUID_DEFINED 293 | #endif // !__cplusplus 294 | 295 | #ifndef ARRAYSIZE 296 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 297 | #endif 298 | 299 | // 300 | ////////////////////////////////////////////////////////////////////////////// 301 | 302 | #ifdef __cplusplus 303 | extern "C" { 304 | #endif // __cplusplus 305 | 306 | /////////////////////////////////////////////////// Instruction Target Macros. 307 | // 308 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 309 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 310 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 311 | 312 | extern const GUID DETOUR_EXE_RESTORE_GUID; 313 | extern const GUID DETOUR_EXE_HELPER_GUID; 314 | 315 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 316 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 317 | 318 | /////////////////////////////////////////////////////////// Binary Structures. 319 | // 320 | #pragma pack(push, 8) 321 | typedef struct _DETOUR_SECTION_HEADER 322 | { 323 | DWORD cbHeaderSize; 324 | DWORD nSignature; 325 | DWORD nDataOffset; 326 | DWORD cbDataSize; 327 | 328 | DWORD nOriginalImportVirtualAddress; 329 | DWORD nOriginalImportSize; 330 | DWORD nOriginalBoundImportVirtualAddress; 331 | DWORD nOriginalBoundImportSize; 332 | 333 | DWORD nOriginalIatVirtualAddress; 334 | DWORD nOriginalIatSize; 335 | DWORD nOriginalSizeOfImage; 336 | DWORD cbPrePE; 337 | 338 | DWORD nOriginalClrFlags; 339 | DWORD reserved1; 340 | DWORD reserved2; 341 | DWORD reserved3; 342 | 343 | // Followed by cbPrePE bytes of data. 344 | } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; 345 | 346 | typedef struct _DETOUR_SECTION_RECORD 347 | { 348 | DWORD cbBytes; 349 | DWORD nReserved; 350 | GUID guid; 351 | } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; 352 | 353 | typedef struct _DETOUR_CLR_HEADER 354 | { 355 | // Header versioning 356 | ULONG cb; 357 | USHORT MajorRuntimeVersion; 358 | USHORT MinorRuntimeVersion; 359 | 360 | // Symbol table and startup information 361 | IMAGE_DATA_DIRECTORY MetaData; 362 | ULONG Flags; 363 | 364 | // Followed by the rest of the IMAGE_COR20_HEADER 365 | } DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; 366 | 367 | typedef struct _DETOUR_EXE_RESTORE 368 | { 369 | DWORD cb; 370 | DWORD cbidh; 371 | DWORD cbinh; 372 | DWORD cbclr; 373 | 374 | PBYTE pidh; 375 | PBYTE pinh; 376 | PBYTE pclr; 377 | 378 | IMAGE_DOS_HEADER idh; 379 | union { 380 | IMAGE_NT_HEADERS inh; 381 | IMAGE_NT_HEADERS32 inh32; 382 | IMAGE_NT_HEADERS64 inh64; 383 | BYTE raw[sizeof(IMAGE_NT_HEADERS64) + 384 | sizeof(IMAGE_SECTION_HEADER) * 32]; 385 | }; 386 | DETOUR_CLR_HEADER clr; 387 | 388 | } DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; 389 | 390 | typedef struct _DETOUR_EXE_HELPER 391 | { 392 | DWORD cb; 393 | DWORD pid; 394 | DWORD nDlls; 395 | CHAR rDlls[4]; 396 | } DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; 397 | 398 | #pragma pack(pop) 399 | 400 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 401 | { \ 402 | sizeof(DETOUR_SECTION_HEADER),\ 403 | DETOUR_SECTION_HEADER_SIGNATURE,\ 404 | sizeof(DETOUR_SECTION_HEADER),\ 405 | (cbSectionSize),\ 406 | \ 407 | 0,\ 408 | 0,\ 409 | 0,\ 410 | 0,\ 411 | \ 412 | 0,\ 413 | 0,\ 414 | 0,\ 415 | 0,\ 416 | } 417 | 418 | /////////////////////////////////////////////////////////////// Helper Macros. 419 | // 420 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 421 | #define DETOURS_STRINGIFY_(x) #x 422 | 423 | ///////////////////////////////////////////////////////////// Binary Typedefs. 424 | // 425 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 426 | _In_opt_ PVOID pContext, 427 | _In_opt_ LPCSTR pszFile, 428 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 429 | 430 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 431 | _In_opt_ PVOID pContext, 432 | _In_ LPCSTR pszOrigFile, 433 | _In_ LPCSTR pszFile, 434 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 435 | 436 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 437 | _In_opt_ PVOID pContext, 438 | _In_ ULONG nOrigOrdinal, 439 | _In_ ULONG nOrdinal, 440 | _Out_ ULONG *pnOutOrdinal, 441 | _In_opt_ LPCSTR pszOrigSymbol, 442 | _In_opt_ LPCSTR pszSymbol, 443 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 444 | 445 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 446 | _In_opt_ PVOID pContext); 447 | 448 | typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 449 | _In_ ULONG nOrdinal, 450 | _In_opt_ LPCSTR pszName, 451 | _In_opt_ PVOID pCode); 452 | 453 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 454 | _In_opt_ HMODULE hModule, 455 | _In_opt_ LPCSTR pszFile); 456 | 457 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 458 | _In_ DWORD nOrdinal, 459 | _In_opt_ LPCSTR pszFunc, 460 | _In_opt_ PVOID pvFunc); 461 | 462 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 463 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 464 | _In_ DWORD nOrdinal, 465 | _In_opt_ LPCSTR pszFunc, 466 | _In_opt_ PVOID* ppvFunc); 467 | 468 | typedef VOID * PDETOUR_BINARY; 469 | typedef VOID * PDETOUR_LOADED_BINARY; 470 | 471 | //////////////////////////////////////////////////////////// Transaction APIs. 472 | // 473 | LONG WINAPI DetourTransactionBegin(VOID); 474 | LONG WINAPI DetourTransactionAbort(VOID); 475 | LONG WINAPI DetourTransactionCommit(VOID); 476 | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 477 | 478 | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); 479 | 480 | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, 481 | _In_ PVOID pDetour); 482 | 483 | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, 484 | _In_ PVOID pDetour, 485 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 486 | _Out_opt_ PVOID *ppRealTarget, 487 | _Out_opt_ PVOID *ppRealDetour); 488 | 489 | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, 490 | _In_ PVOID pDetour); 491 | 492 | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 493 | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); 494 | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 495 | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 496 | 497 | ////////////////////////////////////////////////////////////// Code Functions. 498 | // 499 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 500 | _In_ LPCSTR pszFunction); 501 | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, 502 | _Out_opt_ PVOID *ppGlobals); 503 | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, 504 | _Inout_opt_ PVOID *ppDstPool, 505 | _In_ PVOID pSrc, 506 | _Out_opt_ PVOID *ppTarget, 507 | _Out_opt_ LONG *plExtra); 508 | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, 509 | _In_ BOOL fLimitReferencesToModule); 510 | 511 | ///////////////////////////////////////////////////// Loaded Binary Functions. 512 | // 513 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); 514 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); 515 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); 516 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); 517 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, 518 | _In_opt_ PVOID pContext, 519 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); 520 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, 521 | _In_opt_ PVOID pContext, 522 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 523 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); 524 | 525 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, 526 | _In_opt_ PVOID pContext, 527 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 528 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); 529 | 530 | _Writable_bytes_(*pcbData) 531 | _Readable_bytes_(*pcbData) 532 | _Success_(return != NULL) 533 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, 534 | _In_ REFGUID rguid, 535 | _Out_ DWORD *pcbData); 536 | 537 | _Writable_bytes_(*pcbData) 538 | _Readable_bytes_(*pcbData) 539 | _Success_(return != NULL) 540 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, 541 | _Out_ DWORD * pcbData); 542 | 543 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); 544 | 545 | ///////////////////////////////////////////////// Persistent Binary Functions. 546 | // 547 | 548 | PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); 549 | 550 | _Writable_bytes_(*pcbData) 551 | _Readable_bytes_(*pcbData) 552 | _Success_(return != NULL) 553 | PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, 554 | _Out_opt_ GUID *pGuid, 555 | _Out_ DWORD *pcbData, 556 | _Inout_ DWORD *pnIterator); 557 | 558 | _Writable_bytes_(*pcbData) 559 | _Readable_bytes_(*pcbData) 560 | _Success_(return != NULL) 561 | PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, 562 | _In_ REFGUID rguid, 563 | _Out_ DWORD *pcbData); 564 | 565 | PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, 566 | _In_ REFGUID rguid, 567 | _In_reads_opt_(cbData) PVOID pData, 568 | _In_ DWORD cbData); 569 | BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); 570 | BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); 571 | BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); 572 | BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, 573 | _In_opt_ PVOID pContext, 574 | _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, 575 | _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, 576 | _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, 577 | _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); 578 | BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); 579 | BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); 580 | 581 | /////////////////////////////////////////////////// Create Process & Load Dll. 582 | // 583 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( 584 | _In_opt_ LPCSTR lpApplicationName, 585 | _Inout_opt_ LPSTR lpCommandLine, 586 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 587 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 588 | _In_ BOOL bInheritHandles, 589 | _In_ DWORD dwCreationFlags, 590 | _In_opt_ LPVOID lpEnvironment, 591 | _In_opt_ LPCSTR lpCurrentDirectory, 592 | _In_ LPSTARTUPINFOA lpStartupInfo, 593 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 594 | 595 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( 596 | _In_opt_ LPCWSTR lpApplicationName, 597 | _Inout_opt_ LPWSTR lpCommandLine, 598 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 599 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 600 | _In_ BOOL bInheritHandles, 601 | _In_ DWORD dwCreationFlags, 602 | _In_opt_ LPVOID lpEnvironment, 603 | _In_opt_ LPCWSTR lpCurrentDirectory, 604 | _In_ LPSTARTUPINFOW lpStartupInfo, 605 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 606 | 607 | BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, 608 | _Inout_opt_ LPSTR lpCommandLine, 609 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 610 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 611 | _In_ BOOL bInheritHandles, 612 | _In_ DWORD dwCreationFlags, 613 | _In_opt_ LPVOID lpEnvironment, 614 | _In_opt_ LPCSTR lpCurrentDirectory, 615 | _In_ LPSTARTUPINFOA lpStartupInfo, 616 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 617 | _In_ LPCSTR lpDllName, 618 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 619 | 620 | BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, 621 | _Inout_opt_ LPWSTR lpCommandLine, 622 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 623 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 624 | _In_ BOOL bInheritHandles, 625 | _In_ DWORD dwCreationFlags, 626 | _In_opt_ LPVOID lpEnvironment, 627 | _In_opt_ LPCWSTR lpCurrentDirectory, 628 | _In_ LPSTARTUPINFOW lpStartupInfo, 629 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 630 | _In_ LPCSTR lpDllName, 631 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 632 | 633 | #ifdef UNICODE 634 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllW 635 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW 636 | #else 637 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllA 638 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA 639 | #endif // !UNICODE 640 | 641 | BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, 642 | _Inout_opt_ LPSTR lpCommandLine, 643 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 644 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 645 | _In_ BOOL bInheritHandles, 646 | _In_ DWORD dwCreationFlags, 647 | _In_opt_ LPVOID lpEnvironment, 648 | _In_opt_ LPCSTR lpCurrentDirectory, 649 | _In_ LPSTARTUPINFOA lpStartupInfo, 650 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 651 | _In_ LPCSTR lpDllName, 652 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 653 | 654 | BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, 655 | _Inout_opt_ LPWSTR lpCommandLine, 656 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 657 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 658 | _In_ BOOL bInheritHandles, 659 | _In_ DWORD dwCreationFlags, 660 | _In_opt_ LPVOID lpEnvironment, 661 | _In_opt_ LPCWSTR lpCurrentDirectory, 662 | _In_ LPSTARTUPINFOW lpStartupInfo, 663 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 664 | _In_ LPCSTR lpDllName, 665 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 666 | 667 | #ifdef UNICODE 668 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW 669 | #else 670 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA 671 | #endif // !UNICODE 672 | 673 | BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, 674 | _Inout_opt_ LPSTR lpCommandLine, 675 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 676 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 677 | _In_ BOOL bInheritHandles, 678 | _In_ DWORD dwCreationFlags, 679 | _In_opt_ LPVOID lpEnvironment, 680 | _In_opt_ LPCSTR lpCurrentDirectory, 681 | _In_ LPSTARTUPINFOA lpStartupInfo, 682 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 683 | _In_ DWORD nDlls, 684 | _In_reads_(nDlls) LPCSTR *rlpDlls, 685 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 686 | 687 | BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, 688 | _Inout_opt_ LPWSTR lpCommandLine, 689 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 690 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 691 | _In_ BOOL bInheritHandles, 692 | _In_ DWORD dwCreationFlags, 693 | _In_opt_ LPVOID lpEnvironment, 694 | _In_opt_ LPCWSTR lpCurrentDirectory, 695 | _In_ LPSTARTUPINFOW lpStartupInfo, 696 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 697 | _In_ DWORD nDlls, 698 | _In_reads_(nDlls) LPCSTR *rlpDlls, 699 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 700 | 701 | #ifdef UNICODE 702 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW 703 | #else 704 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA 705 | #endif // !UNICODE 706 | 707 | BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, 708 | _In_ LPCSTR lpDllName, 709 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 710 | 711 | BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, 712 | _In_ LPCSTR lpDllName, 713 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 714 | 715 | #ifdef UNICODE 716 | #define DetourProcessViaHelper DetourProcessViaHelperW 717 | #else 718 | #define DetourProcessViaHelper DetourProcessViaHelperA 719 | #endif // !UNICODE 720 | 721 | BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, 722 | _In_ DWORD nDlls, 723 | _In_reads_(nDlls) LPCSTR *rlpDlls, 724 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 725 | 726 | BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, 727 | _In_ DWORD nDlls, 728 | _In_reads_(nDlls) LPCSTR *rlpDlls, 729 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 730 | 731 | #ifdef UNICODE 732 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW 733 | #else 734 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA 735 | #endif // !UNICODE 736 | 737 | BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, 738 | _In_reads_(nDlls) LPCSTR *rlpDlls, 739 | _In_ DWORD nDlls); 740 | 741 | BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, 742 | _In_ HMODULE hImage, 743 | _In_ BOOL bIs32Bit, 744 | _In_reads_(nDlls) LPCSTR *rlpDlls, 745 | _In_ DWORD nDlls); 746 | 747 | BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, 748 | _In_ REFGUID rguid, 749 | _In_reads_bytes_(cbData) PVOID pvData, 750 | _In_ DWORD cbData); 751 | BOOL WINAPI DetourRestoreAfterWith(VOID); 752 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, 753 | _In_ DWORD cbData); 754 | BOOL WINAPI DetourIsHelperProcess(VOID); 755 | VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, 756 | _In_ HINSTANCE, 757 | _In_ LPSTR, 758 | _In_ INT); 759 | 760 | // 761 | ////////////////////////////////////////////////////////////////////////////// 762 | #ifdef __cplusplus 763 | } 764 | #endif // __cplusplus 765 | 766 | //////////////////////////////////////////////// Detours Internal Definitions. 767 | // 768 | #ifdef __cplusplus 769 | #ifdef DETOURS_INTERNAL 770 | 771 | #define NOTHROW 772 | // #define NOTHROW (nothrow) 773 | 774 | ////////////////////////////////////////////////////////////////////////////// 775 | // 776 | #if (_MSC_VER < 1299) 777 | #include 778 | typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; 779 | typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; 780 | typedef IMAGEHLP_SYMBOL SYMBOL_INFO; 781 | typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; 782 | 783 | static inline 784 | LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) 785 | { 786 | return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); 787 | } 788 | #else 789 | #pragma warning(push) 790 | #pragma warning(disable:4091) // empty typedef 791 | #include 792 | #pragma warning(pop) 793 | #endif 794 | 795 | #ifdef IMAGEAPI // defined by DBGHELP.H 796 | typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); 797 | 798 | typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, 799 | _In_opt_ LPCSTR UserSearchPath, 800 | _In_ BOOL fInvadeProcess); 801 | typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); 802 | typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); 803 | typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, 804 | _In_opt_ HANDLE hFile, 805 | _In_ LPSTR ImageName, 806 | _In_opt_ LPSTR ModuleName, 807 | _In_ DWORD64 BaseOfDll, 808 | _In_opt_ DWORD SizeOfDll); 809 | typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, 810 | _In_ DWORD64 qwAddr, 811 | _Out_ PIMAGEHLP_MODULE64 ModuleInfo); 812 | typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, 813 | _In_ LPSTR Name, 814 | _Out_ PSYMBOL_INFO Symbol); 815 | 816 | typedef struct _DETOUR_SYM_INFO 817 | { 818 | HANDLE hProcess; 819 | HMODULE hDbgHelp; 820 | PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; 821 | PF_SymInitialize pfSymInitialize; 822 | PF_SymSetOptions pfSymSetOptions; 823 | PF_SymGetOptions pfSymGetOptions; 824 | PF_SymLoadModule64 pfSymLoadModule64; 825 | PF_SymGetModuleInfo64 pfSymGetModuleInfo64; 826 | PF_SymFromName pfSymFromName; 827 | } DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; 828 | 829 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); 830 | 831 | #endif // IMAGEAPI 832 | 833 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 834 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 835 | #endif 836 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 837 | 838 | #ifndef DETOUR_TRACE 839 | #if DETOUR_DEBUG 840 | #define DETOUR_TRACE(x) printf x 841 | #define DETOUR_BREAK() __debugbreak() 842 | #include 843 | #include 844 | #else 845 | #define DETOUR_TRACE(x) 846 | #define DETOUR_BREAK() 847 | #endif 848 | #endif 849 | 850 | #if 1 || defined(DETOURS_IA64) 851 | 852 | // 853 | // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. 854 | // 855 | 856 | #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) 857 | 858 | #define DETOUR_IA64_TEMPLATE_OFFSET (0) 859 | #define DETOUR_IA64_TEMPLATE_SIZE (5) 860 | 861 | #define DETOUR_IA64_INSTRUCTION_SIZE (41) 862 | #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) 863 | #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 864 | #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 865 | 866 | C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); 867 | 868 | __declspec(align(16)) struct DETOUR_IA64_BUNDLE 869 | { 870 | public: 871 | union 872 | { 873 | BYTE data[16]; 874 | UINT64 wide[2]; 875 | }; 876 | 877 | enum { 878 | A_UNIT = 1u, 879 | I_UNIT = 2u, 880 | M_UNIT = 3u, 881 | B_UNIT = 4u, 882 | F_UNIT = 5u, 883 | L_UNIT = 6u, 884 | X_UNIT = 7u, 885 | }; 886 | struct DETOUR_IA64_METADATA 887 | { 888 | ULONG nTemplate : 8; // Instruction template. 889 | ULONG nUnit0 : 4; // Unit for slot 0 890 | ULONG nUnit1 : 4; // Unit for slot 1 891 | ULONG nUnit2 : 4; // Unit for slot 2 892 | }; 893 | 894 | protected: 895 | static const DETOUR_IA64_METADATA s_rceCopyTable[33]; 896 | 897 | UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 898 | 899 | bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, 900 | _In_ BYTE slot, 901 | _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 902 | 903 | // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 904 | // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. 905 | 906 | // 00 907 | // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. 908 | // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] 909 | // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] 910 | // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] 911 | // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] 912 | // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] 913 | // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] 914 | // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] 915 | BYTE GetTemplate() const; 916 | // Get 4 bit opcodes. 917 | BYTE GetInst0() const; 918 | BYTE GetInst1() const; 919 | BYTE GetInst2() const; 920 | BYTE GetUnit(BYTE slot) const; 921 | BYTE GetUnit0() const; 922 | BYTE GetUnit1() const; 923 | BYTE GetUnit2() const; 924 | // Get 37 bit data. 925 | UINT64 GetData0() const; 926 | UINT64 GetData1() const; 927 | UINT64 GetData2() const; 928 | 929 | // Get/set the full 41 bit instructions. 930 | UINT64 GetInstruction(BYTE slot) const; 931 | UINT64 GetInstruction0() const; 932 | UINT64 GetInstruction1() const; 933 | UINT64 GetInstruction2() const; 934 | void SetInstruction(BYTE slot, UINT64 instruction); 935 | void SetInstruction0(UINT64 instruction); 936 | void SetInstruction1(UINT64 instruction); 937 | void SetInstruction2(UINT64 instruction); 938 | 939 | // Get/set bitfields. 940 | static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); 941 | static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); 942 | 943 | // Get specific read-only fields. 944 | static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode 945 | static UINT64 GetX(UINT64 instruction); // 1bit opcode extension 946 | static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension 947 | static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension 948 | 949 | // Get/set specific fields. 950 | static UINT64 GetImm7a(UINT64 instruction); 951 | static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); 952 | static UINT64 GetImm13c(UINT64 instruction); 953 | static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); 954 | static UINT64 GetSignBit(UINT64 instruction); 955 | static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); 956 | static UINT64 GetImm20a(UINT64 instruction); 957 | static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); 958 | static UINT64 GetImm20b(UINT64 instruction); 959 | static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); 960 | 961 | static UINT64 SignExtend(UINT64 Value, UINT64 Offset); 962 | 963 | BOOL IsMovlGp() const; 964 | 965 | VOID SetInst(BYTE Slot, BYTE nInst); 966 | VOID SetInst0(BYTE nInst); 967 | VOID SetInst1(BYTE nInst); 968 | VOID SetInst2(BYTE nInst); 969 | VOID SetData(BYTE Slot, UINT64 nData); 970 | VOID SetData0(UINT64 nData); 971 | VOID SetData1(UINT64 nData); 972 | VOID SetData2(UINT64 nData); 973 | BOOL SetNop(BYTE Slot); 974 | BOOL SetNop0(); 975 | BOOL SetNop1(); 976 | BOOL SetNop2(); 977 | 978 | public: 979 | BOOL IsBrl() const; 980 | VOID SetBrl(); 981 | VOID SetBrl(UINT64 target); 982 | UINT64 GetBrlTarget() const; 983 | VOID SetBrlTarget(UINT64 target); 984 | VOID SetBrlImm(UINT64 imm); 985 | UINT64 GetBrlImm() const; 986 | 987 | UINT64 GetMovlGp() const; 988 | VOID SetMovlGp(UINT64 gp); 989 | 990 | VOID SetStop(); 991 | 992 | UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; 993 | }; 994 | #endif // DETOURS_IA64 995 | 996 | #ifdef DETOURS_ARM 997 | 998 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 999 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 1000 | 1001 | #endif // DETOURS_ARM 1002 | 1003 | ////////////////////////////////////////////////////////////////////////////// 1004 | 1005 | #ifdef __cplusplus 1006 | extern "C" { 1007 | #endif // __cplusplus 1008 | 1009 | #define DETOUR_OFFLINE_LIBRARY(x) \ 1010 | PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 1011 | _Inout_opt_ PVOID *ppDstPool, \ 1012 | _In_ PVOID pSrc, \ 1013 | _Out_opt_ PVOID *ppTarget, \ 1014 | _Out_opt_ LONG *plExtra); \ 1015 | \ 1016 | BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ 1017 | _In_ BOOL fLimitReferencesToModule); \ 1018 | 1019 | DETOUR_OFFLINE_LIBRARY(X86) 1020 | DETOUR_OFFLINE_LIBRARY(X64) 1021 | DETOUR_OFFLINE_LIBRARY(ARM) 1022 | DETOUR_OFFLINE_LIBRARY(ARM64) 1023 | DETOUR_OFFLINE_LIBRARY(IA64) 1024 | 1025 | #undef DETOUR_OFFLINE_LIBRARY 1026 | 1027 | ////////////////////////////////////////////////////////////////////////////// 1028 | // 1029 | // Helpers for manipulating page protection. 1030 | // 1031 | 1032 | _Success_(return != FALSE) 1033 | BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, 1034 | _In_ PVOID pAddress, 1035 | _In_ SIZE_T nSize, 1036 | _In_ DWORD dwNewProtect, 1037 | _Out_ PDWORD pdwOldProtect); 1038 | 1039 | _Success_(return != FALSE) 1040 | BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 1041 | _In_ SIZE_T nSize, 1042 | _In_ DWORD dwNewProtect, 1043 | _Out_ PDWORD pdwOldProtect); 1044 | #ifdef __cplusplus 1045 | } 1046 | #endif // __cplusplus 1047 | 1048 | ////////////////////////////////////////////////////////////////////////////// 1049 | 1050 | #define MM_ALLOCATION_GRANULARITY 0x10000 1051 | 1052 | ////////////////////////////////////////////////////////////////////////////// 1053 | 1054 | #endif // DETOURS_INTERNAL 1055 | #endif // __cplusplus 1056 | 1057 | #endif // _DETOURS_H_ 1058 | // 1059 | //////////////////////////////////////////////////////////////// End of File. 1060 | -------------------------------------------------------------------------------- /ext/include/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 18 | #define DETOURS_STRINGIFY_(x) #x 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /ext/lib/x64/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/ext/lib/x64/detours.lib -------------------------------------------------------------------------------- /ext/lib/x64/detours.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/ext/lib/x64/detours.pdb -------------------------------------------------------------------------------- /ext/lib/x86/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/ext/lib/x86/detours.lib -------------------------------------------------------------------------------- /ext/lib/x86/detours.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billziss-gh/bang/ec936e8a5df2026da750b714cf616cda2d4b94be/ext/lib/x86/detours.pdb -------------------------------------------------------------------------------- /src/dll/bang.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/bang.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | 15 | 16 | /* 17 | * force load 18 | */ 19 | 20 | __declspec(dllexport) 21 | VOID BangLoad(VOID) 22 | { 23 | } 24 | 25 | 26 | /* 27 | * debugging 28 | */ 29 | 30 | static DWORD BangDebugFlags = 0; 31 | 32 | static 33 | VOID BangDebugLogA(struct CreateProcessPacketA *CreateProcessPacket) 34 | { 35 | CHAR Buf[1024]; 36 | DWORD Bytes; 37 | wsprintfA(Buf, "bang: %s\n", CreateProcessPacket->lpApplicationName); 38 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), Buf, lstrlenA(Buf), &Bytes, 0); 39 | } 40 | 41 | static 42 | VOID BangDebugLogW(struct CreateProcessPacketW *CreateProcessPacket) 43 | { 44 | CHAR Buf[1024]; 45 | DWORD Bytes; 46 | wsprintfA(Buf, "bang: %S", CreateProcessPacket->lpApplicationName); 47 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), Buf, lstrlenA(Buf), &Bytes, 0); 48 | } 49 | 50 | __declspec(dllexport) 51 | VOID BangSetDebugFlags(DWORD DebugFlags) 52 | { 53 | BangDebugFlags = DebugFlags; 54 | } 55 | 56 | 57 | /* 58 | * argument handling 59 | */ 60 | 61 | static 62 | BOOL BangParseCommandLineA(PSTR CommandLine, int *PArgc, PSTR **PArgv) 63 | { 64 | PWSTR CommandLineW = 0, *ArgvW = 0; 65 | PSTR *Argv = 0, Text; 66 | int Length, Total, Copied; 67 | 68 | *PArgc = 0; 69 | *PArgv = 0; 70 | 71 | Length = lstrlenA(CommandLine); 72 | CommandLineW = HeapAlloc(GetProcessHeap(), 0, (Length + 1) * 4); 73 | if (0 == CommandLineW) 74 | goto exit; 75 | 76 | if (0 == MultiByteToWideChar(CP_UTF8, 0, CommandLine, Length + 1, CommandLineW, (Length + 1) * 4)) 77 | goto exit; 78 | 79 | ArgvW = CommandLineToArgvW(CommandLineW, PArgc); 80 | if (0 == ArgvW) 81 | goto exit; 82 | 83 | Total = 0; 84 | for (int I = 0; *PArgc > I; I++) 85 | { 86 | if (0 == (Length = WideCharToMultiByte(CP_UTF8, 0, ArgvW[I], -1, 0, 0, 0, 0))) 87 | goto exit; 88 | Total += Length; 89 | } 90 | 91 | Argv = LocalAlloc(LMEM_ZEROINIT, (*PArgc + 1) * sizeof(PVOID) + Total); 92 | if (0 == Argv) 93 | goto exit; 94 | Text = (PUINT8)Argv + (*PArgc + 1) * sizeof(PVOID); 95 | 96 | Copied = 0; 97 | for (int I = 0; *PArgc > I; I++) 98 | { 99 | Argv[I] = Text + Copied; 100 | if (0 == (Length = WideCharToMultiByte(CP_UTF8, 0, ArgvW[I], -1, Argv[I], Total - Copied, 0, 0))) 101 | goto exit; 102 | Copied += Length; 103 | } 104 | Argv[*PArgc] = 0; 105 | 106 | *PArgv = Argv; 107 | Argv = 0; 108 | 109 | exit: 110 | if (0 != Argv) 111 | LocalFree(Argv); 112 | 113 | if (0 != ArgvW) 114 | LocalFree(ArgvW); 115 | 116 | if (0 != CommandLineW) 117 | HeapFree(GetProcessHeap(), 0, CommandLineW); 118 | 119 | return 0 != *PArgv; 120 | } 121 | 122 | static 123 | BOOL BangParseCommandLineW(PWSTR CommandLine, int *PArgc, PWSTR **PArgv) 124 | { 125 | *PArgc = 0; 126 | *PArgv = CommandLineToArgvW(CommandLine, PArgc); 127 | return 0 != *PArgv; 128 | } 129 | 130 | static 131 | int BangMultiByteToXCharA( 132 | PSTR SourceString, int SourceLength, 133 | PSTR DestinationString, int DestinationLength) 134 | { 135 | if (SourceLength > DestinationLength) 136 | return 0; 137 | memcpy(DestinationString, SourceString, SourceLength); 138 | return SourceLength; 139 | } 140 | 141 | int BangMultiByteToXCharW( 142 | PSTR SourceString, int SourceLength, 143 | PWSTR DestinationString, int DestinationLength) 144 | { 145 | return MultiByteToWideChar(CP_UTF8, 0, 146 | SourceString, SourceLength, 147 | DestinationString, DestinationLength); 148 | } 149 | 150 | 151 | /* 152 | * bang execution 153 | */ 154 | 155 | #undef strnicmp 156 | #define strnicmp(s, t, n) _strnicmp(s, t, n) 157 | #undef stricmp 158 | #define stricmp(s, t) _stricmp(s, t) 159 | #undef wcsnicmp 160 | #define wcsnicmp(s, t, n) _wcsnicmp(s, t, n) 161 | #undef wcsicmp 162 | #define wcsicmp(s, t) _wcsicmp(s, t) 163 | 164 | #undef XTYP 165 | #define XTYP CHAR 166 | #undef XLIT 167 | #define XLIT(S) S 168 | #undef XSYM 169 | #define XSYM(N) N ## A 170 | #undef XSTR 171 | #define XSTR(N) str ## N 172 | #include "bang.i" 173 | 174 | #undef XTYP 175 | #define XTYP WCHAR 176 | #undef XLIT 177 | #define XLIT(S) L ## S 178 | #undef XSYM 179 | #define XSYM(N) N ## W 180 | #undef XSTR 181 | #define XSTR(N) wcs ## N 182 | #include "bang.i" 183 | -------------------------------------------------------------------------------- /src/dll/bang.i: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/bang.i 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | 14 | /* 15 | * registry 16 | */ 17 | 18 | static inline 19 | BOOL XSYM(BangRegGetValue)(XTYP *Name, XTYP *Buffer, PDWORD PLength) 20 | { 21 | return ERROR_SUCCESS == XSYM(RegGetValue)( 22 | HKEY_CURRENT_USER, 23 | XLIT("Software\\Bang"), 24 | Name, 25 | RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ, 26 | 0, 27 | Buffer, 28 | PLength); 29 | } 30 | 31 | 32 | /* 33 | * argument handling 34 | */ 35 | 36 | static 37 | int XSYM(BangAllArgumentsLength)(int Argc, XTYP **Argv, BOOL Quote) 38 | { 39 | int Length = 0, QuoteLength = Quote ? 2 : 0; 40 | for (int I = 1; Argc > I; I++) 41 | Length += (1 < I) + QuoteLength + XSYM(lstrlen)(Argv[I]); 42 | return Length; 43 | } 44 | 45 | static 46 | XTYP *XSYM(BangAllArgumentsCopy)(int Argc, XTYP **Argv, BOOL Quote, XTYP *Q) 47 | { 48 | int L = 0; 49 | for (int I = 1; Argc > I; I++) 50 | { 51 | if (1 < I) 52 | *Q++ = ' '; 53 | if (Quote) 54 | *Q++ = '\"'; 55 | L = XSYM(lstrlen)(Argv[I]); 56 | memcpy(Q, Argv[I], L * sizeof(XTYP)); 57 | Q += L; 58 | if (Quote) 59 | *Q++ = '\"'; 60 | } 61 | return Q; 62 | } 63 | 64 | static 65 | BOOL XSYM(BangReplaceArguments)(XTYP *String, int Argc, XTYP **Argv, XTYP **PNewString) 66 | { 67 | XTYP *NewString = 0, *P, *Q; 68 | int Length, L; 69 | 70 | *PNewString = 0; 71 | 72 | Length = 0; 73 | for (P = String; *P; P++) 74 | switch (*P) 75 | { 76 | case '$': 77 | if ('\0' == P[1]) 78 | goto default_length; 79 | P++; 80 | if ('0' <= *P && *P <= '9' && Argc > *P - '0') 81 | Length += XSYM(lstrlen)(Argv[*P - '0']); 82 | else if ('@' == *P) 83 | Length += XSYM(BangAllArgumentsLength)(Argc, Argv, FALSE); 84 | break; 85 | case '\"': 86 | if ('$' == P[1] && '@' == P[2] && '\"' == P[3]) 87 | { 88 | P += 3; 89 | Length += XSYM(BangAllArgumentsLength)(Argc, Argv, TRUE); 90 | break; 91 | } 92 | goto default_length; 93 | #if 0 94 | /* backslash is the path sep on Windows, so using it for escape is asking for trouble */ 95 | case '\\': 96 | if ('\0' == P[1]) 97 | goto default_length; 98 | P++; 99 | /* fallthrough */ 100 | #endif 101 | default: 102 | default_length: 103 | Length++; 104 | break; 105 | } 106 | 107 | NewString = HeapAlloc(GetProcessHeap(), 0, (Length + 1) * sizeof(XTYP)); 108 | if (0 == NewString) 109 | return FALSE; 110 | 111 | for (P = String, Q = NewString; *P; P++) 112 | switch (*P) 113 | { 114 | case '$': 115 | if ('\0' == P[1]) 116 | goto default_copy; 117 | P++; 118 | if ('0' <= *P && *P <= '9' && Argc > *P - '0') 119 | { 120 | L = XSYM(lstrlen)(Argv[*P - '0']); 121 | memcpy(Q, Argv[*P - '0'], L * sizeof(XTYP)); 122 | Q += L; 123 | } 124 | else if ('@' == *P) 125 | Q = XSYM(BangAllArgumentsCopy)(Argc, Argv, FALSE, Q); 126 | break; 127 | case '\"': 128 | if ('$' == P[1] && '@' == P[2] && '\"' == P[3]) 129 | { 130 | P += 3; 131 | Q = XSYM(BangAllArgumentsCopy)(Argc, Argv, TRUE, Q); 132 | break; 133 | } 134 | goto default_length; 135 | #if 0 136 | /* backslash is the path sep on Windows, so using it for escape is asking for trouble */ 137 | case '\\': 138 | if ('\0' == P[1]) 139 | goto default_copy; 140 | P++; 141 | /* fallthrough */ 142 | #endif 143 | default: 144 | default_copy: 145 | *Q++ = *P; 146 | break; 147 | } 148 | *Q = '\0'; 149 | 150 | *PNewString = NewString; 151 | 152 | return TRUE; 153 | } 154 | 155 | 156 | /* 157 | * bang execution 158 | */ 159 | 160 | static 161 | BOOL XSYM(BangRemapInterpreter)(struct XSYM(CreateProcessPacket) *CreateProcessPacket, 162 | CHAR **PRestOfLine) 163 | { 164 | static XTYP DefaultPathmap[] = XLIT( 165 | "/usr/bin/env*;" 166 | "/usr/bin/*%SYSTEMROOT%\\System32\\;" 167 | "/bin/*%SYSTEMROOT%\\System32\\" 168 | ); 169 | XTYP Pathmap[4096], *P, *Q; 170 | XTYP *PosixPath, *WindowsPath, ApplicationName[MAX_PATH]; 171 | DWORD PosixLength, WindowsLength, Length; 172 | 173 | Length = sizeof Pathmap; 174 | if (!XSYM(BangRegGetValue)(XLIT("Pathmap"), Pathmap, &Length)) 175 | { 176 | if (0 == XSYM(ExpandEnvironmentStrings)( 177 | DefaultPathmap, Pathmap, sizeof Pathmap / sizeof Pathmap[0])) 178 | return FALSE; 179 | } 180 | 181 | for (P = Pathmap; P && *P; P = Q) 182 | { 183 | Q = XSTR(chr)(P, '*'); 184 | if (Q) 185 | { 186 | PosixPath = P; 187 | PosixLength = (DWORD)(Q - P); 188 | *Q++ = '\0'; 189 | } 190 | else 191 | break; 192 | 193 | P = Q; 194 | Q = XSTR(chr)(P, ';'); 195 | if (Q) 196 | { 197 | WindowsPath = P; 198 | WindowsLength = (DWORD)(Q - P); 199 | *Q++ = '\0'; 200 | } 201 | else 202 | { 203 | WindowsPath = P; 204 | WindowsLength = XSYM(lstrlen)(P); 205 | } 206 | 207 | if (0 < PosixLength && '/' == PosixPath[PosixLength - 1] && 208 | 0 == XSTR(ncmp)(CreateProcessPacket->ApplicationName, PosixPath, PosixLength)) 209 | { 210 | if ('\0' == *WindowsPath) 211 | { 212 | XSYM(lstrcpy)(ApplicationName, CreateProcessPacket->ApplicationName + PosixLength); 213 | 214 | Length = XSYM(SearchPath)( 215 | 0, ApplicationName, XLIT(".exe"), MAX_PATH, CreateProcessPacket->ApplicationName, 0); 216 | return 0 < Length && Length < MAX_PATH; /* term-0 not included in Length */ 217 | } 218 | else 219 | { 220 | Length = XSYM(lstrlen)(CreateProcessPacket->ApplicationName + PosixLength); 221 | if (WindowsLength + Length + sizeof ".exe" > MAX_PATH) 222 | return FALSE; 223 | 224 | memcpy( 225 | ApplicationName, 226 | WindowsPath, 227 | WindowsLength * sizeof(XTYP)); 228 | memcpy( 229 | ApplicationName + WindowsLength, 230 | CreateProcessPacket->ApplicationName + PosixLength, 231 | Length * sizeof(XTYP)); 232 | memcpy( 233 | ApplicationName + WindowsLength + Length, 234 | XLIT(".exe"), 235 | sizeof ".exe" * sizeof(XTYP)); 236 | 237 | Length = XSYM(GetFullPathName)( 238 | ApplicationName, MAX_PATH, CreateProcessPacket->ApplicationName, 0); 239 | return 0 < Length && Length <= MAX_PATH; /* term-0 included in Length */ 240 | } 241 | } 242 | else 243 | if (0 == XSTR(cmp)(CreateProcessPacket->ApplicationName, PosixPath)) 244 | { 245 | if ('\0' == *WindowsPath) 246 | { 247 | CHAR *Interpreter, *P; 248 | 249 | for (P = *PRestOfLine; *P && (' ' == *P || '\t' == *P); P++) 250 | ; 251 | Interpreter = P; 252 | for (; *P && ' ' != *P && '\t' != *P; P++) 253 | ; 254 | *PRestOfLine = P; 255 | 256 | if (0 == (Length = XSYM(BangMultiByteToXChar)( 257 | Interpreter, 258 | (int)(*PRestOfLine - Interpreter), 259 | ApplicationName, 260 | MAX_PATH - 1))) 261 | return FALSE; 262 | ApplicationName[Length] = '\0'; 263 | 264 | Length = XSYM(SearchPath)( 265 | 0, ApplicationName, XLIT(".exe"), MAX_PATH, CreateProcessPacket->ApplicationName, 0); 266 | return 0 < Length && Length < MAX_PATH; /* term-0 not included in Length */ 267 | } 268 | else 269 | { 270 | if (WindowsLength >= MAX_PATH) 271 | return FALSE; 272 | 273 | memcpy( 274 | ApplicationName, 275 | WindowsPath, 276 | (WindowsLength + 1) * sizeof(XTYP)); 277 | 278 | Length = XSYM(GetFullPathName)( 279 | ApplicationName, MAX_PATH, CreateProcessPacket->ApplicationName, 0); 280 | return 0 < Length && Length <= MAX_PATH; /* term-0 included in Length */ 281 | } 282 | } 283 | } 284 | 285 | return FALSE; 286 | } 287 | 288 | static 289 | BOOL XSYM(BangExecuteInterpreter)(struct XSYM(CreateProcessPacket) *CreateProcessPacket, 290 | CHAR *Line) 291 | { 292 | CHAR *Interpreter, *RestOfLine, *P; 293 | XTYP **Argv = 0, *NewRestOfLine = 0, *ExitCommand, *X; 294 | int CommandLineLength, Length, Argc; 295 | BOOL Result = FALSE; 296 | 297 | CreateProcessPacket->CommandLine = HeapAlloc(GetProcessHeap(), 0, MAX_COMMANDLINE); 298 | if (0 == CreateProcessPacket->CommandLine) 299 | goto exit; 300 | 301 | Interpreter = Line + 2; 302 | for (P = Interpreter; *P && ' ' != *P && '\t' != *P; P++) 303 | ; 304 | RestOfLine = P; 305 | 306 | if (0 == (Length = XSYM(BangMultiByteToXChar)( 307 | Interpreter, 308 | (int)(RestOfLine - Interpreter), 309 | CreateProcessPacket->ApplicationName, 310 | MAX_PATH - 1))) 311 | goto exit; 312 | CreateProcessPacket->ApplicationName[Length] = '\0'; 313 | 314 | if (!XSYM(BangRemapInterpreter)(CreateProcessPacket, &RestOfLine)) 315 | goto exit; 316 | 317 | CommandLineLength = 0; 318 | Length = XSYM(lstrlen)(CreateProcessPacket->ApplicationName); 319 | if (2/* quotes */ + Length > MAX_COMMANDLINE - 1 - CommandLineLength) 320 | goto exit; 321 | CreateProcessPacket->CommandLine[CommandLineLength++] = '\"'; 322 | memcpy(CreateProcessPacket->CommandLine + CommandLineLength, 323 | CreateProcessPacket->ApplicationName, Length * sizeof(XTYP)); 324 | CommandLineLength += Length; 325 | CreateProcessPacket->CommandLine[CommandLineLength++] = '\"'; 326 | CreateProcessPacket->CommandLine[CommandLineLength] = '\0'; 327 | 328 | if ('#' == Line[0]) 329 | { 330 | if (*RestOfLine) 331 | { 332 | if (0 == (Length = XSYM(BangMultiByteToXChar)( 333 | RestOfLine, 334 | lstrlenA(RestOfLine), 335 | CreateProcessPacket->CommandLine + CommandLineLength, 336 | MAX_COMMANDLINE - 1 - CommandLineLength))) 337 | goto exit; 338 | CommandLineLength += Length; 339 | CreateProcessPacket->CommandLine[CommandLineLength] = '\0'; 340 | } 341 | 342 | if (0 != CreateProcessPacket->lpCommandLine) 343 | { 344 | Length = XSYM(lstrlen)(CreateProcessPacket->lpCommandLine); 345 | if (1/* separator space */ + Length > MAX_COMMANDLINE - 1 - CommandLineLength) 346 | goto exit; 347 | CreateProcessPacket->CommandLine[CommandLineLength++] = ' '; 348 | memcpy(CreateProcessPacket->CommandLine + CommandLineLength, 349 | CreateProcessPacket->lpCommandLine, Length * sizeof(XTYP)); 350 | CommandLineLength += Length; 351 | CreateProcessPacket->CommandLine[CommandLineLength] = '\0'; 352 | } 353 | } 354 | else 355 | if ('/' == Line[0]) 356 | { 357 | if (*RestOfLine) 358 | { 359 | if (0 == (Length = XSYM(BangMultiByteToXChar)( 360 | RestOfLine, 361 | lstrlenA(RestOfLine), 362 | CreateProcessPacket->CommandLine + CommandLineLength, 363 | MAX_COMMANDLINE - 1 - CommandLineLength))) 364 | goto exit; 365 | CreateProcessPacket->CommandLine[CommandLineLength + Length] = '\0'; 366 | 367 | /* strip "; exit at the end */ 368 | for (X = CreateProcessPacket->CommandLine + CommandLineLength + Length - 1; 369 | CreateProcessPacket->CommandLine + CommandLineLength <= X && ';' != *X && '\"' != *X; 370 | X--) 371 | ; 372 | if (CreateProcessPacket->CommandLine + CommandLineLength <= X && ';' == *X) 373 | { 374 | ExitCommand = X; 375 | for (X++; *X && (' ' == *X || '\t' == *X); X++) 376 | ; 377 | if (0 == XSTR(ncmp)(X, XLIT("exit"), 4)) 378 | { 379 | for (X += 4; *X && (' ' == *X || '\t' == *X); X++) 380 | ; 381 | if ('\0' == *X) 382 | *ExitCommand = '\0'; 383 | } 384 | } 385 | 386 | if (!XSYM(BangParseCommandLine)(CreateProcessPacket->lpCommandLine, &Argc, &Argv)) 387 | goto exit; 388 | if (!XSYM(BangReplaceArguments)(CreateProcessPacket->CommandLine + CommandLineLength, 389 | Argc, Argv, &NewRestOfLine)) 390 | goto exit; 391 | 392 | Length = XSYM(lstrlen)(NewRestOfLine); 393 | if (Length > MAX_COMMANDLINE - 1 - CommandLineLength) 394 | goto exit; 395 | memcpy(CreateProcessPacket->CommandLine + CommandLineLength, 396 | NewRestOfLine, Length * sizeof(XTYP)); 397 | CommandLineLength += Length; 398 | CreateProcessPacket->CommandLine[CommandLineLength] = '\0'; 399 | } 400 | } 401 | 402 | CreateProcessPacket->lpApplicationName = CreateProcessPacket->ApplicationName; 403 | CreateProcessPacket->lpCommandLine = CreateProcessPacket->CommandLine; 404 | 405 | Result = TRUE; 406 | 407 | exit: 408 | if (0 != NewRestOfLine) 409 | HeapFree(GetProcessHeap(), 0, NewRestOfLine); 410 | 411 | if (0 != Argv) 412 | LocalFree(Argv); 413 | 414 | return Result; 415 | } 416 | 417 | static 418 | VOID XSYM(BangExecute)(struct XSYM(CreateProcessPacket) *CreateProcessPacket, 419 | const XTYP *FilePath, PBOOL PIsExecutable) 420 | { 421 | HANDLE Handle = INVALID_HANDLE_VALUE; 422 | CHAR Buffer[4096]; 423 | DWORD Bytes; 424 | 425 | if (0 != PIsExecutable) 426 | *PIsExecutable = FALSE; 427 | 428 | Handle = XSYM(CreateFile)( 429 | FilePath, 430 | FILE_READ_DATA | FILE_EXECUTE, 431 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 432 | 0, 433 | OPEN_EXISTING, 434 | 0, 435 | 0); 436 | if (INVALID_HANDLE_VALUE == Handle) 437 | goto exit; 438 | 439 | if (!ReadFile(Handle, Buffer, sizeof Buffer - 1, &Bytes, 0)) 440 | goto exit; 441 | 442 | if (3 <= Bytes && 443 | ('#' == Buffer[0] && '!' == Buffer[1] && '/' == Buffer[2]) || 444 | ('/' == Buffer[0] && '/' == Buffer[1] && '/' == Buffer[2])) 445 | { 446 | for (CHAR *P = Buffer + 3, *EndP = Buffer + Bytes; EndP > P; P++) 447 | if ('\r' == *P || '\n' == *P) 448 | { 449 | *P = '\0'; 450 | break; 451 | } 452 | Buffer[Bytes] = '\0'; 453 | 454 | if (0 != PIsExecutable) 455 | *PIsExecutable = TRUE; 456 | else 457 | XSYM(BangExecuteInterpreter)(CreateProcessPacket, Buffer); 458 | } 459 | 460 | exit: 461 | if (INVALID_HANDLE_VALUE != Handle) 462 | CloseHandle(Handle); 463 | } 464 | 465 | static 466 | BOOL XSYM(BangShouldExecute)(const XTYP *FilePath) 467 | { 468 | /* FilePath should be full path */ 469 | 470 | XTYP Directories[4096], DirName[MAX_PATH], *P, *Q; 471 | DWORD Length; 472 | 473 | Length = sizeof Directories; 474 | if (!XSYM(BangRegGetValue)(XLIT("Directories"), Directories, &Length)) 475 | return TRUE; 476 | 477 | XSYM(lstrcpy)(DirName, FilePath); 478 | P = XSTR(rchr)(DirName, '\\'); 479 | if (0 != P) 480 | *++P = '\0'; 481 | else 482 | return FALSE; 483 | 484 | for (P = Directories; P && *P; P = Q) 485 | { 486 | Q = XSTR(chr)(P, ';'); 487 | if (Q) 488 | *Q++ = '\0'; 489 | if (0 == XSTR(nicmp)(DirName, P, XSYM(lstrlen)(P))) 490 | return TRUE; 491 | } 492 | 493 | return FALSE; 494 | } 495 | 496 | static 497 | BOOL XSYM(BangShouldDetour)(const XTYP *FilePath) 498 | { 499 | /* FilePath should be full path */ 500 | 501 | XTYP Programs[4096], *BaseName, *P, *Q; 502 | DWORD Length; 503 | 504 | Length = sizeof Programs; 505 | if (!XSYM(BangRegGetValue)(XLIT("Programs"), Programs, &Length)) 506 | return TRUE; 507 | 508 | BaseName = XSTR(rchr)(FilePath, '\\'); 509 | if (0 != BaseName) 510 | BaseName++; 511 | else 512 | return FALSE; 513 | 514 | for (P = Programs; P && *P; P = Q) 515 | { 516 | Q = XSTR(chr)(P, ';'); 517 | if (Q) 518 | *Q++ = '\0'; 519 | if (0 != XSTR(chr)(P, '\\')) 520 | { 521 | /* match full path; we do not care about alternate names from symlinks, etc. */ 522 | if (0 == XSTR(icmp)(FilePath, P)) 523 | return TRUE; 524 | } 525 | else 526 | { 527 | /* match base name */ 528 | if (0 == XSTR(icmp)(BaseName, P)) 529 | return TRUE; 530 | } 531 | } 532 | 533 | return FALSE; 534 | } 535 | 536 | VOID XSYM(BangBeforeCreateProcess)(struct XSYM(CreateProcessPacket) *CreateProcessPacket) 537 | { 538 | if (BangDebugFlags) 539 | { 540 | XSYM(BangDebugLog)(CreateProcessPacket); 541 | return; 542 | } 543 | 544 | if (0 == CreateProcessPacket->lpApplicationName && 545 | 0 == CreateProcessPacket->lpCommandLine) 546 | return; 547 | 548 | XTYP FilePathBuf[MAX_PATH], FileNameBuf[MAX_PATH]; 549 | XTYP *StartP, *P; 550 | DWORD Length; 551 | 552 | FilePathBuf[0] = '\0'; 553 | FileNameBuf[0] = '\0'; 554 | 555 | if (0 != CreateProcessPacket->lpApplicationName) 556 | { 557 | Length = XSYM(GetFullPathName)( 558 | CreateProcessPacket->lpApplicationName, MAX_PATH, FilePathBuf, 0); 559 | if (0 == Length || MAX_PATH < Length) 560 | FilePathBuf[0] = '\0'; 561 | } 562 | else 563 | if (0 != CreateProcessPacket->lpCommandLine) 564 | { 565 | if ('\"' == CreateProcessPacket->lpCommandLine[0]) 566 | { 567 | StartP = CreateProcessPacket->lpCommandLine + 1; 568 | for (P = StartP; *P && '\"' != *P; P++) 569 | ; 570 | } 571 | else 572 | { 573 | StartP = CreateProcessPacket->lpCommandLine; 574 | for (P = StartP; *P && ' ' != *P && '\t' != *P; P++) 575 | ; 576 | } 577 | 578 | if (P - StartP < MAX_PATH) 579 | { 580 | memcpy(FileNameBuf, StartP, (P - StartP) * sizeof(XTYP)); 581 | FileNameBuf[P - StartP] = '\0'; 582 | 583 | Length = XSYM(SearchPath)(0, FileNameBuf, 0, MAX_PATH, FilePathBuf, 0); 584 | if (0 == Length || MAX_PATH <= Length) 585 | FilePathBuf[0] = '\0'; 586 | } 587 | } 588 | 589 | if (FilePathBuf[0]) 590 | { 591 | if (XSYM(BangShouldExecute)(FilePathBuf)) 592 | XSYM(BangExecute)(CreateProcessPacket, FilePathBuf, 0); 593 | /* do not detour if we are executing an interpreter script to avoid recursive execution */ 594 | CreateProcessPacket->Detour = 595 | CreateProcessPacket->lpApplicationName != CreateProcessPacket->ApplicationName && 596 | XSYM(BangShouldDetour)(FilePathBuf); 597 | } 598 | } 599 | 600 | VOID XSYM(BangBeforeShellExecute)(XSYM(SHELLEXECUTEINFO) *ShellExecuteInfo) 601 | { 602 | static XTYP ClassName[] = XLIT(".exe"); 603 | XTYP FilePathBuf[MAX_PATH]; 604 | DWORD Length; 605 | BOOL IsExecutable; 606 | 607 | if (sizeof *ShellExecuteInfo == ShellExecuteInfo->cbSize && 608 | (0 == (ShellExecuteInfo->fMask & ~( 609 | SEE_MASK_NOCLOSEPROCESS | 610 | SEE_MASK_NOASYNC | 611 | SEE_MASK_DOENVSUBST | 612 | SEE_MASK_FLAG_NO_UI | 613 | SEE_MASK_UNICODE | 614 | SEE_MASK_NO_CONSOLE | 615 | SEE_MASK_ASYNCOK))) && 616 | (0 == ShellExecuteInfo->lpVerb || 617 | 0 == XSTR(cmp)(XLIT("open"), ShellExecuteInfo->lpVerb) || 618 | 0 == XSTR(cmp)(XLIT("runas"), ShellExecuteInfo->lpVerb) || 619 | 0 == XSTR(cmp)(XLIT("runasuser"), ShellExecuteInfo->lpVerb)) && 620 | 0 != ShellExecuteInfo->lpFile) 621 | { 622 | Length = XSYM(GetFullPathName)( 623 | ShellExecuteInfo->lpFile, MAX_PATH, FilePathBuf, 0); 624 | if (0 == Length || MAX_PATH < Length) 625 | ; 626 | else if (XSYM(BangShouldExecute)(FilePathBuf)) 627 | { 628 | XSYM(BangExecute)(0, FilePathBuf, &IsExecutable); 629 | if (IsExecutable) 630 | { 631 | ShellExecuteInfo->fMask |= SEE_MASK_CLASSNAME | SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE; 632 | ShellExecuteInfo->lpClass = ClassName; 633 | } 634 | } 635 | } 636 | } 637 | -------------------------------------------------------------------------------- /src/dll/hookcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/hookcp.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | 15 | #define HOOK_IMPL(N, T, A, ...) \ 16 | static \ 17 | BOOL (WINAPI *Real_ ## N) A = N; \ 18 | static \ 19 | BOOL WINAPI Hook_ ## N A \ 20 | { \ 21 | struct CreateProcessPacket ## T CreateProcessPacket;\ 22 | DWORD LastError; \ 23 | BOOL Result; \ 24 | *lpProcessInformation = (PROCESS_INFORMATION){ 0 };\ 25 | CreateProcessPacket.Detour = TRUE;\ 26 | CreateProcessPacket.CommandLine = 0;\ 27 | __VA_ARGS__; \ 28 | TlsSetValue(CreateProcessPacketTlsIndex, &CreateProcessPacket);\ 29 | BeforeCreateProcess ## T(&CreateProcessPacket);\ 30 | if (CreateProcessPacket.Detour) \ 31 | Result = DetourCreateProcessWithDllEx ## T(\ 32 | ARG(lpApplicationName), \ 33 | ARG(lpCommandLine), \ 34 | ARG(lpProcessAttributes),\ 35 | ARG(lpThreadAttributes),\ 36 | ARG(bInheritHandles), \ 37 | ARG(dwCreationFlags), \ 38 | ARG(lpEnvironment), \ 39 | ARG(lpCurrentDirectory),\ 40 | ARG(lpStartupInfo), \ 41 | &ARG(ProcessInformation),\ 42 | ModuleFileNameA, \ 43 | Wrap_ ## N); \ 44 | else \ 45 | Result = Wrap_ ## N( \ 46 | ARG(lpApplicationName), \ 47 | ARG(lpCommandLine), \ 48 | ARG(lpProcessAttributes),\ 49 | ARG(lpThreadAttributes),\ 50 | ARG(bInheritHandles), \ 51 | ARG(dwCreationFlags), \ 52 | ARG(lpEnvironment), \ 53 | ARG(lpCurrentDirectory),\ 54 | ARG(lpStartupInfo), \ 55 | &ARG(ProcessInformation));\ 56 | LastError = GetLastError(); \ 57 | TlsSetValue(CreateProcessPacketTlsIndex, 0);\ 58 | if (0 != CreateProcessPacket.CommandLine)\ 59 | HeapFree(GetProcessHeap(), 0, CreateProcessPacket.CommandLine);\ 60 | SetLastError(LastError); \ 61 | if (Result) \ 62 | *lpProcessInformation = ARG(ProcessInformation);\ 63 | return Result; \ 64 | } 65 | #define HOOK_ATTACH(F, N) \ 66 | (((F) ? DetourAttach : DetourDetach)((PVOID *)&Real_ ## N, Hook_ ## N)) 67 | 68 | #define ARG(N) \ 69 | CreateProcessPacket.N 70 | #define SETARG(N) \ 71 | CreateProcessPacket.N = N 72 | 73 | #define Wrap_CreateProcessA Real_CreateProcessA 74 | #define Wrap_CreateProcessW Real_CreateProcessW 75 | static 76 | BOOL WINAPI Wrap_CreateProcessAsUserA( 77 | LPCSTR lpApplicationName, 78 | LPSTR lpCommandLine, 79 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 80 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 81 | BOOL bInheritHandles, 82 | DWORD dwCreationFlags, 83 | LPVOID lpEnvironment, 84 | LPCSTR lpCurrentDirectory, 85 | LPSTARTUPINFOA lpStartupInfo, 86 | LPPROCESS_INFORMATION lpProcessInformation); 87 | static 88 | BOOL WINAPI Wrap_CreateProcessAsUserW( 89 | LPCWSTR lpApplicationName, 90 | LPWSTR lpCommandLine, 91 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 92 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 93 | BOOL bInheritHandles, 94 | DWORD dwCreationFlags, 95 | LPVOID lpEnvironment, 96 | LPCWSTR lpCurrentDirectory, 97 | LPSTARTUPINFOW lpStartupInfo, 98 | LPPROCESS_INFORMATION lpProcessInformation); 99 | static 100 | BOOL WINAPI Wrap_CreateProcessWithLogonW( 101 | LPCWSTR lpApplicationName, 102 | LPWSTR lpCommandLine, 103 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 104 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 105 | BOOL bInheritHandles, 106 | DWORD dwCreationFlags, 107 | LPVOID lpEnvironment, 108 | LPCWSTR lpCurrentDirectory, 109 | LPSTARTUPINFOW lpStartupInfo, 110 | LPPROCESS_INFORMATION lpProcessInformation); 111 | static 112 | BOOL WINAPI Wrap_CreateProcessWithTokenW( 113 | LPCWSTR lpApplicationName, 114 | LPWSTR lpCommandLine, 115 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 116 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 117 | BOOL bInheritHandles, 118 | DWORD dwCreationFlags, 119 | LPVOID lpEnvironment, 120 | LPCWSTR lpCurrentDirectory, 121 | LPSTARTUPINFOW lpStartupInfo, 122 | LPPROCESS_INFORMATION lpProcessInformation); 123 | 124 | static DWORD CreateProcessPacketTlsIndex = TLS_OUT_OF_INDEXES; 125 | static VOID (*BeforeCreateProcessA)(struct CreateProcessPacketA *); 126 | static VOID (*BeforeCreateProcessW)(struct CreateProcessPacketW *); 127 | 128 | HOOK_IMPL(CreateProcessA, A, ( 129 | LPCSTR lpApplicationName, 130 | LPSTR lpCommandLine, 131 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 132 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 133 | BOOL bInheritHandles, 134 | DWORD dwCreationFlags, 135 | LPVOID lpEnvironment, 136 | LPCSTR lpCurrentDirectory, 137 | LPSTARTUPINFOA lpStartupInfo, 138 | LPPROCESS_INFORMATION lpProcessInformation), 139 | { 140 | SETARG(lpApplicationName); 141 | SETARG(lpCommandLine); 142 | SETARG(lpProcessAttributes); 143 | SETARG(lpThreadAttributes); 144 | SETARG(bInheritHandles); 145 | SETARG(dwCreationFlags); 146 | SETARG(lpEnvironment); 147 | SETARG(lpCurrentDirectory); 148 | SETARG(lpStartupInfo); 149 | SETARG(lpProcessInformation); 150 | }) 151 | 152 | HOOK_IMPL(CreateProcessW, W, ( 153 | LPCWSTR lpApplicationName, 154 | LPWSTR lpCommandLine, 155 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 156 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 157 | BOOL bInheritHandles, 158 | DWORD dwCreationFlags, 159 | LPVOID lpEnvironment, 160 | LPCWSTR lpCurrentDirectory, 161 | LPSTARTUPINFOW lpStartupInfo, 162 | LPPROCESS_INFORMATION lpProcessInformation), 163 | { 164 | SETARG(lpApplicationName); 165 | SETARG(lpCommandLine); 166 | SETARG(lpProcessAttributes); 167 | SETARG(lpThreadAttributes); 168 | SETARG(bInheritHandles); 169 | SETARG(dwCreationFlags); 170 | SETARG(lpEnvironment); 171 | SETARG(lpCurrentDirectory); 172 | SETARG(lpStartupInfo); 173 | SETARG(lpProcessInformation); 174 | }) 175 | 176 | HOOK_IMPL(CreateProcessAsUserA, A, ( 177 | HANDLE hToken, 178 | LPCSTR lpApplicationName, 179 | LPSTR lpCommandLine, 180 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 181 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 182 | BOOL bInheritHandles, 183 | DWORD dwCreationFlags, 184 | LPVOID lpEnvironment, 185 | LPCSTR lpCurrentDirectory, 186 | LPSTARTUPINFOA lpStartupInfo, 187 | LPPROCESS_INFORMATION lpProcessInformation), 188 | { 189 | SETARG(hToken); 190 | SETARG(lpApplicationName); 191 | SETARG(lpCommandLine); 192 | SETARG(lpProcessAttributes); 193 | SETARG(lpThreadAttributes); 194 | SETARG(bInheritHandles); 195 | SETARG(dwCreationFlags); 196 | SETARG(lpEnvironment); 197 | SETARG(lpCurrentDirectory); 198 | SETARG(lpStartupInfo); 199 | SETARG(lpProcessInformation); 200 | }) 201 | 202 | HOOK_IMPL(CreateProcessAsUserW, W, ( 203 | HANDLE hToken, 204 | LPCWSTR lpApplicationName, 205 | LPWSTR lpCommandLine, 206 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 207 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 208 | BOOL bInheritHandles, 209 | DWORD dwCreationFlags, 210 | LPVOID lpEnvironment, 211 | LPCWSTR lpCurrentDirectory, 212 | LPSTARTUPINFOW lpStartupInfo, 213 | LPPROCESS_INFORMATION lpProcessInformation), 214 | { 215 | SETARG(hToken); 216 | SETARG(lpApplicationName); 217 | SETARG(lpCommandLine); 218 | SETARG(lpProcessAttributes); 219 | SETARG(lpThreadAttributes); 220 | SETARG(bInheritHandles); 221 | SETARG(dwCreationFlags); 222 | SETARG(lpEnvironment); 223 | SETARG(lpCurrentDirectory); 224 | SETARG(lpStartupInfo); 225 | SETARG(lpProcessInformation); 226 | }) 227 | 228 | HOOK_IMPL(CreateProcessWithLogonW, W, ( 229 | LPCWSTR lpUsername, 230 | LPCWSTR lpDomain, 231 | LPCWSTR lpPassword, 232 | DWORD dwLogonFlags, 233 | LPCWSTR lpApplicationName, 234 | LPWSTR lpCommandLine, 235 | DWORD dwCreationFlags, 236 | LPVOID lpEnvironment, 237 | LPCWSTR lpCurrentDirectory, 238 | LPSTARTUPINFOW lpStartupInfo, 239 | LPPROCESS_INFORMATION lpProcessInformation), 240 | { 241 | SETARG(lpUsername); 242 | SETARG(lpDomain); 243 | SETARG(lpPassword); 244 | SETARG(dwLogonFlags); 245 | SETARG(lpApplicationName); 246 | SETARG(lpCommandLine); 247 | SETARG(dwCreationFlags); 248 | SETARG(lpEnvironment); 249 | SETARG(lpCurrentDirectory); 250 | SETARG(lpStartupInfo); 251 | SETARG(lpProcessInformation); 252 | }) 253 | 254 | HOOK_IMPL(CreateProcessWithTokenW, W, ( 255 | HANDLE hToken, 256 | DWORD dwLogonFlags, 257 | LPCWSTR lpApplicationName, 258 | LPWSTR lpCommandLine, 259 | DWORD dwCreationFlags, 260 | LPVOID lpEnvironment, 261 | LPCWSTR lpCurrentDirectory, 262 | LPSTARTUPINFOW lpStartupInfo, 263 | LPPROCESS_INFORMATION lpProcessInformation), 264 | { 265 | SETARG(hToken); 266 | SETARG(dwLogonFlags); 267 | SETARG(lpApplicationName); 268 | SETARG(lpCommandLine); 269 | SETARG(dwCreationFlags); 270 | SETARG(lpEnvironment); 271 | SETARG(lpCurrentDirectory); 272 | SETARG(lpStartupInfo); 273 | SETARG(lpProcessInformation); 274 | }) 275 | 276 | static 277 | BOOL WINAPI Wrap_CreateProcessAsUserA( 278 | LPCSTR lpApplicationName, 279 | LPSTR lpCommandLine, 280 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 281 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 282 | BOOL bInheritHandles, 283 | DWORD dwCreationFlags, 284 | LPVOID lpEnvironment, 285 | LPCSTR lpCurrentDirectory, 286 | LPSTARTUPINFOA lpStartupInfo, 287 | LPPROCESS_INFORMATION lpProcessInformation) 288 | { 289 | struct CreateProcessPacketA *CreateProcessPacket = (PVOID)lpProcessInformation; 290 | if (TlsGetValue(CreateProcessPacketTlsIndex) == CreateProcessPacket) 291 | return Real_CreateProcessAsUserA( 292 | CreateProcessPacket->hToken, 293 | lpApplicationName, 294 | lpCommandLine, 295 | lpProcessAttributes, 296 | lpThreadAttributes, 297 | bInheritHandles, 298 | dwCreationFlags, 299 | lpEnvironment, 300 | lpCurrentDirectory, 301 | lpStartupInfo, 302 | lpProcessInformation); 303 | else 304 | return Real_CreateProcessA( 305 | lpApplicationName, 306 | lpCommandLine, 307 | lpProcessAttributes, 308 | lpThreadAttributes, 309 | bInheritHandles, 310 | dwCreationFlags, 311 | lpEnvironment, 312 | lpCurrentDirectory, 313 | lpStartupInfo, 314 | lpProcessInformation); 315 | } 316 | 317 | static 318 | BOOL WINAPI Wrap_CreateProcessAsUserW( 319 | LPCWSTR lpApplicationName, 320 | LPWSTR lpCommandLine, 321 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 322 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 323 | BOOL bInheritHandles, 324 | DWORD dwCreationFlags, 325 | LPVOID lpEnvironment, 326 | LPCWSTR lpCurrentDirectory, 327 | LPSTARTUPINFOW lpStartupInfo, 328 | LPPROCESS_INFORMATION lpProcessInformation) 329 | { 330 | struct CreateProcessPacketW *CreateProcessPacket = (PVOID)lpProcessInformation; 331 | if (TlsGetValue(CreateProcessPacketTlsIndex) == CreateProcessPacket) 332 | return Real_CreateProcessAsUserW( 333 | CreateProcessPacket->hToken, 334 | lpApplicationName, 335 | lpCommandLine, 336 | lpProcessAttributes, 337 | lpThreadAttributes, 338 | bInheritHandles, 339 | dwCreationFlags, 340 | lpEnvironment, 341 | lpCurrentDirectory, 342 | lpStartupInfo, 343 | lpProcessInformation); 344 | else 345 | return Real_CreateProcessW( 346 | lpApplicationName, 347 | lpCommandLine, 348 | lpProcessAttributes, 349 | lpThreadAttributes, 350 | bInheritHandles, 351 | dwCreationFlags, 352 | lpEnvironment, 353 | lpCurrentDirectory, 354 | lpStartupInfo, 355 | lpProcessInformation); 356 | } 357 | 358 | static 359 | BOOL WINAPI Wrap_CreateProcessWithLogonW( 360 | LPCWSTR lpApplicationName, 361 | LPWSTR lpCommandLine, 362 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 363 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 364 | BOOL bInheritHandles, 365 | DWORD dwCreationFlags, 366 | LPVOID lpEnvironment, 367 | LPCWSTR lpCurrentDirectory, 368 | LPSTARTUPINFOW lpStartupInfo, 369 | LPPROCESS_INFORMATION lpProcessInformation) 370 | { 371 | struct CreateProcessPacketW *CreateProcessPacket = (PVOID)lpProcessInformation; 372 | if (TlsGetValue(CreateProcessPacketTlsIndex) == CreateProcessPacket) 373 | return Real_CreateProcessWithLogonW( 374 | CreateProcessPacket->lpUsername, 375 | CreateProcessPacket->lpDomain, 376 | CreateProcessPacket->lpPassword, 377 | CreateProcessPacket->dwLogonFlags, 378 | lpApplicationName, 379 | lpCommandLine, 380 | dwCreationFlags, 381 | lpEnvironment, 382 | lpCurrentDirectory, 383 | lpStartupInfo, 384 | lpProcessInformation); 385 | else 386 | return Real_CreateProcessW( 387 | lpApplicationName, 388 | lpCommandLine, 389 | lpProcessAttributes, 390 | lpThreadAttributes, 391 | bInheritHandles, 392 | dwCreationFlags, 393 | lpEnvironment, 394 | lpCurrentDirectory, 395 | lpStartupInfo, 396 | lpProcessInformation); 397 | } 398 | 399 | static 400 | BOOL WINAPI Wrap_CreateProcessWithTokenW( 401 | LPCWSTR lpApplicationName, 402 | LPWSTR lpCommandLine, 403 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 404 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 405 | BOOL bInheritHandles, 406 | DWORD dwCreationFlags, 407 | LPVOID lpEnvironment, 408 | LPCWSTR lpCurrentDirectory, 409 | LPSTARTUPINFOW lpStartupInfo, 410 | LPPROCESS_INFORMATION lpProcessInformation) 411 | { 412 | struct CreateProcessPacketW *CreateProcessPacket = (PVOID)lpProcessInformation; 413 | if (TlsGetValue(CreateProcessPacketTlsIndex) == CreateProcessPacket) 414 | return Real_CreateProcessWithTokenW( 415 | CreateProcessPacket->hToken, 416 | CreateProcessPacket->dwLogonFlags, 417 | lpApplicationName, 418 | lpCommandLine, 419 | dwCreationFlags, 420 | lpEnvironment, 421 | lpCurrentDirectory, 422 | lpStartupInfo, 423 | lpProcessInformation); 424 | else 425 | return Real_CreateProcessW( 426 | lpApplicationName, 427 | lpCommandLine, 428 | lpProcessAttributes, 429 | lpThreadAttributes, 430 | bInheritHandles, 431 | dwCreationFlags, 432 | lpEnvironment, 433 | lpCurrentDirectory, 434 | lpStartupInfo, 435 | lpProcessInformation); 436 | } 437 | 438 | VOID HookCreateProcess(BOOL Flag, 439 | VOID (*BeforeA)(struct CreateProcessPacketA *), 440 | VOID (*BeforeW)(struct CreateProcessPacketW *)) 441 | { 442 | if (Flag) 443 | CreateProcessPacketTlsIndex = TlsAlloc(); 444 | if (Flag) 445 | { 446 | BeforeCreateProcessA = BeforeA; 447 | BeforeCreateProcessW = BeforeW; 448 | } 449 | 450 | if (TLS_OUT_OF_INDEXES != CreateProcessPacketTlsIndex) 451 | { 452 | HOOK_ATTACH(Flag, CreateProcessA); 453 | HOOK_ATTACH(Flag, CreateProcessW); 454 | HOOK_ATTACH(Flag, CreateProcessAsUserA); 455 | HOOK_ATTACH(Flag, CreateProcessAsUserW); 456 | HOOK_ATTACH(Flag, CreateProcessWithLogonW); 457 | HOOK_ATTACH(Flag, CreateProcessWithTokenW); 458 | } 459 | 460 | if (!Flag) 461 | { 462 | BeforeCreateProcessA = 0; 463 | BeforeCreateProcessW = 0; 464 | } 465 | if (!Flag && TLS_OUT_OF_INDEXES != CreateProcessPacketTlsIndex) 466 | TlsFree(CreateProcessPacketTlsIndex); 467 | } 468 | -------------------------------------------------------------------------------- /src/dll/hooksh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/hooksh.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | 15 | #define HOOK_IMPL(N, T, A) \ 16 | static \ 17 | HINSTANCE (WINAPI *Real_ ## N) A = 0;\ 18 | static \ 19 | HINSTANCE WINAPI Hook_ ## N A \ 20 | { \ 21 | SHELLEXECUTEINFO ## T ShellExecuteInfo =\ 22 | { \ 23 | .cbSize = sizeof ShellExecuteInfo,\ 24 | .fMask = SEE_MASK_FLAG_NO_UI,\ 25 | .hwnd = hwnd, \ 26 | .lpVerb = lpOperation, \ 27 | .lpFile = lpFile, \ 28 | .lpParameters = lpParameters,\ 29 | .lpDirectory = lpDirectory, \ 30 | .nShow = nShowCmd, \ 31 | }; \ 32 | BeforeShellExecute ## T(&ShellExecuteInfo);\ 33 | Real_ShellExecuteEx ## T(&ShellExecuteInfo);\ 34 | return ShellExecuteInfo.hInstApp;\ 35 | } 36 | #define HOOK_IMPL_EX(N, T, A) \ 37 | static \ 38 | BOOL (WINAPI *Real_ ## N) A = 0;\ 39 | static \ 40 | BOOL WINAPI Hook_ ## N A \ 41 | { \ 42 | SHELLEXECUTEINFO ## T ShellExecuteInfo = *pExecInfo;\ 43 | BOOL Result; \ 44 | BeforeShellExecute ## T(&ShellExecuteInfo);\ 45 | Result = Real_ShellExecuteEx ## T(&ShellExecuteInfo);\ 46 | pExecInfo->hInstApp = ShellExecuteInfo.hInstApp;\ 47 | pExecInfo->hProcess = ShellExecuteInfo.hProcess;\ 48 | return Result; \ 49 | } 50 | #define HOOK_ATTACH(F, N) \ 51 | (((F) ? DetourAttach : DetourDetach)((PVOID *)&Real_ ## N, Hook_ ## N)) 52 | #define HOOK_GETPROC(M, N) \ 53 | (Real_ ## N = (PVOID)GetProcAddress(M, #N)) 54 | 55 | VOID (*BeforeShellExecuteA)(SHELLEXECUTEINFOA *ShellExecuteInfo); 56 | VOID (*BeforeShellExecuteW)(SHELLEXECUTEINFOW *ShellExecuteInfo); 57 | 58 | HOOK_IMPL_EX(ShellExecuteExA, A, ( 59 | SHELLEXECUTEINFOA *pExecInfo)) 60 | 61 | HOOK_IMPL_EX(ShellExecuteExW, W, ( 62 | SHELLEXECUTEINFOW *pExecInfo)) 63 | 64 | HOOK_IMPL(ShellExecuteA, A, ( 65 | HWND hwnd, 66 | LPCSTR lpOperation, 67 | LPCSTR lpFile, 68 | LPCSTR lpParameters, 69 | LPCSTR lpDirectory, 70 | INT nShowCmd)) 71 | 72 | HOOK_IMPL(ShellExecuteW, W, ( 73 | HWND hwnd, 74 | LPCWSTR lpOperation, 75 | LPCWSTR lpFile, 76 | LPCWSTR lpParameters, 77 | LPCWSTR lpDirectory, 78 | INT nShowCmd)) 79 | 80 | VOID HookShellExecute(BOOL Flag, 81 | VOID (*BeforeA)(SHELLEXECUTEINFOA *), 82 | VOID (*BeforeW)(SHELLEXECUTEINFOW *)) 83 | { 84 | static HANDLE Module; 85 | 86 | if (Flag) 87 | { 88 | Module = GetModuleHandleA("shell32.dll"); 89 | if (0 != Module) 90 | { 91 | HOOK_GETPROC(Module, ShellExecuteExA); 92 | HOOK_GETPROC(Module, ShellExecuteExW); 93 | HOOK_GETPROC(Module, ShellExecuteA); 94 | HOOK_GETPROC(Module, ShellExecuteW); 95 | } 96 | } 97 | if (Flag) 98 | { 99 | BeforeShellExecuteA = BeforeA; 100 | BeforeShellExecuteW = BeforeW; 101 | } 102 | 103 | if (0 != Module) 104 | { 105 | HOOK_ATTACH(Flag, ShellExecuteExA); 106 | HOOK_ATTACH(Flag, ShellExecuteExW); 107 | HOOK_ATTACH(Flag, ShellExecuteA); 108 | HOOK_ATTACH(Flag, ShellExecuteW); 109 | } 110 | 111 | if (!Flag) 112 | { 113 | BeforeShellExecuteA = 0; 114 | BeforeShellExecuteW = 0; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/dll/library.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/library.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | 15 | CHAR ModuleFileNameA[MAX_PATH]; 16 | 17 | BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved) 18 | { 19 | if (DetourIsHelperProcess()) 20 | return TRUE; 21 | 22 | switch (Reason) 23 | { 24 | case DLL_PROCESS_ATTACH: 25 | GetModuleFileNameA(Instance, ModuleFileNameA, MAX_PATH); 26 | 27 | DetourRestoreAfterWith(); 28 | DetourTransactionBegin(); 29 | DetourUpdateThread(GetCurrentThread()); 30 | HookCreateProcess(TRUE, BangBeforeCreateProcessA, BangBeforeCreateProcessW); 31 | HookShellExecute(TRUE, BangBeforeShellExecuteA, BangBeforeShellExecuteW); 32 | DetourTransactionCommit(); 33 | break; 34 | 35 | case DLL_PROCESS_DETACH: 36 | DetourTransactionBegin(); 37 | DetourUpdateThread(GetCurrentThread()); 38 | HookShellExecute(FALSE, 0, 0); 39 | HookCreateProcess(FALSE, 0, 0); 40 | DetourTransactionCommit(); 41 | break; 42 | } 43 | 44 | return TRUE; 45 | } 46 | -------------------------------------------------------------------------------- /src/dll/library.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DetourFinishHelperProcess @1 NONAME 3 | -------------------------------------------------------------------------------- /src/dll/library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dll/library.h 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #ifndef BANG_DLL_LIBRARY_H_INCLUDED 14 | #define BANG_DLL_LIBRARY_H_INCLUDED 15 | 16 | #include 17 | #include 18 | 19 | extern CHAR ModuleFileNameA[]; 20 | 21 | #define MAX_COMMANDLINE 32767 22 | 23 | struct CreateProcessPacketA 24 | { 25 | /* output; ProcessInformation must be first */ 26 | PROCESS_INFORMATION ProcessInformation; 27 | /* input */ 28 | HANDLE hToken; 29 | LPCSTR lpApplicationName; 30 | LPSTR lpCommandLine; 31 | LPSECURITY_ATTRIBUTES lpProcessAttributes; 32 | LPSECURITY_ATTRIBUTES lpThreadAttributes; 33 | BOOL bInheritHandles; 34 | DWORD dwCreationFlags; 35 | LPVOID lpEnvironment; 36 | LPCSTR lpCurrentDirectory; 37 | LPSTARTUPINFOA lpStartupInfo; 38 | LPPROCESS_INFORMATION lpProcessInformation; 39 | /* extra */ 40 | BOOL Detour; 41 | CHAR ApplicationName[MAX_PATH]; 42 | CHAR *CommandLine; 43 | }; 44 | 45 | struct CreateProcessPacketW 46 | { 47 | /* output; ProcessInformation must be first */ 48 | PROCESS_INFORMATION ProcessInformation; 49 | /* input */ 50 | HANDLE hToken; 51 | LPCWSTR lpApplicationName; 52 | LPWSTR lpCommandLine; 53 | LPSECURITY_ATTRIBUTES lpProcessAttributes; 54 | LPSECURITY_ATTRIBUTES lpThreadAttributes; 55 | BOOL bInheritHandles; 56 | DWORD dwCreationFlags; 57 | LPVOID lpEnvironment; 58 | LPCWSTR lpCurrentDirectory; 59 | LPSTARTUPINFOW lpStartupInfo; 60 | LPPROCESS_INFORMATION lpProcessInformation; 61 | LPCWSTR lpUsername; 62 | LPCWSTR lpDomain; 63 | LPCWSTR lpPassword; 64 | DWORD dwLogonFlags; 65 | /* extra */ 66 | BOOL Detour; 67 | WCHAR ApplicationName[MAX_PATH]; 68 | WCHAR *CommandLine; 69 | }; 70 | 71 | VOID HookCreateProcess(BOOL Flag, 72 | VOID (*BeforeA)(struct CreateProcessPacketA *), 73 | VOID (*BeforeW)(struct CreateProcessPacketW *)); 74 | VOID HookShellExecute(BOOL Flag, 75 | VOID (*BeforeA)(SHELLEXECUTEINFOA *), 76 | VOID (*BeforeW)(SHELLEXECUTEINFOW *)); 77 | 78 | VOID BangBeforeCreateProcessA(struct CreateProcessPacketA *CreateProcessPacket); 79 | VOID BangBeforeCreateProcessW(struct CreateProcessPacketW *CreateProcessPacket); 80 | VOID BangBeforeShellExecuteA(SHELLEXECUTEINFOA *ShellExecuteInfo); 81 | VOID BangBeforeShellExecuteW(SHELLEXECUTEINFOW *ShellExecuteInfo); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/exe/program.c: -------------------------------------------------------------------------------- 1 | /* 2 | * exe/program.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | __declspec(dllimport) 21 | VOID BangLoad(VOID); 22 | 23 | static void warn(const char *format, ...) 24 | { 25 | va_list ap; 26 | va_start(ap, format); 27 | vfprintf(stderr, format, ap); 28 | va_end(ap); 29 | } 30 | 31 | static void usage() 32 | { 33 | fprintf(stderr, "" 34 | "usage:\n" 35 | " bang [-p -1|PID]\n" 36 | " bang COMMAND [ARG ...]\n"); 37 | 38 | exit(2); 39 | } 40 | 41 | static int attach(int argc, char **argv) 42 | { 43 | CHAR ModuleFileName[MAX_PATH + sizeof "bang64.dll" - 1], *ModuleFileNameSuffix; 44 | DWORD ProcessId; 45 | HANDLE Process = 0; 46 | DWORD RemoteModule32Count = 0; 47 | PVOID RemoteBuffer = 0; 48 | HANDLE RemoteThread = 0; 49 | DWORD RemoteExitCode; 50 | SIZE_T Bytes; 51 | int ExitCode; 52 | 53 | if (2 > argc) 54 | usage(); 55 | 56 | ProcessId = strtoul(argv[1], 0, 10); 57 | 58 | if (-1 == ProcessId) 59 | { 60 | PROCESS_BASIC_INFORMATION BasicInfo = { 0 }; 61 | ULONG Length; 62 | NTSTATUS Status = NtQueryInformationProcess( 63 | GetCurrentProcess(), 64 | ProcessBasicInformation, 65 | &BasicInfo, 66 | sizeof BasicInfo, 67 | &Length); 68 | if (!NT_SUCCESS(Status)) 69 | { 70 | warn("cannot find parent process id"); 71 | ExitCode = 1; 72 | goto exit; 73 | } 74 | ProcessId = (DWORD)(ULONG_PTR)BasicInfo.Reserved3; 75 | } 76 | 77 | Process = OpenProcess( 78 | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 79 | FALSE, 80 | ProcessId); 81 | if (0 == Process) 82 | { 83 | warn("cannot open process id %lu", ProcessId); 84 | ExitCode = 1; 85 | goto exit; 86 | } 87 | 88 | GetModuleFileNameA(0, ModuleFileName, MAX_PATH); 89 | ModuleFileNameSuffix = strrchr(ModuleFileName, '\\'); 90 | ModuleFileNameSuffix = ModuleFileNameSuffix ? ModuleFileNameSuffix + 1 : ModuleFileName; 91 | 92 | EnumProcessModulesEx(Process, 0, 0, &RemoteModule32Count, LIST_MODULES_32BIT); 93 | if (0 == RemoteModule32Count) 94 | strcpy(ModuleFileNameSuffix, "bang64.dll"); 95 | else 96 | strcpy(ModuleFileNameSuffix, "bang32.dll"); 97 | 98 | RemoteBuffer = VirtualAllocEx(Process, 0, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 99 | if (0 == RemoteBuffer) 100 | { 101 | warn("cannot allocate memory in process id %lu", ProcessId); 102 | ExitCode = 1; 103 | goto exit; 104 | } 105 | 106 | if (!WriteProcessMemory(Process, RemoteBuffer, ModuleFileName, strlen(ModuleFileName) + 1, &Bytes)) 107 | { 108 | warn("cannot write memory in process id %lu", ProcessId); 109 | ExitCode = 1; 110 | goto exit; 111 | } 112 | 113 | RemoteThread = CreateRemoteThread(Process, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, RemoteBuffer, 0, 0); 114 | if (0 == RemoteThread) 115 | { 116 | warn("cannot create thread in process id %lu", ProcessId); 117 | ExitCode = 1; 118 | goto exit; 119 | } 120 | 121 | WaitForSingleObject(RemoteThread, INFINITE); 122 | GetExitCodeThread(RemoteThread, &RemoteExitCode); 123 | if (0 == RemoteExitCode) 124 | { 125 | warn("cannot load %s in process id %lu", ModuleFileNameSuffix, ProcessId); 126 | ExitCode = 1; 127 | goto exit; 128 | } 129 | 130 | ExitCode = 0; 131 | 132 | exit: 133 | if (0 != RemoteThread) 134 | CloseHandle(RemoteThread); 135 | 136 | if (0 != RemoteBuffer) 137 | VirtualFreeEx(Process, RemoteBuffer, 0, MEM_RELEASE); 138 | 139 | if (0 != Process) 140 | CloseHandle(Process); 141 | 142 | return ExitCode; 143 | } 144 | 145 | static int spawn(int argc, char **argv) 146 | { 147 | HANDLE Process = INVALID_HANDLE_VALUE; 148 | int ExitCode; 149 | 150 | BangLoad(); 151 | 152 | Process = (HANDLE)_spawnvp(_P_NOWAIT, argv[0], argv); 153 | if (INVALID_HANDLE_VALUE == Process) 154 | { 155 | warn("cannot spawn process %s", argv[0]); 156 | ExitCode = 1; 157 | goto exit; 158 | } 159 | 160 | ExitCode = 0; 161 | 162 | exit: 163 | if (INVALID_HANDLE_VALUE != Process) 164 | CloseHandle(Process); 165 | 166 | return ExitCode; 167 | } 168 | 169 | int main(int argc, char **argv) 170 | { 171 | if (2 > argc) 172 | usage(); 173 | 174 | if (0 == strcmp("-p", argv[1])) 175 | return attach(argc - 1, argv + 1); 176 | else 177 | return spawn(argc - 1, argv + 1); 178 | } 179 | -------------------------------------------------------------------------------- /tools/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | setlocal EnableDelayedExpansion 5 | 6 | set Configuration=Release 7 | if not X%1==X set Configuration=%1 8 | 9 | cd %~dp0..\build\VStudio 10 | 11 | if exist build\ for /R build\ %%d in (%Configuration%) do ( 12 | if exist "%%d" rmdir /s/q "%%d" 13 | ) 14 | 15 | set tag="" 16 | for /f "usebackq tokens=*" %%i in (`git describe`) do ( 17 | set Version=%%i 18 | REM remove leading "v" from tag 19 | set Version=!Version:v=! 20 | ) 21 | 22 | echo Version=%Version% Configuration=%Configuration% 23 | echo: 24 | 25 | call "%~dp0vcvarsall.bat" x64 26 | devenv bang.sln /build "%Configuration%|x64" 27 | if errorlevel 1 goto fail 28 | devenv bang.sln /build "%Configuration%|x86" 29 | if errorlevel 1 goto fail 30 | 31 | set ZipArchive=bang-%Version%.zip 32 | set ZipFiles=bang64.exe,bang64.dll,bang32.exe,bang32.dll 33 | 34 | pushd build\%Configuration% 35 | powershell -NoProfile -ExecutionPolicy Bypass -Command "Compress-Archive -DestinationPath %ZipArchive% -Path %ZipFiles%" 36 | if errorlevel 1 goto fail 37 | popd 38 | 39 | exit /b 0 40 | 41 | :fail 42 | exit /b 1 43 | -------------------------------------------------------------------------------- /tools/nmake-detours.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | 5 | call "%~dp0vcvarsall.bat" %1 6 | 7 | cd %~dp0..\ext\detours\src 8 | nmake 9 | if errorlevel 1 goto fail 10 | 11 | cd ..\.. 12 | xcopy /siy detours\include include 13 | xcopy /siy detours\lib.%1 lib\%1 14 | 15 | exit /b 0 16 | 17 | :fail 18 | exit /b 1 19 | -------------------------------------------------------------------------------- /tools/vcvarsall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set vcvarsall="" 4 | 5 | set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" 6 | if exist %vswhere% ( 7 | for /f "usebackq tokens=*" %%i in (`%vswhere% -latest -find VC\**\vcvarsall.bat`) do ( 8 | set vcvarsall="%%i" 9 | ) 10 | ) 11 | 12 | if not exist %vcvarsall% ( 13 | if exist %vswhere% ( 14 | for /f "usebackq tokens=*" %%i in (`%vswhere% -latest -property installationPath`) do ( 15 | set vcvarsall="%%i\VC\Auxiliary\Build\vcvarsall.bat" 16 | ) 17 | ) 18 | ) 19 | 20 | if not exist %vcvarsall% ( 21 | set vcvarsall="%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" 22 | ) 23 | 24 | call %vcvarsall% %* 25 | -------------------------------------------------------------------------------- /tst/hook-test/hook-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hook-test.c 3 | * 4 | * Copyright 2023 Bill Zissimopoulos 5 | */ 6 | /* 7 | * This file is part of Bang. 8 | * 9 | * It is licensed under the MIT license. The full license text can be found 10 | * in the License.txt file at the root of this project. 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | __declspec(dllimport) 17 | VOID BangSetDebugFlags(DWORD DebugFlags); 18 | 19 | int main(int argc, char **argv) 20 | { 21 | CHAR ModuleFileName[MAX_PATH], *ModuleFileNameSuffix; 22 | CHAR CommandLine[1024]; 23 | STARTUPINFOA StartupInfo; 24 | PROCESS_INFORMATION ProcessInformation; 25 | BOOL Success; 26 | unsigned long Count = 0; 27 | 28 | if (2 <= argc) 29 | Count = strtoul(argv[1], 0, 10); 30 | 31 | printf("%lu\n", Count); 32 | if (0 == Count--) 33 | return 0; 34 | 35 | BangSetDebugFlags(1); 36 | 37 | GetModuleFileNameA(0, ModuleFileName, MAX_PATH); 38 | ModuleFileNameSuffix = ModuleFileName + strlen(ModuleFileName) - (sizeof "64.exe" - 1); 39 | if (0 == strcmp(ModuleFileNameSuffix, "64.exe")) 40 | ModuleFileNameSuffix[0] = '3', ModuleFileNameSuffix[1] = '2'; 41 | else 42 | if (0 == strcmp(ModuleFileNameSuffix, "32.exe")) 43 | ModuleFileNameSuffix[0] = '6', ModuleFileNameSuffix[1] = '4'; 44 | snprintf(CommandLine, sizeof CommandLine, "\"%s\" %lu", ModuleFileName, Count); 45 | 46 | memset(&StartupInfo, 0, sizeof StartupInfo); 47 | Success = CreateProcessA( 48 | ModuleFileName, 49 | CommandLine, 50 | 0, 51 | 0, 52 | FALSE, 53 | 0, 54 | 0, 55 | 0, 56 | &StartupInfo, 57 | &ProcessInformation); 58 | 59 | return Success ? 0 : GetLastError(); 60 | } 61 | --------------------------------------------------------------------------------