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.
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:
HANDLE CreateRemoteThread(
HANDLE hProcess, </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:
- User
VirtualAllocEx
API to allocate memory equal to the size of DLL full file path in the remote process:
VirtualAllocEx(hProcess, NULL, dwSizeOfFilePath, MEM_COMMIT, PAGE_READWRITE);
- Use
WriteProcessMemory
to copy the DLL's full file path in the allocated space [Step 1]:
WriteProcessMemory(hProcess, pDLLFilePath,
(void</span />*)szDLLFilePath, dwSizeOfFilePath,NULL);
- 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.
::CreateRemoteThread(
hProcess, </span /> NULL,
0</span />,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"</span />LoadLibraryA"</span />),
pDLLFilePath, </span /> 0</span />,
NULL);
- Using
VirtualFreeEx
function to free the memory allocated in step 1:
::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:
- Locate the Module’s import section by calling
ImageDirectoryEntryToData
. - 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.
- 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:
pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDesc-></span />FirstThunk);
- 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:
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
.
DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch</span />( ul_reason_for_call )
{
case</span /> DLL_PROCESS_ATTACH:
HookTheAPI(); </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.
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 RandomNumber
s 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
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.