Note
This is a fork from CoreHook by @unknownv2, adding .NET 5+ compatibility and widly refactoring the sources (I hope the original author won't be upset about it 😉).
This project name will probably change in a near future, since .NET isn't named Core anymore.
Here's the original description:
A library that simplifies intercepting application function calls using managed code and the .NET Core runtime.
Inspired and based on the great EasyHook.
Any contributions are all welcome! If you find any problems or want to add features, don't hesitate to open a new issue or create a pull request.
Credits go to the same people @unknownv2 mentioned here and also to himself. While I deeply modified (not to say "improved") his code, I wouldn't have been able to do that without his project!
Since this project is a fork and all initial credits goes to @unknownv2, please consider donating to the causes he supports.
I kept them here unmodified:
If the project has helped you in any way and you want to give back, consider donating to great organizations such as Black Girls Code and Hack the Hood, or volunteering at others like The Hidden Genius Project.
- Intercept public API functions such as
CreateFile
- Intercept internal functions by address or name if symbol files are available
- Supports NuGet package references for the plugin libraries
- Supports multiple architectures for the plugins
- Now supports .NET 5+.
- Major refactoring to simplify the code (too many interfaces and split classes for me!)
- CoreHook.Loader is now embedded into the main CoreHook project (I guess there was a good reason for not doing it, but I have yet to check that...)
- Updated the C++ .NET host to support .NET 5+ and moved it into the same solution (now named CoreHook.NativeHost)
- Simplified the examples while keeping the same functionality
Note: the CoreHook.IPC project should be moved outside the CoreHook repository and probably renamed as it is not solely usable in this context but for any inter-process communication needs.
CoreHook supports application function call interception on various architectures running Windows. Linux and macOS support is also planned.
Architecture | Operating System |
---|---|
x86 | Windows |
x64 | Windows |
ARM | Windows 10 IoT Core |
If you are building the CoreHook project (for example, with dotnet build
) and not publishing it, you must setup the project configuration as described below.
The project provides two options for configuring the runtime:
- A local configuration file named
CoreHook.runtimeconfig.json
(which is located next toCoreHook.dll
assembly in the CoreHook output directory) to initialize CoreCLR. - A global configuration file named
dotnet.runtimeconfig.json
.
The host module will first attempt to use the local configuration file, then it will check for the global configuration file and use that if it exists, and finally it will use the directory of the CoreHook.dll
assembly for resolving dependencies.
The runtimeconfig
file must contain the framework information for hosting .NET Core in the target application.
When you build any .NET 5+ application, these files are generated to the output directory. For more information on the configuration options, see here.
You can use the CoreHook.FileMonitor.runtimeconfig.json
and CoreHook.FileMonitor.runtimeconfig.dev.json
files found in your build output directory as references for creating the global or local configuration files.
Warning
The following has to be reviewed and hasn't been updated for this fork!
The runtime configuration file should look like the one below, where additionalProbingPaths
contains file paths the host module can check for additional dependencies. This guide assumes you have installed the .NET Core 2.2
runtime or SDK for both x86 and x64 architectures.
Notice: Either replace <user>
with your local computer user name or modify the paths to point to where your NuGet packages are installed. Take a look at CoreHook.FileMonitor.runtimeconfig.dev.json
in the output directory to find your paths.
{
"runtimeOptions": {
"tfm": "netcoreapp2.2",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.2.0"
},
"additionalProbingPaths": [
"C:\\Users\\<user>\\.dotnet\\store\\|arch|\\|tfm|",
"C:\\Users\\<user>\\.nuget\\packages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
]
}
}
To use a local configuration, create a file with the contents described above called CoreHook.runtimeconfig.json
and save it to the project output directory where CoreHook.dll
is located.
To use a global configuration, first create a dotnet.runtimeconfig.json
file with the contents described above and save it to a folder. This will be the global configuration file the project uses to initialize the runtime in the target processs. In this example, our file is saved at C:\CoreHook\dotnet.runtimeconfig.json
.
Set the environment variables for the x86
and x64
applications to the directory of the runtime configuration file. This allows you to have different configuration files for 32-bit
and 64-bit
applications.
For example (if you saved the file another installation directory or drive, make sure to use that path instead):
-
Set
CORE_ROOT_32
toC:\CoreHook
for32-bit
applications. -
Set
CORE_ROOT_64
toC:\CoreHook
for64-bit
applications.
setx CORE_ROOT_64 "C:\CoreHook"
setx CORE_ROOT_32 "C:\CoreHook"
Or set them for the current command prompt session with:
set CORE_ROOT_64=C:\CoreHook
set CORE_ROOT_32=C:\CoreHook
Then, you can either open the CoreHook
solution in Visual Studio
or run dotnet build
to build the library and the examples.
Dependencies are already embedded in this project as they shouldn't be updated that regularly. They are saved in the Native folder of the CoreHook project.
You can get the Application User Model Id (AUMID) required for launching UWP apps for the FileMonitor example with this script:
$installedapps = get-AppxPackage
$aumidList = @()
foreach ($app in $installedapps)
{
foreach ($id in (Get-AppxPackageManifest $app).package.applications.application.id)
{
$aumidList += $app.packagefamilyname + "!" + $id
}
}
$aumidList
You can print the list using the $aumidList
variable.
Notes: There is currently no way to set the proper access control on our pipes on the .NET Core platform and the issue is being tracked here so we use P/Invoke to call kernel32.dll!CreateNamedPipe
directly.
For Windows 10 IoT Core
, you can publish the application by running the publish.ps1
PowerShell script.
.\publish -example win32 -runtime win-arm
Make sure to also copy the coreload32.dll
and the corehook32.dll
to the directory of the program. For example, the application directory structure should look like this:
[+]Publish\win32\win-arm\
[+]Hook\
...
[-] CoreHook.FileMonitor.Hook.deps.json
[-] CoreHook.FileMonitor.Hook.dll
...
...
[-] CoreHook.FileMonitor.dll
[-] CoreHook.FileMonitor.exe
[-] corehook32.dll
[-] coreload32.dll
...
You can then copy the folder to your device and start the CoreHook.FileMonitor.exe
program.
The PowerShell script publish.ps1
allows you to publish the examples as self-contained executables. The default configuration is Release
and the output will be in the Publish
directory, created in the same location as the publishing script.
.\publish -example [uwp|win32] -runtime [Runtime IDentifier] -configuration [Debug|Release]
You can find a list of Runtime IDentifiers here.
For example, the command
.\publish -example win32 -runtime win10-arm
will create a folder called Publish/win32/win10-arm/
containing the CoreHook.FileMonitor
example.
CoreHook supports symbol name lookup from PDBs to get function addresses with the use of LocalHook.GetProcAddress
. For symbol lookup to work, you must either place the PDB file in the directory of the target program you are hooking or set the environment variable _NT_SYMBOL_PATH
to a symbol server. You can read more about Windows symbol support from the Microsoft documentation here.
Important: To use the complete symbol lookup, you need to have both dbghelp.dll
(provides the symbol lookup APIs) and symsrv.dll
(provides the symbol server lookup) and in your DLL search path. You can add these files to the directory of your target program or add them to your path. You can get both DLLs by installing the Debugging Tools for Windows.
Example locations where you can find dbghelp.dll
and symsrv.dll
are:
- %PROGRAMFILES(X86)%\Windows Kits\10\Debuggers\x86 (For 32-bit applications)
- %PROGRAMFILES(X86)%\Windows Kits\10\Debuggers\x64 (For 64-bit applications)
An example of what you can set the environment variable _NT_SYMBOL_PATH
to is:
srv*C:\SymbolCache*https://msdl.microsoft.com/downloads/symbols
The C:\SymbolCache
folder is a local cache directory where symbol files can be stored or downloaded to. When Windows needs to retrieve a PDB for a DLL, it can download them from https://msdl.microsoft.com/downloads/symbols
and store them in a folder for use by a debugger.
You can confirm that symbol support is properly configured by running the symbols tests.