You have to use DuplicateHandle to transfer the handle to your own process first
.
I'll have to stand UNcorrected on this. I initially thought there was something unique about DuplicateHandles making it easy to close handles on remote processes. Well, it seems to me that this is just misinformation. The only way to use DuplicateHandle with a remote process is to establish an IPC transport mechanism such as name pipes, WM_COPYDATA etc. between the two processes. This will allow the handle to be passed back and forth. Thus, it is limited to user processes not system processes. That is, it's nothing more than a very basic client/server model. The following code is an example of the ONLY way DuplicateHandle can be used to close a handle in a LOCAL process. It is for illustrative purposes. It's fully functional but executing the code will probably put your OS in an unstable state. To finish it off, you'll have to add an ExitProcess function and to be really fancy add a DeleteFile function to delete the executable making it a self deleting executable
Code:
#include <windows.h>
#include <stdio.h>
typedef UINT (WINAPI *WAITFORSINGLEOBJECT)(HANDLE, DWORD);
typedef BOOL (WINAPI *CLOSEHANDLE)(HANDLE);
typedef BOOL (WINAPI *DELETEFILE)(LPCTSTR);
typedef VOID (WINAPI *EXITPROCESS)(DWORD);
typedef DWORD (WINAPI *REMOTETHREAD)(LPVOID);
typedef struct
{
WAITFORSINGLEOBJECT WaitForSingleObject;
CLOSEHANDLE CloseHandle;
HANDLE hProcess;
TCHAR szFileName[MAX_PATH];
} FUNCTIONINJECT;
#pragma check_stack(off)
DWORD WINAPI RemoteThread(FUNCTIONINJECT *injectremote)
{
injectremote->WaitForSingleObject(injectremote->hProcess, INFINITE);
injectremote->CloseHandle(injectremote->hProcess);
return 0;
}
#pragma check_stack
BOOL CloseHandle()
{
HANDLE hRemoteProcess = NULL;
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if(CreateProcess(0, "explorer.exe", 0, 0, FALSE, (CREATE_SUSPENDED | CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS), 0, 0, &si, &pi)){
CloseHandle(pi.hThread);
hRemoteProcess = pi.hProcess;
}
if(hRemoteProcess == NULL) return FALSE;
BYTE *code = (BYTE *)VirtualAllocEx(hRemoteProcess, 0, sizeof(FUNCTIONINJECT) + 128, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(code == NULL){ CloseHandle(hRemoteProcess); return FALSE; };
FUNCTIONINJECT *remotestruct = (FUNCTIONINJECT *)(code + 128);
HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
FUNCTIONINJECT injectlocal;
injectlocal.WaitForSingleObject = (WAITFORSINGLEOBJECT)GetProcAddress(hKernel32, "WaitForSingleObject");
injectlocal.CloseHandle = (CLOSEHANDLE)GetProcAddress(hKernel32, "CloseHandle");
// Duplicate our own process handle for remotestruct process to wait on
HANDLE hCurrentProcess = GetCurrentProcess();
DuplicateHandle(hCurrentProcess, hCurrentProcess, hRemoteProcess, &injectlocal.hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
GetModuleFileName(NULL, injectlocal.szFileName, MAX_PATH);
WriteProcessMemory(hRemoteProcess, code, RemoteThread, 128, 0);
WriteProcessMemory(hRemoteProcess, remotestruct, &injectlocal, sizeof(injectlocal), 0);
DWORD dwThreadId = 0;
HANDLE hThread = CreateRemoteThread(hRemoteProcess, NULL, 0, (REMOTETHREAD)code, remotestruct, 0, &dwThreadId);
if(hThread != 0) CloseHandle(hThread);
return TRUE;
}
int main(void)
{
CloseHandle();
return 0;
}