#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <dbghelp.h>
/*
HMODULE moduleHandles[1024];
DWORD cbNeeded;
if (EnumProcessModules(processHandle, moduleHandles, sizeof(moduleHandles), &cbNeeded)) {
for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
TCHAR moduleName[MAX_PATH];
if (GetModuleFileNameEx(processHandle, moduleHandles[i], moduleName, sizeof(moduleName) / sizeof(TCHAR))) {
printf("%s address: %p difference address: %td\n", moduleName, (uintptr_t)moduleHandles[i], (ptrdiff_t)event.u.Exception.ExceptionRecord.ExceptionAddress - (ptrdiff_t)moduleHandles[i]);
}
}
} else {
printf("Failed to enumerate process modules.\n");
}
*/
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PULONG RegionSize,
ULONG AllocationType,
ULONG Protect
);
//static __typeof__(NtAllocateVirtualMemory) *fnNtAllocateVirtualMemory;
//optimize(0)
#define PIC CALLBACK __attribute__((noclone,noinline,))
HMODULE RemoteAddressToModule( HANDLE hProcess , void* pAddress ) {
//context for input/output from the remote function
//must contain REMOTE PROCESS pointers to any function that will be called (kernel32/ntdll is free.)
//so for other than kernel32 is better to import LoadLibraryA / GetProcAddressA // FreeLibraryA and use there
typedef struct {
HMODULE hModuleOut;
void *pAddressIn;
__typeof__(GetModuleHandleExA) *fnGetModuleHandleExA;
} RemoteFuncContext;
//declaring functions before and after to serve as barriers, and to know the function size
//the function must not use constant strings or any other constant that would be end being in .data .rodata etc... sections
//those must reside on the context if required, so no accessing global or TLS variables
//no directly accessing any other functions except those that are forcefully inlined
void PIC RemoteFuncA() {}
BOOL PIC RemoteFuncN( RemoteFuncContext *p ) {
return p->fnGetModuleHandleExA( 0x6 , (LPCSTR)p->pAddressIn , &(p->hModuleOut) );
}
void PIC RemoteFuncZ() {}
assert( ((uintptr_t)RemoteFuncZ) > ((uintptr_t)RemoteFuncN) );
assert( ((uintptr_t)RemoteFuncN) > ((uintptr_t)RemoteFuncA) );
//RemoteFunctionN();
//printf("%p %p %p\n",RemoteFuncA,RemoteFuncN,RemoteFuncZ);
//printf("size = %i\n", ((uintptr_t)RemoteFuncZ)-((uintptr_t)RemoteFuncN));
//module handles for import kernel32 import functions
HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
//initialize context with function pointers and input parameter or constants that would not be inside code
RemoteFuncContext tCtx = {
.pAddressIn = pAddress,
.fnGetModuleHandleExA = (void*)GetProcAddress(hKernel32,"GetModuleHandleExA")
};
if (!tCtx.fnGetModuleHandleExA) { puts("failed to get import addresses"); }
//load nt function
HMODULE ntdll = GetModuleHandle("ntdll.dll");
printf("NT1 %d\n", GetLastError());
pNtAllocateVirtualMemory myNtAlloc = (pNtAllocateVirtualMemory)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
printf("NT2 %d\n", GetLastError());
//allocate memory on the remote process and copy code/data to it
int CodeSize = (((uintptr_t)RemoteFuncZ)-((uintptr_t)RemoteFuncN)) , DataSize = sizeof(tCtx);
ULONG thSize = CodeSize+DataSize;
PVOID rb = 0;
printf("NT allocated memory. StatusCode: 0x%08X\n", myNtAlloc( hProcess , &rb ,0 , &thSize , MEM_COMMIT , PAGE_EXECUTE_READWRITE));
DWORD statusNtAlloc = 0;
printf("NT3\n", GetLastError());
RemoteFuncContext *pCtx = rb;
WriteProcessMemory( hProcess , pCtx , &tCtx , DataSize , NULL );
WriteProcessMemory( hProcess , pCtx+1 , RemoteFuncN , CodeSize , NULL );
printf("Last Error after WriteProcessMemory(hProcess ,pCtx , &tCtx, DataSize, NULL): %d\n", GetLastError());
//create thread and wait for it to finish
DWORD dwTID;
HANDLE hThread = CreateRemoteThread( hProcess , NULL , 0 , (LPTHREAD_START_ROUTINE)(pCtx+1) , pCtx , 0 , &dwTID );
if (!hThread) {
puts("Failed to create remote thread");
} else {
WaitForSingleObject( hThread , INFINITE );
CloseHandle(hThread);
}
//copy back structure data (output) so it can even do a partial copy of the structure with just OUTPUT elements
ReadProcessMemory( hProcess , pCtx , &tCtx , sizeof(tCtx) , NULL );
VirtualFreeEx( hProcess , pCtx , CodeSize+DataSize , MEM_RELEASE );
//done
return tCtx.hModuleOut;
}
// Exception handler function
void checkBits(DWORD pid) {
/* check the bits of the process */
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProcess == NULL) {
printf("Error: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid) failed with error code %d\n", GetLastError());
return;
}
BOOL isWow64 = FALSE;
if (!IsWow64Process(hProcess, &isWow64)) {
printf("Error: !IsWow64Process(hProcess, &isWow64) failed with error code %d\n", GetLastError());
CloseHandle(hProcess);
return;
}
if (isWow64) {
printf("Process %d is running as a 32-bit process on a 64-bit system.\n", pid);
} else {
printf("Process %d is running as a 64-bit process.\n", pid);
}
CloseHandle(hProcess);
}
// Main function
int main(int argc, char *argv[]) {
// Check if target process ID was provided as argument
if (argc < 2) {
printf("Usage: %s <Process ID>\n", argv[0]);
return 1;
}
// Convert target process ID from string to integer
DWORD processId = atoi(argv[1]);
checkBits(processId);
// Attach to target process
if (!DebugActiveProcess(processId)) {
printf("Error attaching to process (error code %d)\n", GetLastError());
return 1;
}
// Loop indefinitel
DEBUG_EVENT event;
while (WaitForDebugEvent(&event, INFINITE)) {
switch (event.dwDebugEventCode) {
case EXCEPTION_DEBUG_EVENT:
printf("Exception occurred with code 0x%08X at address 0x%p ", event.u.Exception.ExceptionRecord.ExceptionCode, event.u.Exception.ExceptionRecord.ExceptionAddress);
HMODULE moduleToTheAddress;
if (!GetModuleHandleEx(0x00000004, (LPCSTR)event.u.Exception.ExceptionRecord.ExceptionAddress, &moduleToTheAddress)) {
printf("Error GetModuleHandleEx(0x00000004, ptr, &moduleToTheAddress) (error code %d)\n", GetLastError());
/* Enumerating Modules Loaded */
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (processHandle == NULL) {
printf("Failed to open process handle.\n");
return 0;
}
HMODULE moduleTaken = RemoteAddressToModule( processHandle, (void*) event.u.Exception.ExceptionRecord.ExceptionAddress );
char moduleName[MAX_PATH];
GetModuleFileNameEx(processHandle, moduleTaken, moduleName, MAX_PATH);
printf(" Module Name: %s", moduleName);
CloseHandle(processHandle);
}else{
char moduleName[MAX_PATH];
GetModuleFileName(moduleToTheAddress, moduleName, MAX_PATH);
printf(" Module Name: %s", moduleName);
/* Enumerating Modules Loaded */
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (processHandle == NULL) {
printf("Failed to open process handle.\n");
return 0;
}
HMODULE moduleTaken = RemoteAddressToModule( processHandle, (void*) event.u.Exception.ExceptionRecord.ExceptionAddress );
char moduleName2[MAX_PATH];
GetModuleFileNameEx(processHandle, moduleTaken, moduleName2, MAX_PATH);
printf(" Module Name: %s", moduleName2);
CloseHandle(processHandle);
}
printf("\n");
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
break;
default:
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
break;
}
}
// Detach from target process
DebugActiveProcessStop(processId);
return 0;
}