swapping dirbase and peb in clone process E/KPROC

master
_xeroxz 4 years ago
parent 89c2e85c4d
commit 78ec8745ad

@ -1,3 +1,5 @@
# pclone
# pclone (Process Cloning)
Process Cloning
pclone is small project designed to clone running processes. The cloning does not clone threads nor handles, it does however clone all virtual memory.
It does this by swapping dirbase in the clones EPROCESS structure. It also swaps the PEB in the EPROCESS structure so the clone will list the same loaded modules
as the cloned process.

@ -55,15 +55,15 @@ int __cdecl main(int argc, char** argv)
vdm.set_read(_read_phys);
vdm.set_write(_write_phys);
nasa::mem_ctx notepad_proc(vdm, std::atoi(argv[2]));
nasa::pclone_ctx clone_notepad(&notepad_proc);
const auto [clone_pid, clone_handle] = clone_notepad.clone();
nasa::mem_ctx target_proc(vdm, std::atoi(argv[2]));
nasa::pclone_ctx clone_ctx(&target_proc);
const auto [clone_pid, clone_handle] = clone_ctx.clone();
unsigned short mz = 0u;
std::size_t bytes_read;
ReadProcessMemory(clone_handle, GetModuleHandleA("ntdll.dll"), &mz, sizeof mz, &bytes_read);
std::printf("[+] handle -> 0x%x, clone pid -> 0x%x\n", clone_handle, clone_pid);
std::printf("[+] notepad mz -> 0x%x\n", mz);
std::printf("[+] ntdll mz in clone -> 0x%x\n", mz);
std::getchar();
}

@ -73,13 +73,6 @@ namespace nasa
this->new_pt.first = reinterpret_cast<ppte>(new_pt_entries.pt.second.pfn << 12);
}
mem_ctx::~mem_ctx()
{
const auto pml4 =
reinterpret_cast<ppml4e>(
set_page(dirbase))[pml4e_index] = pml4e{ NULL };
}
void* mem_ctx::set_page(void* addr)
{
// table entry change.

@ -9,8 +9,6 @@ namespace nasa
friend class pclone_ctx;
public:
mem_ctx(vdm::vdm_ctx& v_ctx, std::uint32_t pid = GetCurrentProcessId());
~mem_ctx();
std::pair<ppte, pte> get_pte(void* addr, bool use_hyperspace = false);
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);

@ -1,4 +1,4 @@
#include "pclone_ctx.hpp"
#include "pclone_ctx.hpp"
namespace nasa
{
@ -7,67 +7,67 @@ namespace nasa
clone_target_ctx(clone_ctx)
{}
pclone_ctx::~pclone_ctx()
{
delete clone_source_ctx;
}
auto pclone_ctx::clone() -> std::pair<std::uint32_t, HANDLE>
{
const auto runtime_broker_pid =
const auto runtime_broker_pid =
util::start_runtime_broker();
const auto runtime_broker_handle =
const auto runtime_broker_handle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, runtime_broker_pid);
const auto v_ctx = clone_target_ctx->v_ctx;
clone_source_ctx = new mem_ctx(
*v_ctx, runtime_broker_pid);
if (!this->sync())
return { {}, {} };
// zombie the the process by incrementing an exit counter
// then calling TerminateProcess so the process never closes...
const auto runtime_broker_peproc =
v_ctx->get_peprocess(runtime_broker_pid);
const auto runtime_broker_peproc =
reinterpret_cast<std::uintptr_t>(
v_ctx->get_peprocess(runtime_broker_pid));
static const auto inc_ref_counter =
static const auto inc_ref_counter =
util::get_kmodule_export(
"ntoskrnl.exe",
"PsAcquireProcessExitSynchronization"
);
const auto result =
v_ctx->syscall<NTSTATUS(*)(PEPROCESS)>(
const auto result =
v_ctx->syscall<NTSTATUS(*)(std::uintptr_t)>(
inc_ref_counter, runtime_broker_peproc);
TerminateProcess(runtime_broker_handle, NULL);
return { runtime_broker_pid, runtime_broker_handle };
}
if (result != STATUS_SUCCESS)
return { {}, {} };
bool pclone_ctx::sync() const
{
// do not remove...
std::printf("[+] clone target dirbase -> 0x%p\n", clone_target_ctx->get_dirbase());
const auto target_pml4 =
clone_target_ctx->set_page(
clone_target_ctx->get_dirbase());
if (!TerminateProcess(runtime_broker_handle, NULL))
return { {}, {} };
// change the _KPROCESS.DirectoryTableBase to the
// DirectoryTableBase of the process wanting to be
// cloned...
const auto clone_target_peproc =
reinterpret_cast<std::uintptr_t>(
v_ctx->get_peprocess(clone_target_ctx->get_pid()));
// do not remove...
std::printf("[+] clone source dirbase -> 0x%p\n", clone_source_ctx->get_dirbase());
const auto source_pml4 =
clone_source_ctx->set_page(
clone_source_ctx->get_dirbase());
const auto clone_target_dirbase =
v_ctx->rkm<pte>(clone_target_peproc + 0x28);
__try
{
memcpy(source_pml4, target_pml4, PAGE_4KB);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
return true;
// change dirbase of runtime broker to the dirbase of the desired process...
v_ctx->wkm<pte>(runtime_broker_peproc + 0x28, clone_target_dirbase);
// get the peb offset inside dirbase...
// .text:00000001403387B0 public PsGetProcessPeb
// .text:00000001403387B0 PsGetProcessPeb proc near;
// .text:00000001403387B0 48 8B 81 50 05 00 00 mov rax, [rcx + 550h] <==== + 3 bytes here...
// .text:00000001403387B7 C3 retn
// .text:00000001403387B7 PsGetProcessPeb endp
const auto eprocess_peb_offset =
*reinterpret_cast<std::uint32_t*>(
reinterpret_cast<std::uintptr_t>(
GetProcAddress(GetModuleHandleA(
"ntoskrnl.exe"), "PsGetProcessPeb")) + 0x3); // <==== + 3 bytes here...
const auto clone_target_peb =
v_ctx->rkm<std::uintptr_t>(
clone_target_peproc + eprocess_peb_offset);
v_ctx->wkm<std::uintptr_t>(runtime_broker_peproc + eprocess_peb_offset, clone_target_peb);
return { runtime_broker_pid, runtime_broker_handle };
}
}

@ -7,11 +7,8 @@ namespace nasa
friend class mem_ctx;
public:
explicit pclone_ctx(mem_ctx* clone_ctx);
~pclone_ctx();
auto clone() -> std::pair<std::uint32_t, HANDLE>;
bool sync() const;
private:
mem_ctx* clone_target_ctx;
mem_ctx* clone_source_ctx;
};
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Loading…
Cancel
Save