CreateRemoteThread works with PROCESS_QUERY_LIMITED_INFORMATION - c++

Recently, I've studied dll injection techniques using CreateRemoteThread, and I found something interesting. I just opened the process with PROCESS_QUERY_LIMITED_INFORMATION and called CreateRemoteThread with its handle. Surprisingly it worked. The funny thing about this, I tried create remote thread in the same way with another function NtCreateThreadEx which is an internal function of CreateRemoteThread and it didn't work.I can't understand what's happening here. The code is as follows:
void Create_Remote_Thread()
{
HMODULE ntdll, kernel32;
HANDLE hCurrp = nullptr;
ntdll = GetModuleHandle(L"ntdll.dll");
kernel32 = LoadLibrary(L"kernel32.dll");
FARPROC lpfnLoadLibrary = NULL;
_NtGetNextProcess nextProc = (_NtGetNextProcess)GetProcAddress(ntdll, "NtGetNextProcess");
lpfnLoadLibrary = GetProcAddress(kernel32, "LoadLibraryA");
char buf[MAX_PATH];
//while (nextProc(hCurrp, PROCESS_QUERY_LIMITED_INFORMATION, 0, 0, &hCurrp) == 0) {
while (nextProc(hCurrp, PROCESS_ALL_ACCESS, 0, 0, &hCurrp) == 0) {
GetModuleFileNameExA(hCurrp, 0, buf, MAX_PATH);
HANDLE hThread = NULL;
if (strstr(buf, "notepad.exe") != NULL) {
hThread = CreateRemoteThread(hCurrp, NULL, 0, (LPTHREAD_START_ROUTINE)lpfnLoadLibrary, NULL, 0, NULL);
}
}
}
Then, Can I create remote thread just with lower privilege? If anyone knows about this, please inform me. Thanks.

Related

CreateRemoteThread + LoadLibraryA doesn't do anything despite succeeding

Despite the fact that memory allocation/write, finding LoadLibraryA address and creating a remote thread return valid (not NULL) results, absolutely nothing happens after that (mainly, the DllMain of the loaded DLL doesn't seem to get called).
#define PROC_NAME L"TestConsole.exe"
#define DLL_NAME "TestLib.dll\0"
HANDLE GetProcessByName(const wchar_t* name);
int main()
{
const char dllName[] = DLL_NAME;
int dllNameSize = strlen(dllName) + 1;
HANDLE process = GetProcessByName(PROC_NAME);
LPVOID allocMem = VirtualAllocEx(process, NULL, dllNameSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(process, allocMem, dllName, dllNameSize, NULL);
// Just to make sure
char buff[20];
ReadProcessMemory(process, allocMem, buff, dllNameSize, NULL);
printf("Data: %s\n", buff);
LPVOID libraryAddress =
(LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
HANDLE remoteThread = CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)libraryAddress, allocMem, NULL, NULL);
}
HANDLE GetProcessByName(const wchar_t* name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (wcscmp(entry.szExeFile, name) == 0)
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ParentProcessID);
}
}
}
return NULL;
}
Things I know/checked:
The thread gets created and a valid (not null) handle is returned. Despite it nothing happens.
I'm pretty sure that it's not DLL's fault. It's extremely simple, simply prints to console when it gets loaded and it works correctly when used simply with CreateThread().
Injector, DLL and the app to which I'm injecting are all 64 bit. If I chose any other platform (for all 3) everything works the same except for CreateRemoteThread(), which now fails.
The entry.th32ParentProcessID is the identifier of the process that created this process (its parent process). which means you did inject into the parent process of the target process (explorer.exe in my test). You should use entry.th32ProcessID instead.
In addition, the open permission PROCESS_ALL_ACCESS used in OpenProcess is too large, you only need to use what the CreateRemoteThread document requires: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ

WINAPI - Close mutex without being the owner

