├── .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 |
--------------------------------------------------------------------------------