https://github.com/windowsnt/hotpatch
Hotpatching in Windows with 5 methods.
https://github.com/windowsnt/hotpatch
hotfix hotpatch win32 win64
Last synced: 3 months ago
JSON representation
Hotpatching in Windows with 5 methods.
- Host: GitHub
- URL: https://github.com/windowsnt/hotpatch
- Owner: WindowsNT
- License: mit
- Created: 2018-10-22T18:45:16.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2018-10-23T12:16:47.000Z (over 7 years ago)
- Last Synced: 2025-04-10T16:06:55.162Z (about 1 year ago)
- Topics: hotfix, hotpatch, win32, win64
- Language: C++
- Size: 83 KB
- Stars: 64
- Watchers: 8
- Forks: 17
- Open Issues: 1
-
Metadata Files:
- Readme: Readme.md
- License: LICENSE
Awesome Lists containing this project
README
# HotPatch
A single-header C++ library for Windows to create hotpatchable images and apply hotpatches with 5 methods
Article at CodeProject: https://www.codeproject.com/Articles/1043089/HotPatching-Deep-Inside
## Executable to be hot-patched preparation
1. Build the executable in ***release*** mode from solution
2. The solution is automatically configured to run the executable with parameter /postbuildpatch which updates itself with the patch information. It uses BeginUpdateResource and EndUpdateResource.
Note that these are frequently stopped by antivirus. You can also use the included pig.exe which is a standalone app to read a file and its pdf, and put the hotpatch data inside it.
## Method 1: Using a DLL to patch an Executable
1. Load the DLL from the executable and call an exported function (say, Patch()).
2. Call hp.ApplyPatchFor() for each function you want to be patched:
```C++
hr = hp.ApplyPatchFor(hM, L"FOO::PatchableFunction1", PatchableFunction1, &xPatch);
```
## Method 2: Using the same executable as a COM server
1. Call hp.PrepareExecutableForCOMPatching();
2. If embedding, start the COM server, specifying the patches and installing a message loop:
```C++
void EmbeddingStart()
{
hp.StartCOMServer(GUID_TEST, [](vector& w) -> HRESULT
{
w.clear();
HOTPATCH::NAMEANDPOINTER nap;
nap.n = L"PatchableFunction1";
nap.f = [](size_t*) -> size_t
{
MessageBox(0, L"Patch from COM Patcher", L"Patched", MB_ICONINFORMATION);
return 0;
};
w.push_back(nap);
return S_OK;
},
[]()
{
// We are closing...
PostThreadMessage(mtid, WM_QUIT, 0, 0);
}
);
}
// main
if (argc == 2 && (_wcsicmp(wargv[1], L"-embedding") == 0 || _wcsicmp(wargv[1], L"/embedding") == 0))
{
mtid = GetCurrentThreadId();
EmbeddingStart();
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
```
If main, start the patching process
```C++
hp.StartCOMPatching();
vector pns;
hp.AckGetPatchNames(pns);
for (auto& aa : pns)
{
hp.ApplyCOMPatchFor(xPatch, GetModuleHandle(0), aa.c_str());
}
...
// End app
hp.FinishCOMPatching();
```
## Method 3: Using the same executable with shared memory
1. Call hp.PrepareExecutableForUSMPatching();
2. If patching mode, start the USM server, specifying the patches and installing a message loop:
```C++
void USMStart()
{
hp.StartUSMServer(GUID_TEST, [](vector& w) -> HRESULT
{
HOTPATCH::NAMEANDPOINTER nap;
nap.n = L"PatchableFunction1";
TCHAR cidx[1000] = { 0 };
StringFromGUID2(GUID_TEST, cidx, 1000);
swprintf_s(cidx + wcslen(cidx), 1000 - wcslen(cidx), L"-%u", 0);
nap.mu = (mutual*)new mutual(cidx, [&](unsigned long long)
{
MessageBox(0, L"Patch from USM Patcher", L"Patched", MB_ICONINFORMATION);
return;
}, 0, true);
w.push_back(nap);
return S_OK;
},
[]()
{
// We are closing...
PostThreadMessage(mtid, WM_QUIT, 0, 0);
}
);
}
// main
if (argc == 2 && (_wcsicmp(wargv[1], L"-usm") == 0 || _wcsicmp(wargv[1], L"/usm") == 0))
{
mtid = GetCurrentThreadId();
USMStart();
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
```
If main, start the patching process
```C++
// a has path name to patcher
wcscat_s(a, 1000, L" /usm");
// Run it with /USM
STARTUPINFO sInfo = { 0 };
sInfo.cb = sizeof(sInfo);
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcess(0, a, 0, 0, 0, 0, 0, 0, &sInfo, &pi))
return 0;
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// Get the names
vector pns;
hp.AckGetPatchNames(pns);
for (size_t i = 0; i < pns.size(); i++)
{
auto& aa = pns[i];
hp.ApplyUSMPatchFor(xPatch, GetModuleHandle(0), aa.c_str(), i);
}
...
// End app
hp.FinishCOMPatching();
```
## Method 4 : Self-EXE
This method is based on my article at https://www.codeproject.com/Articles/1045674/Load-EXE-as-DLL-Mission-Possible , which describes how to load an EXE as a DLL.
However this is a highly hackish method and should not be used.
## Method 5 : Self-DLL
The final method requires your app to be build itself as DLL. Therefore, the post-build event is now *rundll32 .\test.dll,PostBuildPatch*, the debugger run command is now *rundll32 .\test.dll,dmain*
and you can have the program and the patcher inside the same DLL.