Click here to Skip to main content
15,880,967 members
Articles / Programming Languages / C++

Hot Patching Made Easy

Rate me:
Please Sign up or sign in to vote.
4.88/5 (6 votes)
7 Oct 2010CPOL5 min read 47.4K   1.7K   45   11
Addresses the problems related to unavailability of service provided by the system or the program

Introduction

A patch is a piece of software designed to fix problems.

Hot patching is a mechanism of applying the patch to an application without requiring to shutdown or restart the system or the program concerned. This addresses the problems related to unavailability of service provided by the system or the program.

Example

We came across a situation where a DLL is loaded by one of the critical processes in a system and that process demands high availability. The DLL has exported functions that are supposed to perform the core operations within the process. We identified a critical flaw in one of the exported functions from the DLL. One constraint we had while trying to fix the problem was to avoid any down time of this critical process.

We solved this problem by using the hot patch mechanism. We used an external process to inject a DLL [Hot patch]. This DLL has the corrected version of the defective function and also a hook to GetProcAddress function. As we know, calling GetProcAddress returns the address of the exported function from the specified DLL. By hooking into the GetProcAddress API, we monitored the requests to the exported function. When we find that the request was made for the flawed function, we just returned the address of the updated function which was part of the injected DLL.

By intercepting the calls of GetProcAddress API, we redirected the requests from the flawed function to the corrected function.

We could resolve this problem by using the concepts like DLL injection and API hooking.

Hot Patch Structure

This hot patching structure has the following binaries:

  • Hot Patch DLL: This DLL has only exported functions that are updated and will be used as replacement for the flawed functions. This also has the hooking logic to hook to GetProcAddress API exported by Kernel32.DLL.
  • Updater.exe: This process injects the hot patched DLL into the target process.
Image.png

How to Inject DLL into a Remote Process

One method of injecting a DLL into a remote process requires a thread in the remote process to call LoadLibray of the desired DLL. Since we can't control the threads in a process other that our own, the solution would be to create a new thread in the target process. This enables us to have full control over the code that this thread is going to execute.

We can create a thread in a remote process using the following Windows API:

C++
HANDLE CreateRemoteThread(
	HANDLE hProcess,		//</span /> Handle of the target process
</span />	PSECURITY_ATTRIBUTES psa,
	DWORD dwStackSize,
	PTHREAD_START_ROUTINE pfnStartAddr,
	PVOID pvParam,
	DWORD fdwCreate,
	PDWORD pdwThreadId );

After creating a new thread in the target process, we need to make sure that there is a call to LoadLibrary API that will load the DLL into the target process.

Following is the complete set of steps for injecting a DLL into the target process:

  1. User VirtualAllocEx API to allocate memory equal to the size of DLL full file path in the remote process:
    C++
    VirtualAllocEx(hProcess, NULL, dwSizeOfFilePath, MEM_COMMIT, PAGE_READWRITE);
  2. Use WriteProcessMemory to copy the DLL's full file path in the allocated space [Step 1]:
    C++
    WriteProcessMemory(hProcess, pDLLFilePath, 
    	(void</span />*)szDLLFilePath, dwSizeOfFilePath,NULL);
  3. Use CreateRemoteThread API to create thread in the remote process passing in the address of LoadLibary API and also the memory location of the DLL's full file path.
    C++
    ::CreateRemoteThread(
    	hProcess, 		//</span /> Handle of the target process
    </span />	NULL,
    	0</span />,
    	(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"</span />LoadLibraryA"</span />), 
    	pDLLFilePath, //</span /> Address of the Full DLL file path as done in Step 1
    </span />	0</span />,
    	NULL);
  4. Using VirtualFreeEx function to free the memory allocated in step 1:
    C++
    ::VirtualFreeEx( hProcess, pDLLFilePath, dwSize, MEM_RELEASE );

How to Perform API Hooking using Import Section

Using module’s import section to perform hooking is quiet robust and easy to implement. To hook to a particular function, all we need to do is change the address of the flawed function in the module's import section.

We are trying to Hook to the GetProcAddress API exported by Kernel32.dll.

Following is the complete set of steps for API hooking:

  1. Locate the Module’s import section by calling ImageDirectoryEntryToData.
  2. Loop through import section for the DLL which contains API that we want to hook. In this case, we would be searching for Kernel32.dll.
  3. Once the DLL module is located, get the address to the array of IMAGE_THUNK_DATA structure that contains the information about the imported symbols:
    C++
    pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDesc-></span />FirstThunk);
  4. Once the address of the exported is located, use the following APIs to update the address to the new function that needs to be hooked:
    C++
    WriteProcessMemory(GetCurrentProcess(), ppfn, &pNewFunction,
    sizeof</span />(pNewFunction), NULL);
    VirtualProtect(ppfn, sizeof</span />(pNewFunction), dwOldProtect,&dwOldProtect);

