phnt
phnt copied to clipboard
Process Cloning Not Working in x86 Windows Config (C++)
I'm attempting to clone a process in C++ on Windows. All shown examples were compiled & ran with Visual Studio 2022 on a Windows 10 system.
The minimal example below (adapted from the following tutorial on process cloning in Windows) uses the NtCreateUserProcess
function from this phnt
library in order to perform the process clone, smillar to the Unix fork
function:
#include <iostream>
#include <chrono>
#include <thread>
#include <phnt_windows.h>
#include <phnt.h>
int main()
{
std::cout << "---- PROGRAM STARTED ----\n\n";
// Prepare cloning variables
HANDLE processHandle, threadHandle;
PS_CREATE_INFO createInfo = {0};
createInfo.Size = sizeof(createInfo);
// Do the actual cloning
NTSTATUS cloneStatus = NtCreateUserProcess(&processHandle, &threadHandle, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, PROCESS_CREATE_FLAGS_INHERIT_HANDLES, 0, NULL, &createInfo, NULL);
// Print something from cloned process & exit it
if (cloneStatus == STATUS_PROCESS_CLONED)
{
FreeConsole();
AttachConsole(ATTACH_PARENT_PROCESS);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "This is from cloned process. (ID: " << (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess << ")\n";
NtTerminateProcess(NtCurrentProcess(), STATUS_PROCESS_CLONED);
}
// Check if parent successfully created cloned process
else
{
std::cout << "This is from original process. (ID: " << (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess << ")\n";
if (!NT_SUCCESS(cloneStatus))
{
std::cout << "ERROR: Failed to clone process! (Status: " << cloneStatus << ")\n";
}
else
{
NTSTATUS waitStatus = NtWaitForSingleObject(processHandle, FALSE, NULL);
NtClose(processHandle);
NtClose(threadHandle);
if (!NT_SUCCESS(waitStatus))
std::cout << "ERROR: Cloned process failed to return! (Status: " << waitStatus << ")\n";
else
std::cout << "Cloned process successfully returned.\n";
}
}
std::cout << "\n---- PROGRAM FINISHED ----\n\n";
system("pause");
return 0;
}
The example above can successfully clone a process in the x64
configuration in my VS instance:
---- PROGRAM STARTED ----
This is from original process. (ID: 14352)
This is from cloned process. (ID: 20648)
Cloned process successfully returned.
---- PROGRAM FINISHED ----
However, it appears that the example above, and other examples present in the cloning tutorial linked above, do not work properly in any x86
configuration. Attempting to run the example above in any x86
configuration results in only the parent process printing it's output:
---- PROGRAM STARTED ----
This is from original process. (ID: 20332)
Cloned process successfully returned.
---- PROGRAM FINISHED ----
The child process appears to terminate & return successfully, but it fails to print it's output.
The same behaviour is exhibited with the following slightly different example using the RtlCloneUserProcess
function, also from this library:
#include <iostream>
#include <chrono>
#include <thread>
#include <phnt_windows.h>
#include <phnt.h>
int main()
{
std::cout << "---- PROGRAM STARTED ----\n\n";
// Prepare cloning variables
RTL_USER_PROCESS_INFORMATION cloneInfo;
// Do the actual cloning
NTSTATUS cloneStatus = RtlCloneUserProcess(RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &cloneInfo);
// Print something from cloned process & exit it
if (cloneStatus == STATUS_PROCESS_CLONED)
{
FreeConsole();
AttachConsole(ATTACH_PARENT_PROCESS);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "This is from cloned process. (ID: " << (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess << ")\n";
NtTerminateProcess(NtCurrentProcess(), STATUS_PROCESS_CLONED);
}
// Check if parent successfully created cloned process
else
{
std::cout << "This is from original process. (ID: " << (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess << ")\n";
if (!NT_SUCCESS(cloneStatus))
{
std::cout << "ERROR: Failed to clone process! (Status: " << cloneStatus << ")\n";
}
else
{
NTSTATUS waitStatus = NtWaitForSingleObject(cloneInfo.ProcessHandle, FALSE, NULL);
NtClose(cloneInfo.ProcessHandle);
NtClose(cloneInfo.ThreadHandle);
if (!NT_SUCCESS(waitStatus))
std::cout << "ERROR: Cloned process failed to return! (Status: " << waitStatus << ")\n";
else
std::cout << "Cloned process successfully returned.\n";
}
}
std::cout << "\n---- PROGRAM FINISHED ----\n\n";
system("pause");
return 0;
}
Also only printing the parent process's output when running in the x86
configuration.
I'm assuming that I'm missing some include files specifically for building these examples in the x86
configuration. The only additional include directory I have setup in these VS example projects is the phnt
library, and below is the list of libraries included by the Linker (copied from the official examples):
ntdll.lib
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib
Has anyone else encountered simillar issues with the NtCreateUserProcess
and RtlCloneUserProcess
functions from this library when attempting to clone a Windows process in the x86
configuration?
Thanks for reading my post, any guidance is appreciated.