This article logs the interesting things happened when I inject a DLL into the main thread of Notepad.exe.
The main thread is the thread which handles all code execution, so what happens if I inject a dll into the main thread?
In order to hijack the thread I have to first suspend it. Nothing went wrong, I can suspend the thread, and I can update the Context to point Rip to my payload.
But the payload is not executed, and Notepad.exe is dead when I tried to input anything into it.
If I tried to input something to freeze Notepad.exe, then close the app, the process will be terminated.
But, if I don't input anything, close Notepad.exe right after I hijack the main thread, Notepad.exe process maintains running in the background.
Looking at Threads, I got a kernel32.dll!LoadLibraryW
thread in Suspended
state.
I guess it's because the main thread is hijacked, all the code just cannot be processed, that means the call to LoadLibrary
too.
So, what I did is to manually resume this kernel32.dll!LoadLibraryW
thread (I tried to resume the notepad.exe one, nothing happened).
Code below:
#include <Windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
BOOL GetRemoteThreadHandle(OUT DWORD* dwThreadId, OUT HANDLE* hThread)
{
DWORD dwProcessId = 25260;
HANDLE hSnapShot = NULL;
THREADENTRY32 stThEntry = {
.dwSize = sizeof(THREADENTRY32)
};
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
if (INVALID_HANDLE_VALUE == hSnapShot)
goto _EndOfFunction;
if (!Thread32First(hSnapShot, &stThEntry))
goto _EndOfFunction;
do
{
if (stThEntry.th32OwnerProcessID == dwProcessId && stThEntry.th32ThreadID == 34672)
{
*dwThreadId = stThEntry.th32ThreadID;
*hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, stThEntry.th32ThreadID);
if (NULL == *hThread)
return FALSE;
break;
}
} while (Thread32Next(hSnapShot, &stThEntry));
_EndOfFunction:
if (NULL != hSnapShot)
CloseHandle(hSnapShot);
if (NULL == *dwThreadId || NULL == *hThread)
return FALSE;
return TRUE;
}
int main()
{
DWORD dwThreadId = NULL;
HANDLE hThread = NULL;
if (!GetRemoteThreadHandle(&dwThreadId, &hThread))
{
printf("[-]Failed to get thread handle...\n");
return -1;
}
ResumeThread(hThread);
printf("[*]Done...\n");
return 0;
}
And after executing it, calculator pops up.
Notice that, the state of the thread turned to WrUserRequest
, meaning that it resumed.
Beased on the behavior:
kernel32.dll!LoadLibraryW
is created as a worker thread, but why in suspended state?- main thread is dead, but what kept the process running in the background even after
kernel32.dll!LoadLibraryW
is resumed and finished executing?
Edit:
May have a clue here.
Inspecting the thread Stack here, the next job to be executed is ntdll.dll!NtSuspendThread
.
Since the main thread is suspended, the code stops executing.
After resuming the main thread, now the thread Stack is going to execute ZwWaitForSingleObject
, meaning that my payload is executed.
Still a question, which one is the main thread in the Threads tab?