When Are We Going to Perform this Hooking

Immediately after injecting the DLL into the remote process, LoadLibary calls the DLLMain of the injected DLL with ul_reason_for_call as DLL_PROCESS_ATTACH.

C++
DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	switch</span />( ul_reason_for_call )
	{
		case</span /> DLL_PROCESS_ATTACH:
			HookTheAPI();		//</span /> method to hook the desired API
</span />			break</span />;
	}
}

Implementing Our Own GetProcAddress

Our custom MyGetProcAddress will intercept all the calls made to GetProcAddress APIs to monitor if there is any request for the faulting function and if so, return the address of the corrected function.

C++
FARPROC WINAPI MyGetProcAddress(HMODULE hmod, PCSTR pszProcName)
{
	pOldFunAdd = GetProcAddress(GetModuleHandle("</span />MySubsystem.dll"</span />), "</span />Foo"</span />);
	pNewFunAdd = GetProcAddress(GetModuleHandle("</span />MySubsystem.HP.dll"</span />), "</span />"</span />Foo"</span />);
	pRetFunAdd = GetProcAddress(hmod, pszProcName);

	if((NULL != pOldFunAdd) && (NULL != pNewFunAdd))
	{
		// if the request is of that Faulting Function
		if(pOldFunAdd == pRetFunAdd )
			pRetFunAdd = pNewFunAdd;	// Return address of 
						// corrected function
	}

	return pRetFunAdd ;
}</span />

Demo Application

The attached binaries demo the hot patching implemented using the DLL Injection and Function Hooking. To keep the thing simple and for easy understanding, I am demonstrating with a very basic functionality. Please ignore the code optimizations for now:

  • MySubsystem.DLL: This DLL exports following functions
    • RandomNumber: Returns a random number
    • SleepTime: Specifies the time to sleep before making the other call to RandomNumber
  • MyProcess.exe: This process loads the MySubsystem.DLL and displays the RandomNumbers in console after sleeping for the specified amount of time as returned by MySubsystem.DLL.
  • Change Request: Displays the random numbers which are even. Odd number should not be displayed on the console. This has to be accomplished without restarting the process MyProcess.exe.
  • MySubsystem.HP.DLL: This is a HOT Patch DLL that contains the corrected MyRandomNumber as per the request. This also has the implementation for Hooking and Hooked function MyGetProcAddress.
  • Updater.exe: This process injects the MySubsystem.HP.DLL into MyProcess.exe

Run MyProcess.exe to see that RandomNumbers which are both even and odd are getting displayed. Run the updater.exe and you will see only even numbers getting displayed. All the odd numbers are skipped.

Limitations

One limitation for this approach is that the functions that are exported can be hot patched.

References

History

  • 6th October, 2010: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Question64-Bit? Pin
ITSTH14-May-13 1:14
ITSTH14-May-13 1:14 
GeneralGood, but impractical Pin
Ajay Vijayvargiya14-Oct-10 4:50
Ajay Vijayvargiya14-Oct-10 4:50 
GeneralMy vote of 5 Pin
Andriy Tylychko11-Oct-10 13:37
Andriy Tylychko11-Oct-10 13:37 
GeneralNice article - quick question. Pin
yafan7-Oct-10 3:38
yafan7-Oct-10 3:38 
GeneralRe: Nice article - quick question. Pin
Venkat Varagani10-Oct-10 20:59
Venkat Varagani10-Oct-10 20:59 
GeneralRe: Nice article - quick question. Pin
Andriy Tylychko11-Oct-10 13:34
Andriy Tylychko11-Oct-10 13:34 
QuestionWhy? Pin
Dave Cross7-Oct-10 2:12
professionalDave Cross7-Oct-10 2:12 
AnswerRe: Why? Pin
Venkat Nag7-Oct-10 2:48
Venkat Nag7-Oct-10 2:48 
GeneralRe: Why? Pin
Dave Cross7-Oct-10 7:29
professionalDave Cross7-Oct-10 7:29 
GeneralRe: Why? Pin
[NL]PUR15-Oct-10 4:41
[NL]PUR15-Oct-10 4:41 
GeneralRe: Why? Pin
pd4516-Oct-10 1:45
pd4516-Oct-10 1:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.