Base Process class, to be expanded
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
build
|
build
|
||||||
.clangd
|
.clangd
|
||||||
.zed
|
.zed
|
||||||
|
.cache
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
add_library(xrbx STATIC
|
add_library(xrbx STATIC
|
||||||
src/xrbx.cpp
|
src/xrbx.cpp
|
||||||
|
src/process.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(xrbx
|
target_include_directories(xrbx
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "ntproc.h"
|
||||||
|
|
||||||
|
namespace Nt {
|
||||||
|
inline HMODULE ntdll() {
|
||||||
|
static HMODULE mod = LoadLibraryA("ntdll.dll");
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T resolve(const char *name) {
|
||||||
|
static T fn = reinterpret_cast<T>(GetProcAddress(ntdll(), name));
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
|
||||||
|
namespace Nt {
|
||||||
|
typedef NTSTATUS(NTAPI* OpenProcess)(
|
||||||
|
PHANDLE ProcessHandle,
|
||||||
|
ACCESS_MASK DesiredAccess,
|
||||||
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
CLIENT_ID *ClientId
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI* DuplicateObject)(
|
||||||
|
HANDLE SourceProcessHandle,
|
||||||
|
HANDLE SourceHandle,
|
||||||
|
HANDLE TargetProcessHandle,
|
||||||
|
PHANDLE TargetHandle,
|
||||||
|
ACCESS_MASK DesiredAccess,
|
||||||
|
ULONG HandleAttributes,
|
||||||
|
ULONG Options
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI *Close)(
|
||||||
|
HANDLE Handle
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI *QuerySystemInformation)(
|
||||||
|
SYSTEM_INFORMATION_CLASS,
|
||||||
|
PVOID,
|
||||||
|
ULONG,
|
||||||
|
PULONG
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI *QueryInformationProcess)(
|
||||||
|
HANDLE,
|
||||||
|
PROCESSINFOCLASS,
|
||||||
|
PVOID,
|
||||||
|
ULONG,
|
||||||
|
PULONG
|
||||||
|
);
|
||||||
|
|
||||||
|
struct PROCESS_BASIC_INFORMATION {
|
||||||
|
NTSTATUS ExitStatus;
|
||||||
|
PPEB PebBaseAddress;
|
||||||
|
ULONG_PTR AffinityMask;
|
||||||
|
LONG BasePriority;
|
||||||
|
ULONG_PTR UniqueProcessId;
|
||||||
|
ULONG_PTR InheritedFromUniqueProcessId;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI *ReadVirtualMemory)(
|
||||||
|
HANDLE,
|
||||||
|
PVOID,
|
||||||
|
PVOID,
|
||||||
|
SIZE_T,
|
||||||
|
PSIZE_T
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct _PEB_PARTIAL
|
||||||
|
{
|
||||||
|
BYTE Reserved1[4];
|
||||||
|
PVOID Mutant;
|
||||||
|
PVOID ImageBaseAddress;
|
||||||
|
} PEB_PARTIAL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <winnt.h>
|
||||||
|
|
||||||
|
#include "nt/nt.h"
|
||||||
|
#include "xrbx/nt/ntproc.h"
|
||||||
|
|
||||||
|
class Process {
|
||||||
|
private:
|
||||||
|
DWORD pid;
|
||||||
|
HANDLE proc;
|
||||||
|
BYTE *base;
|
||||||
|
|
||||||
|
HANDLE openProcess();
|
||||||
|
BYTE *getImageBase(void);
|
||||||
|
public:
|
||||||
|
static DWORD findProcessByName(const std::wstring &name);
|
||||||
|
|
||||||
|
inline BYTE *imageBase(void) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T Read(BYTE *addr) {
|
||||||
|
T buf;
|
||||||
|
SIZE_T bytesRead;
|
||||||
|
NTSTATUS status = Nt::resolve<Nt::ReadVirtualMemory>("NtReadVirtualMemory")(proc, addr, &buf, sizeof(buf), &bytesRead);
|
||||||
|
if (status < 0) {
|
||||||
|
throw std::runtime_error(std::format("Failed to read {} bytes from {:X}", sizeof(buf), uintptr_t(addr)));
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Process(const std::wstring &name) {
|
||||||
|
pid = findProcessByName(name);
|
||||||
|
if (pid == 0) {
|
||||||
|
throw std::runtime_error("Process not found");
|
||||||
|
}
|
||||||
|
proc = openProcess();
|
||||||
|
base = getImageBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Process() {
|
||||||
|
Nt::resolve<Nt::Close>("NtClose")(proc);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
void helloWorld(void);
|
void helloWorld(void);
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include "xrbx/process.h"
|
||||||
|
|
||||||
|
HANDLE Process::openProcess() {
|
||||||
|
if (pid == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT_ID cid{};
|
||||||
|
cid.UniqueProcess = (HANDLE)pid;
|
||||||
|
cid.UniqueThread = nullptr;
|
||||||
|
|
||||||
|
OBJECT_ATTRIBUTES oa{};
|
||||||
|
oa.Length = sizeof oa;
|
||||||
|
|
||||||
|
HANDLE proc;
|
||||||
|
|
||||||
|
if(Nt::resolve<Nt::OpenProcess>("NtOpenProcess")(&proc, PROCESS_ALL_ACCESS, &oa, &cid) < 0) {
|
||||||
|
throw std::runtime_error("Failed to open process");
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE duplicate;
|
||||||
|
if(Nt::resolve<Nt::DuplicateObject>("NtDuplicateObject")(GetCurrentProcess(), proc, GetCurrentProcess(), &duplicate, PROCESS_ALL_ACCESS, 0, 0) < 0) {
|
||||||
|
Nt::resolve<Nt::Close>("NtClose")(proc);
|
||||||
|
throw std::runtime_error("Failed to duplicate process");
|
||||||
|
}
|
||||||
|
Nt::resolve<Nt::Close>("NtClose")(proc);
|
||||||
|
|
||||||
|
return duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE *Process::getImageBase(void) {
|
||||||
|
Nt::PROCESS_BASIC_INFORMATION pbi{};
|
||||||
|
|
||||||
|
if (Nt::resolve<Nt::QueryInformationProcess>("NtQueryInformationProcess")(proc, ProcessBasicInformation, &pbi, sizeof(pbi), nullptr) < 0) {
|
||||||
|
throw std::runtime_error("Failed to get process information");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (BYTE *)Read<Nt::PEB_PARTIAL>((BYTE *)pbi.PebBaseAddress).ImageBaseAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD Process::findProcessByName(const std::wstring &name) {
|
||||||
|
auto NtQuerySystemInformation = Nt::resolve<Nt::QuerySystemInformation>("NtQuerySystemInformation");
|
||||||
|
|
||||||
|
ULONG size = 0;
|
||||||
|
NtQuerySystemInformation(SystemProcessInformation, nullptr, 0, &size);
|
||||||
|
|
||||||
|
std::vector<BYTE> buffer(size);
|
||||||
|
NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, buffer.data(), size, &size);
|
||||||
|
if (status < 0) return 0;
|
||||||
|
|
||||||
|
auto entry = reinterpret_cast<PSYSTEM_PROCESS_INFORMATION>(buffer.data());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (entry->ImageName.Buffer) {
|
||||||
|
if (_wcsicmp(entry->ImageName.Buffer, name.c_str()) == 0) {
|
||||||
|
return DWORD(ULONG_PTR(entry->UniqueProcessId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->NextEntryOffset == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
entry = reinterpret_cast<PSYSTEM_PROCESS_INFORMATION>(
|
||||||
|
reinterpret_cast<BYTE*>(entry)
|
||||||
|
+ entry->NextEntryOffset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+4
-1
@@ -1,6 +1,9 @@
|
|||||||
#include "xrbx/xrbx.h"
|
#include "xrbx/xrbx.h"
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
helloWorld();
|
Process rbx(L"notepad.exe");
|
||||||
|
std::cout << std::format("Image Base: {:X}", uintptr_t(rbx.imageBase())) << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user