FreeLibrary not unhooking DLL

714 views Asked by At

I'm trying to hook the DLL onto a notepad process, and then unhook it. When hooked, the DLL should cause the notepad to create a hidden file whenever the user clicks "Save As" (code for this is not shown). When unhooked, that should not be the case.

However, for some reason, while I got the message "DLL unhooking from process", the DLL still is not unhooked from the notepad process, and I know this because the notepad still creates the additional file when it should not have done that.

There are no error messages on the return values whatsover (at least none that I know of), so I removed most return value checks.

Hook

HANDLE hThread;
char * pid = argv[1];
DWORD user_pid = atoi(pid);
LPCSTR Dllpath = "C:\\Users\\xxx\\Desktop....\\MyDll.dll"
LPVOID pDllPath; // Address in remote process where Dllpath will be copied to.
HMODULE hKernel32 = GetModuleHandle("Kernel32");

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, user_pid);

char * command = argv[2];

if (strcmp(command,"hook") == 0){

    SIZE_T bytesWritten = 0;

    //Allocate memory to target process, and write dll to the allocated memory.
    pDllPath = VirtualAllocEx(hProcess, NULL,strlen(DllPath)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);

    // Write DLL hook name
    WriteProcessMemory(hProcess, pDllPath, (LPCVOID)DllPath, strlen(Dllpath)+1,&bytesWritten);

    // Load Dll to remote process
    hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), pDllPath,0,NULL);

    WaitForSingleObject(hThread, INFINITE);

    //Clean up
   CloseHandle(hThread);
   VirtualFreeEx(hProcess, pDllPath, strlen(DllPath+1, MEM_RELEASE);

else if (strcmp(command,"unhook")==0){
    InlineUnhook(); //Call unhook inside the dll itself
}

}

Unhook (inside the dll itself)

HANDLE __stdcall InlineUnhook(){

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
LoadLibrary("C:\\Users\\xxx\\Desktop...\\MyDll.dll);
HMODULE hLibModule = GetModuleHandleA ("C:\\Users\\xxx\\Desktop...\\MyDll.dll);

HANDLE hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "FreeLibraryAndExitThread"), (void *)(hLibModule,0),0,NULL);

if (hThread == NULL){
    OutputDebugStringA("CreateRemoteThread failed.");
    return -1;
}

else{
    WaitForSingleObject(hThread, INFINITE);

    //Clean up
    CloseHandle(hThread);
    OutputDebugStringA("DLL unhooking from process...");

    return 0;
}
}
2

There are 2 answers

2
Remy Lebeau On

Your injector is calling InlineUnhook() directly, so it will act on the instance of the DLL that is loaded in the injector process, not the hooked process.

FreeLibraryAndExitThread() is not compatible with CreateRemoteThread(), so you can't use a remote thread to call it directly, like you can with LoadLibraryA().

Inside of the DLL itself, there is no need for it to call OpenProcess(), LoadLibrary(), or CreateRemoteThread() for itself. The DLL can simply call FreeLibraryAndExitThread() directly, like any other local function.

HINSTANCE hThisInst;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
    hThisInst = hinstDLL;
    ...
    return 1;
}

void __stdcall InlineUnhook()
{
    FreeLibraryAndExitThread(hThisInst, 0);
}

Your injector will have to use a remote thread to call InlineUnhook() within the context of the hooked process, rather than calling it directly. That means you need to:

  • export InlineUnhook() from the DLL.

  • find the address of the loaded DLL within the hooked process. If your DLL is 32bit being loaded into a 32bit target process, that address can be obtained from GetExitCodeThread() when CreateRemoteThread() is done calling LoadLibraryA(). Otherwise, you will have to go hunting for the loaded address afterwards, such as by EnumProcessModules() or CreateToolhelp32Snapshot(TH32CS_SNAPMODULE).

  • find the address of the exported InlineUnhook() within the hooked process. Use LoadLibrary() and GetProcAddress() inside the injector to calculate the offset of InlineUnhook() within the DLL, and then apply that offset to the address of the loaded DLL within the hooked process.

  • use CreateRemoteThread() to call InlineUnhook() at that calculated address. You will have to change the signature of InlineUnhook() to be compatible with CreateRemoteThread(), eg:

DWORD __stdcall InlineUnhook(LPVOID)
{
    FreeLibraryAndExitThread(hThisInst, 0);
    return 1;
}
0
500 - Internal Server Error On

That's because your InlineUnhook call above calls the copy of the dll that is loaded into your injection process, not the one in the target process.