GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - WindowsNT/hotpatch: Hotpatching in Windows with 5 methods.

BranchesTags
Open more actions menu

Latest commit

 

History

13 Commits
13 Commits

Folders and files

NameName
Last commit message
Last commit date
Method1
Method1
 
 
Method2
Method2
 
 
Method3
Method3
 
 
Method4
Method4
 
 
Method5
Method5
 
 
PatchInfoGenerator
PatchInfoGenerator
 
 
xml @ 262397d
xml @ 262397d
 
 
.gitignore
.gitignore
 
 
.gitmodules
.gitmodules
 
 
LICENSE
LICENSE
 
 
Readme.md
Readme.md
 
 
hotpatch.h
hotpatch.h
 
 

Repository files navigation

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:
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:
void EmbeddingStart()
{
	hp.StartCOMServer(GUID_TEST, [](vector<HOTPATCH::NAMEANDPOINTER>& 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

hp.StartCOMPatching();
vector<wstring> 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:
void USMStart()
{
	hp.StartUSMServer(GUID_TEST, [](vector<HOTPATCH::NAMEANDPOINTER>& 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

// 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<wstring> 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.

About

Hotpatching in Windows with 5 methods.

Topics

hotfixhotpatchwin32win64

Resources

Readme
MIT license
Activity

Stars

65 stars

Watchers

7 watching

Forks

18 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.