I'm trying to close a mutex in another application.
I'm using the WinAPI ("windows.h").
Here's my code to close this mutex:
DWORD pid = 0;
hMyWnd = FindWindow(NULL, "TheFamousWindowName");
GetWindowThreadProcessId(hMyWnd, &pid);
HANDLE hProc = OpenProcess(PROCESS_DUP_HANDLE, 0, pid);
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, "TheEvilMutex"); // hMutex isn't null
WaitForSingleObject(hMutex, 10000); // Wait 10 seconds, nothing happens
if (!DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)) {
// Arrive always here because of error 288
// And the mutex is still there, not closed
}
ReleaseMutex(hMutex);
CloseHandle(hMutex);
The problem is when I call
DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
I got the error 288 with
GetLastError()
labeled as "Attempt to release mutex not owned by caller" and the mutex isn't closed
Now, I know that I'm not the owner, but I can't see a solution to close this mutex.
I've seen some programs doing it like Process Explorer or Process Hacker. I've looked into the code of this last on GitHub but didn't find anything about how it close a mutex without being the owner.
I've also checked this thread
how does procexp close a mutex held by another process? but I can't get it working.
Thanks for reading me.
Hoping someone could help me.
EDIT :
Thanks to #RbMm, replacing
DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
with
DuplicateHandle((HANDLE)-1, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
solved error 288, but the mutex isn't closed with this.
in call DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE) hMutex must be handle that is valid in the context of the hProc. but hMutex is handle in current process, not in hProc. so in this line of code you try close arbitrary handle in context of hProc, but not your hMutex. and result of this will be arbitrary. may be you close some handle. may be this handle not exist at all, or handle is protected from close.
And the mutex is still there, not closed
of course it not closed and can not be closed. for close it you need call
DuplicateHandle(NtCurrentProcess(), hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE);
because of error 288
i absolute sure that DuplicateHandle never return this error. ERROR_NOT_OWNER you got from ReleaseMutex(hMutex);
for close mutex in another process - need use handle value of this mutex in target process, not in self process. this code is done work:
void CloseRemote(ULONG dwProcessId, PCWSTR Name)
{
// create any file
HANDLE hFile = OpenMutex(MAXIMUM_ALLOWED, FALSE, Name);
if (hFile != INVALID_HANDLE_VALUE)
{
if (HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId))
{
NTSTATUS status;
ULONG cb = 0x80000;
union {
PSYSTEM_HANDLE_INFORMATION_EX pshi;
PVOID pv;
};
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (pv = LocalAlloc(0, cb))
{
if (0 <= (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, pv, cb, &cb)))
{
if (ULONG_PTR NumberOfHandles = pshi->NumberOfHandles)
{
ULONG_PTR UniqueProcessId = GetCurrentProcessId();
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles = pshi->Handles;
do
{
// search for created file
if (Handles->UniqueProcessId == UniqueProcessId && Handles->HandleValue == (ULONG_PTR)hFile)
{
// we got it !
PVOID Object = Handles->Object;
NumberOfHandles = pshi->NumberOfHandles, Handles = pshi->Handles;
do
{
if (Object == Handles->Object && Handles->UniqueProcessId == dwProcessId)
{
DuplicateHandle(hProcess, (HANDLE)Handles->HandleValue, 0, 0, 0, 0, DUPLICATE_CLOSE_SOURCE);
}
} while (Handles++, --NumberOfHandles);
break;
}
} while (Handles++, --NumberOfHandles);
}
}
LocalFree(pv);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
CloseHandle(hProcess);
}
CloseHandle(hFile);
}
}

Cannot read pipe from CreateProcess() thread

I'm stuck on this since days, i'm goind crazy.
Basically i'm trying to open cmd.exe in a thread and give it input and read output from it, from the parent. Like, assigning a tty in linux, since there's no such thing in windows. I have a good understanding of linux systems but can't say the same thing about windows.
So, here's "my" code:
#undef UNICODE
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
//using namespace std;
#define BUFFER_SIZE 99
// handles for cmd thread pipes
HANDLE cmd_in_rd = NULL;
HANDLE cmd_in_wr = NULL;
HANDLE cmd_out_rd = NULL;
HANDLE cmd_out_wr = NULL;
HANDLE cmd_thread_handle;
void PrintError(char *text, int err) {
DWORD retSize;
LPTSTR pTemp = NULL;
if (!err) return;
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
err,
LANG_NEUTRAL,
(LPTSTR)&pTemp,
0,
NULL);
if (pTemp) printf("%s: %s\n", text, pTemp);
LocalFree((HLOCAL)pTemp);
return;
}
int pipewrite(char *command) {
DWORD dwRead, dwWritten;
BOOL bSuccess = FALSE;
SetLastError(0);
WriteFile(cmd_in_wr, command, strlen(command), &dwWritten, NULL);
bSuccess = GetLastError();
PrintError("WriteToPipe", bSuccess);
return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
}
int __stdcall cmd_thread(int arg) {
// this function only prints when data is ready
DWORD dwRead, dwWritten;
CHAR chBuf[BUFFER_SIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
int rf_ret, wf_ret;
//CloseHandle(cmd_out_wr); makes readfile fail!!
SetLastError(0);
while (1) { // only executes once!!!!!!!
(rf_ret = ReadFile(cmd_out_rd, chBuf, BUFFER_SIZE, &dwRead, NULL))
&&
(wf_ret = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL));
printf("ReadFile returned: %d\nWriteFile returned: %d\n", rf_ret, wf_ret);
bSuccess = GetLastError();
PrintError("ReadingFromPipe", bSuccess);
}
bSuccess = GetLastError();
return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
}
int main(void) {
char buffer[BUFFER_SIZE];
// init the pipes
SECURITY_ATTRIBUTES cmd_sa;
cmd_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
cmd_sa.bInheritHandle = TRUE;
cmd_sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&cmd_out_rd, &cmd_out_wr, &cmd_sa, 0)) {
printf("%s\n", "Error creating pipes");
return 1;
}
if (!SetHandleInformation(cmd_out_rd, HANDLE_FLAG_INHERIT, 0)) {
printf("%s\n", "Error setting handle infos");
return 1;
}
if (!CreatePipe(&cmd_in_rd, &cmd_in_wr, &cmd_sa, 0)) {
printf("%s\n", "Error creating pipes");
return 1;
}
if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {
printf("%s\n", "Error setting handle infos");
return 1;
}
// create the cmd thread
PROCESS_INFORMATION cmd_pi;
STARTUPINFO cmd_si;
ZeroMemory(&cmd_pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&cmd_si, sizeof(STARTUPINFO));
cmd_si.cb = sizeof(STARTUPINFO);
cmd_si.hStdError = cmd_out_wr;
cmd_si.hStdOutput = cmd_out_wr;
cmd_si.hStdInput = cmd_in_rd;
cmd_si.dwFlags |= STARTF_USESTDHANDLES;
TCHAR comm[] = TEXT("cmd.exe");
BOOL th = CreateProcess(NULL,
comm,
NULL,
NULL,
TRUE, // handles are inherited
0,
NULL,
NULL,
&cmd_si,
&cmd_pi);
if (th) {
CloseHandle(cmd_pi.hProcess);
CloseHandle(cmd_pi.hThread);
}
cmd_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)cmd_thread, NULL, 0, NULL);
// read commands from shell and send them to cmd
ZeroMemory(&buffer, BUFFER_SIZE);
while (1) {
fgets(buffer, BUFFER_SIZE, stdin);
if (!pipewrite(buffer)) break;
}
printf("Program terminated\n");
return 0;
}
I actually, for testing purposes, copied a lot from another question on stackoverflow and from MSDN since i couldn't get it to work on my main program. The things I don't understand are:
Why the while loop inside cmd_thread gets executed at startup and then hangs there waiting for the end of the world? I tried to close the pipe out_write handle from the parent before reading, but that makes other parts not working.
pipewrite() seems to work, but I can't be sure that the cmd.exe thread receives and works the input... Since i get no output :/
I thought about stracing/ltracing the program or running it into a debugger, but I know no tool for that...
The strange thing is that the original works (the one from where i got the code). I tried to spot the difference between the two, but even when I look to them side by side, they seem to do the exact same things.
The child process is dying as soon as it attempts to read from standard input, because:
if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {
This should have been:
if (!SetHandleInformation(cmd_in_wr, HANDLE_FLAG_INHERIT, 0)) {
like in the original code.
Also, your error handling is largely incorrect; you don't consistently check for errors and you sometimes call GetLastError() when no error has occurred. (Those problems are in the original code too.)
You also need to put the call to CloseHandle(cmd_out_wr); back in because otherwise you won't be able to tell when the child exits.
Oh, and incidentally, cmd.exe is a process, not a thread.

Injected DLL and calling a function using CreateRemoteThread causes "has stopped working", what happens?

I`m trying to inject a DLL in a process and call a exported function in my DLL.
The DLL is injected alright with that code:
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
HANDLE hThread = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
The module of my DLL is created OK, like you see in that image of Process Hacker (BootstrapDLL.exe):
My exported functions is ok too, like you see in the list of functions exported on Process Hacker (ImplantDotNetAssembly):
The problems, I think, happens on the offset calculation to get the address of the "ImplantDotNetAssembly", because everything above is alright and when I do the calculation I get the address of the "ImplantDotNetAssembly", but when I call CreateRemoteThread again to call it, the window "Has stopped working..." of the windows is showed and the process stoped. What`s happening?
Here is the code of the calculation of the offset:
DWORD_PTR hBootstrap = GetRemoteModuleHandle(ProcId, L"BootstrapDLL.exe");
DWORD_PTR offset = GetFunctionOffset(L"C:\\Users\\Acaz\\Documents\\Visual Studio 2013\\Projects\\Contoso\\Debug\\BootstrapDLL.exe", "ImplantDotNetAssembly");
DWORD_PTR fnImplant = hBootstrap + offset;
HANDLE hThread2 = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)fnImplant, NULL, 0, NULL);
Here are the functions GetRemoteModuleHandle and GetFunctionOffset:
DWORD_PTR GetFunctionOffset(const wstring& library, const char* functionName)
{
// load library into this process
HMODULE hLoaded = LoadLibrary(library.c_str());
// get address of function to invoke
void* lpInject = GetProcAddress(hLoaded, functionName);
// compute the distance between the base address and the function to invoke
DWORD_PTR offset = (DWORD_PTR)lpInject - (DWORD_PTR)hLoaded;
// unload library from this process
FreeLibrary(hLoaded);
// return the offset to the function
return offset;
}
DWORD_PTR GetRemoteModuleHandle(const int processId, const wchar_t* moduleName)
{
MODULEENTRY32 me32;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
// get snapshot of all modules in the remote process
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
// can we start looking?
if (!Module32First(hSnapshot, &me32))
{
CloseHandle(hSnapshot);
return 0;
}
// enumerate all modules till we find the one we are looking for or until every one of them is checked
while (wcscmp(me32.szModule, moduleName) != 0 && Module32Next(hSnapshot, &me32));
// close the handle
CloseHandle(hSnapshot);
// check if module handle was found and return it
if (wcscmp(me32.szModule, moduleName) == 0)
return (DWORD_PTR)me32.modBaseAddr;
return 0;
}
If someone know what is happening, I'll be very grateful!
I cant`t even debug the "has stopped work.." error. When I clik in the DEBUG button on the window, the error throw again and everything stop.
Thank you.
NEVER inject managed assemblies. If for some reason you must inject code into another process, use native code with either NO C library or a STATIC C library.

Ejecting after injecting DLL from running process

I wrote this function to inject DLL into running process:
DLL_Results CDLL_Loader::InjectDll()
{
DWORD ThreadTeminationStatus;
LPVOID VirtualMem;
HANDLE hProcess, hRemoteThread;
HMODULE hModule;
if (!isInit())
return NOT_INIT;
if (isInjected())
return DLL_ALREADY_HOOKED;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if (hProcess == NULL)
return PROCESS_ERROR_OPEN;
VirtualMem = VirtualAllocEx (hProcess, NULL, strlen(DllFilePath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (VirtualMem == NULL)
return PROCESS_ERRORR_VALLOC;
if (WriteProcessMemory(hProcess, (LPVOID)VirtualMem, DllFilePath, strlen(DllFilePath), NULL) == 0)
{
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE|MEM_COMMIT);
CloseHandle(hProcess);
return PROCESS_ERROR_WRITE;
}
hModule = GetModuleHandle(L"kernel32.dll");
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA"),
(LPVOID)VirtualMem, 0, NULL);
if (hRemoteThread == NULL)
{
FreeLibrary(hModule);
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE | MEM_COMMIT);
CloseHandle(hProcess);
return PROCESS_ERROR_CREATE_RTHREAD;
}
WaitForSingleObject(hRemoteThread, INFINITE);
GetExitCodeThread(hRemoteThread, &ThreadTeminationStatus);
FreeLibrary(hModule);
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE | MEM_COMMIT);
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
injected = true;
return DLLHOOK_OK;
}
And It works great, but when i was trying to eject the dll i was unable to find information about unhooking.. i was trying to build some function to do it and i think i'm close
this is what i've got so far:
is that the right way? if so what parameter should i pass in createRemoteThread instade of VirtualMem (That was used in the injecting function)...
DLL_Results CDLL_Loader::EjectDll()
{
DWORD ThreadTeminationStatus;
HANDLE hProcess, hRemoteThread;
HMODULE hModule;
if (isInjected())
return DLLEJECT_OK;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if (hProcess == NULL)
return PROCESS_ERROR_OPEN;
hModule = GetModuleHandle(L"kernel32.dll");
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary"),
/*(LPVOID)VirtualMem <- What do i need to send here?*/, 0, NULL);
if (hRemoteThread != NULL)
{
WaitForSingleObject(hRemoteThread, INFINITE);
GetExitCodeThread(hRemoteThread, &ThreadTeminationStatus);
}
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
injected = false;
return DLLEJECT_OK;
}
On 32-bit systems, the value of ThreadTeminationStatus after GetExitCodeThread contains the return value of LoadLibraryA in the remote process.
This is the module handle of the newly loaded dll.
You can use it as the parameter to FreeLibrary in the remote thread.
If you want to use the code on 64-bit Windows, the thread exit code is truncated to a 32-bit DWORD, so it's unusable.
You have to create a callable routine in the remote process (as Necrolis suggested) or resort to finding the module base of the DLL via psapi or the Toolhelp API (CreateToolhelp32Snapshot, Module32First, Module32Next).
You need to pass it the HANDLE of the dll you injected, else you can pass it VirtualMem but then your remote thread routine would need to be:
DWORD WINAPI UnloadDll(void* pMem)
{
FreeLibrary(GetModuleHandleA((const char*)pMem));
return 0;
}
However, generally the dll you inject should unload itself (see how DllMain works), either manually or automatically when the host is closed.