From 125d8014ef5abfd6be84ea05be8f8ead1fd310c6 Mon Sep 17 00:00:00 2001 From: toneillcodes Date: Thu, 21 May 2026 23:00:32 -0400 Subject: [PATCH] Adding module stomping resources and information --- includes/peb-eat-utils.cpp | 3 + includes/peb-eat-utils.h | 17 ++ includes/ps-utils.cpp | 24 +++ includes/ps-utils.h | 1 + module-stomping/README.md | 259 ++++++++++++++++++++++---- module-stomping/list-process-dlls.cpp | 156 ++++++++++++++++ 6 files changed, 426 insertions(+), 34 deletions(-) create mode 100644 module-stomping/list-process-dlls.cpp diff --git a/includes/peb-eat-utils.cpp b/includes/peb-eat-utils.cpp index 68ba992..15507f4 100644 --- a/includes/peb-eat-utils.cpp +++ b/includes/peb-eat-utils.cpp @@ -1,6 +1,9 @@ #include "peb-eat-utils.h" #include "utils.h" +// Ensure NTSTATUS success is defined +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) + // obtain the local process TEB void* GetLocalTebAddress(void) { #ifdef _WIN64 diff --git a/includes/peb-eat-utils.h b/includes/peb-eat-utils.h index 4d51259..f3ec35a 100644 --- a/includes/peb-eat-utils.h +++ b/includes/peb-eat-utils.h @@ -12,6 +12,23 @@ #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif +// 1. 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; // This is what we use to offset math! + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; // Now visible! + ULONG Flags; + WORD ObsoleteLoadCount; + WORD TlsIndex; + LIST_ENTRY HashLinks; + ULONG TimeDateStamp; +} FULL_LDR_DATA_TABLE_ENTRY, *PFULL_LDR_DATA_TABLE_ENTRY; + // Returns the TEB address for the current thread void* GetLocalTebAddress(void); diff --git a/includes/ps-utils.cpp b/includes/ps-utils.cpp index 8c1f7ae..eafe13d 100644 --- a/includes/ps-utils.cpp +++ b/includes/ps-utils.cpp @@ -25,4 +25,28 @@ extern "C" DWORD FindPidByName(const wchar_t* processName) { CloseHandle(snapshot); } return pid; +} + +HANDLE GetProcessHandle(DWORD targetPID) { + // Request ONLY the minimum permissions needed for the job: + // 1. PROCESS_QUERY_INFORMATION - needed for NtQueryInformationProcess (PEB location) + // 2. PROCESS_VM_READ - needed for ReadProcessMemory (reading the DLL list) + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, targetPID); + + if (hProcess == NULL) { + DWORD error = GetLastError(); + //printf("[-] OpenProcess failed! Error code: %lu\n", error); + + // Quick troubleshooting tips based on common error codes: + if (error == ERROR_ACCESS_DENIED) { + //printf("[!] Hint: Access Denied. Try running your tool as Administrator,\n"); + //printf(" or check if you are targeting a protected system process (like lsass.exe).\n"); + } else if (error == ERROR_INVALID_PARAMETER) { + //printf("[!] Hint: Invalid Parameter. Double-check that the PID actually exists.\n"); + } + return NULL; + } + + //printf("[+] Successfully obtained handle for PID %lu\n", targetPID); + return hProcess; } \ No newline at end of file diff --git a/includes/ps-utils.h b/includes/ps-utils.h index 2147baa..663952f 100644 --- a/includes/ps-utils.h +++ b/includes/ps-utils.h @@ -6,6 +6,7 @@ extern "C" { #endif DWORD FindPidByName(const wchar_t* processName); +HANDLE GetProcessHandle(DWORD pid); #ifdef __cplusplus } diff --git a/module-stomping/README.md b/module-stomping/README.md index 7c0ca32..8945ec6 100644 --- a/module-stomping/README.md +++ b/module-stomping/README.md @@ -9,45 +9,236 @@ Module Stomping is a process injection technique where a legitimate, image-backe | **Tactical Goal** | **Evade Memory Scanners:** Bypasses detections that flag `RX` memory regions not backed by a file on disk (`MEM_PRIVATE`). | | **Stealth** | **Moderate.** While it solves the "unbacked memory" problem, it introduces another IoC "Module Mismatch" (the memory content no longer matches the file on disk). | -## DLL Scanner -[find-stompable-dlls.py](find-stompable-dlls.py) +## DLL Discovery +Identify a target process and the process ID. ``` -PS C:\Users\Administrator\Desktop\Tools > python .\find-stompable-dlls.py 0x80000 +c:\Users\Administrator\Desktop\module-stomping>tasklist /fi "imageName eq rufus.exe" + +Image Name PID Session Name Session# Mem Usage +========================= ======== ================ =========== ============ +rufus.exe 1988 RDP-Tcp#0 2 27,636 K + +c:\Users\Administrator\Desktop\module-stomping> +``` +Output the list of modules loaded by the target process +``` +c:\Users\Administrator\Desktop\module-stomping>.\list-process-dlls.exe -p 1988 +[+] Successfully obtained handle for PID 1988 +[+] Enumerating loaded modules: +-------------------------------------------------- +[0x00007FF7F8A30000] rufus.exe +[0x00007FFFFC060000] ntdll.dll +[0x00007FFFFA990000] KERNEL32.DLL +[0x00007FFFF97E0000] KERNELBASE.dll +[0x00007FFFF6CA0000] apphelp.dll +[0x00007FFFFAB60000] USER32.dll +[0x00007FFFF96F0000] win32u.dll +[0x00007FFFFB5C0000] GDI32.dll +[0x00007FFFF9300000] gdi32full.dll +[0x00007FFFF9430000] msvcp_win.dll +[0x00007FFFF91B0000] ucrtbase.dll +[0x00007FFFF9E10000] IMM32.DLL +[0x00007FFFFB3A0000] ADVAPI32.dll +[0x00007FFFFA2E0000] msvcrt.dll +[0x00007FFFFAF60000] sechost.dll +[0x00007FFFFA7E0000] RPCRT4.dll +[0x00007FFFF8200000] SspiCli.dll +[0x00007FFFFB6F0000] SHELL32.dll +[0x00007FFFF9BE0000] wintypes.dll +[0x00007FFFFB010000] combase.dll +[0x00007FFFF07D0000] windows.storage.dll +[0x00007FFFFB4B0000] SHCORE.dll +[0x00007FFFFAD30000] shlwapi.dll +[0x00007FFFF90D0000] profapi.dll +[0x00007FFFF9570000] CRYPT32.dll +[0x00007FFFF94E0000] WINTRUST.DLL +[0x00007FFFF8800000] MSASN1.dll +[0x00007FFFFA7A0000] imagehlp.dll +[0x00007FFFFA410000] ole32.dll +[0x00007FFFF75D0000] kernel.appcore.dll +[0x00007FFFF9D50000] bcryptPrimitives.dll +[0x00007FFFF6EA0000] uxtheme.dll +[0x00007FFFFADA0000] clbcatq.dll +[0x00007FFFE1890000] vds_ps.dll +[0x00007FFFF8870000] Wldp.DLL +[0x00007FFFD7D10000] Riched20.DLL +[0x00007FFFE5080000] USP10.dll +[0x00007FFFD9880000] msls31.dll +[0x00007FFFEB580000] VERSION.dll +[0x00007FFFFBEB0000] MSCTF.dll +[0x00007FFFEB020000] comctl32.dll +[0x00007FFFF7130000] dwmapi.dll +[0x00007FFFFAE60000] OLEAUT32.dll +[0x00007FFFEEAB0000] textinputframework.dll +[0x00007FFFF53E0000] WindowsCodecs.dll +[0x00007FFFEE460000] IconCodecService.dll +[0x00007FFFD93E0000] oleacc.dll +[0x00007FFFEF500000] TextShaping.dll +[0x00007FFFD9120000] explorerframe.dll +[0x00007FFFFAA60000] ComDlg32.DLL +[0x00007FFFF68A0000] CoreMessaging.dll +[0x00007FFFF3DD0000] CoreUIComponents.dll +[0x00007FFFF8790000] CRYPTBASE.DLL +[0x00007FFFF9E50000] SETUPAPI.dll +[0x00007FFFF8D50000] DEVOBJ.dll +[0x00007FFFF8CF0000] cfgmgr32.dll + +c:\Users\Administrator\Desktop\module-stomping> +``` +Save the list of module names to a file named `rufus-modules-loaded.txt` +``` +c:\Users\Administrator\Desktop\module-stomping>.\list-process-dlls.exe -p 1988 -n -o rufus-modules-loaded.txt +[+] Successfully obtained handle for PID 1988 +[+] Output will also be dumped to: rufus-modules-loaded.txt +[+] Enumerating loaded modules: +-------------------------------------------------- +rufus.exe +ntdll.dll +KERNEL32.DLL +KERNELBASE.dll +apphelp.dll +USER32.dll +win32u.dll +GDI32.dll +gdi32full.dll +msvcp_win.dll +ucrtbase.dll +IMM32.DLL +ADVAPI32.dll +msvcrt.dll +sechost.dll +RPCRT4.dll +SspiCli.dll +SHELL32.dll +wintypes.dll +combase.dll +windows.storage.dll +SHCORE.dll +shlwapi.dll +profapi.dll +CRYPT32.dll +WINTRUST.DLL +MSASN1.dll +imagehlp.dll +ole32.dll +kernel.appcore.dll +bcryptPrimitives.dll +uxtheme.dll +clbcatq.dll +vds_ps.dll +Wldp.DLL +Riched20.DLL +USP10.dll +msls31.dll +VERSION.dll +MSCTF.dll +comctl32.dll +dwmapi.dll +OLEAUT32.dll +textinputframework.dll +WindowsCodecs.dll +IconCodecService.dll +oleacc.dll +TextShaping.dll +explorerframe.dll +ComDlg32.DLL +CoreMessaging.dll +CoreUIComponents.dll +CRYPTBASE.DLL +SETUPAPI.dll +DEVOBJ.dll +cfgmgr32.dll + +c:\Users\Administrator\Desktop\module-stomping> +``` + +[find-stompable-dlls.py](find-stompable-dlls.py) + +Locate qualifying modules that are already loaded using the `includes` list +``` +c:\Users\Administrator\Desktop\module-stomping>python find-stompable-dlls.py 0x80000 -i rufus-modules-loaded.txt +[*] Loading INCLUDE_MODULES from: 'rufus-modules-loaded.txt' +[+] Loaded 56 modules into INCLUDE_MODULES filter. [*] Scanning Target Directory: 'C:\Windows\System32' [*] Filtering for Files : > 1.0MB [*] Required .text Space : 0x80000 bytes ------------------------------------------------------------------------------------------- -DLL Name | File Size (MB) | Size of .text | Virtual Address ------------------------------------------------------------------------------------------- -aadtb.dll | 1.48 | 0xff60c | 0x1000 -ActiveSyncProvider.dll | 1.73 | 0x14abe2 | 0x1000 -aeinv.dll | 1.60 | 0x13495a | 0x1000 -aemarebackup.dll | 1.23 | 0xf8a64 | 0x1000 -aepic.dll | 1.25 | 0xf2afa | 0x1000 -APMon.dll | 1.57 | 0xe395c | 0x1000 -appraiser.dll | 3.18 | 0x26b133 | 0x1000 -AppVEntSubsystemController.dll | 1.22 | 0xc941c | 0x1000 -AppVEntSubsystems64.dll | 1.63 | 0x10565c | 0x1000 -AppVEntVirtualization.dll | 1.56 | 0x108d1c | 0x1000 -AppVIntegration.dll | 1.37 | 0xd648c | 0x1000 -AppXDeploymentClient.dll | 1.45 | 0xe89d0 | 0x1000 -AppXDeploymentExtensions.desktop.dll | 2.68 | 0x1ab07c | 0x1000 -AppXDeploymentExtensions.onecore.dll | 3.44 | 0x23493c | 0x1000 +[*] Targeted Include Filter : Active (56 specific targets allowed) +-------------------------------------------------------------------------------------------------------------------------------------------- +Full File Path | File Size (MB) | Size of .text | Virtual Address +-------------------------------------------------------------------------------------------------------------------------------------------- +C:\Windows\System32\combase.dll | 3.54 | 0x269ca2 | 0x1000 +C:\Windows\System32\CoreMessaging.dll | 1.17 | 0xd1175 | 0x1000 +C:\Windows\System32\CoreUIComponents.dll | 2.89 | 0x19bf50 | 0x1000 +C:\Windows\System32\crypt32.dll | 1.46 | 0x124e7b | 0x1000 +C:\Windows\System32\ExplorerFrame.dll | 2.73 | 0x21677c | 0x1000 +C:\Windows\System32\gdi32full.dll | 1.18 | 0xb32bc | 0x1000 +C:\Windows\System32\KernelBase.dll | 3.94 | 0x1a392f | 0x1000 +C:\Windows\System32\msctf.dll | 1.38 | 0x114f70 | 0x1000 +C:\Windows\System32\ntdll.dll | 2.41 | 0x16ae9c | 0x1000 +C:\Windows\System32\ole32.dll | 1.61 | 0xd5c4c | 0x1000 +C:\Windows\System32\rpcrt4.dll | 1.11 | 0xd3e99 | 0x1000 +C:\Windows\System32\setupapi.dll | 4.58 | 0xebc1e | 0x1000 +C:\Windows\System32\shell32.dll | 7.37 | 0x5aa034 | 0x1000 +C:\Windows\System32\TextInputFramework.dll | 1.30 | 0xf8d0c | 0x1000 +C:\Windows\System32\ucrtbase.dll | 1.31 | 0xf5f61 | 0x1000 +C:\Windows\System32\user32.dll | 1.79 | 0xa7fee | 0x1000 +C:\Windows\System32\windows.storage.dll | 8.43 | 0x64cc4e | 0x1000 +C:\Windows\System32\WindowsCodecs.dll | 2.21 | 0x1a226c | 0x1000 +C:\Windows\System32\WinTypes.dll | 1.43 | 0xa1318 | 0x1000 +C:\Windows\System32\downlevel\ucrtbase.dll | 1.31 | 0xf559c | 0x1000 +-------------------------------------------------------------------------------------------------------------------------------------------- +[*] Found 20 potential candidates matching the criteria. + +c:\Users\Administrator\Desktop\module-stomping> +``` +Locate qualifying modules that are NOT already loaded using the `excludes` list +``` +c:\Users\Administrator\Desktop\module-stomping>python find-stompable-dlls.py 0x80000 -x rufus-modules-loaded.txt +[*] Loading EXCLUDE_MODULES from: 'rufus-modules-loaded.txt' +[+] Loaded 56 modules into EXCLUDE_MODULES filter. +[*] Scanning Target Directory: 'C:\Windows\System32' +[*] Filtering for Files : > 1.0MB +[*] Required .text Space : 0x80000 bytes +[*] Exclusion Filter : Active (56 modules blacklisted) +-------------------------------------------------------------------------------------------------------------------------------------------- +Full File Path | File Size (MB) | Size of .text | Virtual Address +-------------------------------------------------------------------------------------------------------------------------------------------- +C:\Windows\System32\aadtb.dll | 1.48 | 0xff60c | 0x1000 +C:\Windows\System32\ActiveSyncProvider.dll | 1.73 | 0x14abe2 | 0x1000 +C:\Windows\System32\aeinv.dll | 1.60 | 0x13495a | 0x1000 +C:\Windows\System32\aemarebackup.dll | 1.23 | 0xf8a64 | 0x1000 +C:\Windows\System32\aepic.dll | 1.25 | 0xf2afa | 0x1000 +C:\Windows\System32\APMon.dll | 1.57 | 0xe395c | 0x1000 +C:\Windows\System32\appraiser.dll | 3.18 | 0x26b133 | 0x1000 +C:\Windows\System32\AppVEntSubsystemController.dll | 1.22 | 0xc941c | 0x1000 ... -PrintConfig.dll | 3.66 | 0x1c497c | 0x1000 -PS5UI.DLL | 1.19 | 0xa993c | 0x1000 -UNIDRVUI.DLL | 1.27 | 0xb840c | 0x1000 -cimwin32.dll | 1.75 | 0x12f3dc | 0x1000 -DMWmiBridgeProv.dll | 3.75 | 0x244a1c | 0x1000 -Microsoft.Uev.AgentWmi.dll | 1.09 | 0xc3d6c | 0x1000 -NetPeerDistCim.dll | 1.39 | 0xffe3a | 0x1000 -wbemcore.dll | 1.77 | 0xee98c | 0x1000 -Microsoft.Windows.Appx.PackageManager.Commands.Core.dll | 2.68 | 0x2acd98 | 0x2000 -AuthFWSnapIn.Resources.dll | 2.98 | 0x2f9674 | 0x2000 -Microsoft.Windows.ServerManager.Plugins.Ipam.resources.dll | 2.72 | 0x2b6d04 | 0x2000 ------------------------------------------------------------------------------------------- -[*] Found 433 potential candidates. -PS C:\Users\Administrator\Desktop\Tools > +C:\Windows\System32\ru\Microsoft.Windows.ServerManager.Plugins.Ipam.resources.dll | 2.84 | 0x2d6354 | 0x2000 +C:\Windows\System32\SecurityHealth\10.0.29429.1000-0\SecurityHealthAgent.dll | 1.36 | 0xb748c | 0x1000 +C:\Windows\System32\SecurityHealth\10.0.29429.1000-0\SecurityHealthCore.dll | 1.31 | 0xeb64c | 0x1000 +C:\Windows\System32\ShellExperiences\WindowsInternal.Xaml.Controls.Tabs.dll | 1.68 | 0x14766c | 0x1000 +C:\Windows\System32\Speech\Common\sapi.dll | 1.45 | 0xdcaab | 0x1000 +C:\Windows\System32\Speech\SpeechUX\SpeechUX.dll | 1.46 | 0x8f343 | 0x1000 +C:\Windows\System32\Speech_OneCore\Common\sapi_onecore.dll | 4.26 | 0x2aad27 | 0x1000 +C:\Windows\System32\Speech_OneCore\Common\Windows.Speech.Shell.dll | 1.03 | 0xc2818 | 0x1000 +C:\Windows\System32\Speech_OneCore\Engines\SR\spsreng_onecore.dll | 1.41 | 0x10ae0b | 0x1000 +C:\Windows\System32\Speech_OneCore\Engines\TTS\MSTTSEngine_OneCore.dll | 1.87 | 0x16bb0c | 0x1000 +C:\Windows\System32\spool\drivers\W32X86\3\mxdwdrv.dll | 1.12 | 0x10e418 | 0x1000 +C:\Windows\System32\spool\drivers\W32X86\3\PrintConfig.dll | 3.12 | 0x1da306 | 0x1000 +C:\Windows\System32\spool\drivers\x64\3\PrintConfig.dll | 3.66 | 0x1c497c | 0x1000 +C:\Windows\System32\spool\drivers\x64\3\PS5UI.DLL | 1.19 | 0xa993c | 0x1000 +C:\Windows\System32\spool\drivers\x64\3\UNIDRVUI.DLL | 1.27 | 0xb840c | 0x1000 +C:\Windows\System32\wbem\cimwin32.dll | 1.75 | 0x12f3dc | 0x1000 +C:\Windows\System32\wbem\DMWmiBridgeProv.dll | 3.75 | 0x244a1c | 0x1000 +C:\Windows\System32\wbem\Microsoft.Uev.AgentWmi.dll | 1.09 | 0xc3d6c | 0x1000 +C:\Windows\System32\wbem\NetPeerDistCim.dll | 1.39 | 0xffe3a | 0x1000 +C:\Windows\System32\wbem\wbemcore.dll | 1.77 | 0xee98c | 0x1000 +C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Appx\Microsoft.Windows.Appx.PackageManager.Commands.Core.dll | 2.68 | 0x2acd98 | 0x2000 +C:\Windows\System32\zh-HANS\AuthFWSnapIn.Resources.dll | 2.98 | 0x2f9674 | 0x2000 +C:\Windows\System32\zh-HANS\Microsoft.Windows.ServerManager.Plugins.Ipam.resources.dll | 2.72 | 0x2b6d04 | 0x2000 +-------------------------------------------------------------------------------------------------------------------------------------------- +[*] Found 411 potential candidates matching the criteria. + +c:\Users\Administrator\Desktop\module-stomping> ``` ## Execution Steps diff --git a/module-stomping/list-process-dlls.cpp b/module-stomping/list-process-dlls.cpp new file mode 100644 index 0000000..6b6d897 --- /dev/null +++ b/module-stomping/list-process-dlls.cpp @@ -0,0 +1,156 @@ +#include + +#include "..\includes\peb-eat-utils.h" +#include "..\includes\ps-utils.h" + +void InventoryRemoteDlls(HANDLE hProcess, bool namesOnly, const char* outputFilePath) { + PVOID remotePebAddr = GetRemotePebAddress(hProcess); + if (!remotePebAddr) { + printf("[-] Failed to locate remote PEB.\n"); + return; + } + + PEB localPeb; + if (!ReadProcessMemory(hProcess, remotePebAddr, &localPeb, sizeof(PEB), NULL)) { + printf("[-] Failed to read remote PEB structure. Error: %lu\n", GetLastError()); + return; + } + + PEB_LDR_DATA localLdr; + if (!ReadProcessMemory(hProcess, localPeb.Ldr, &localLdr, sizeof(PEB_LDR_DATA), NULL)) { + printf("[-] Failed to read remote LDR data.\n"); + return; + } + + // 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 { + printf("[+] Output will also be dumped to: %s\n", outputFilePath); + } + } + + LIST_ENTRY* headRemoteLink = &((PPEB_LDR_DATA)localPeb.Ldr)->InMemoryOrderModuleList; + LIST_ENTRY currentLink = localLdr.InMemoryOrderModuleList; + + 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 localEntry; + if (!ReadProcessMemory(hProcess, (LPCVOID)remoteEntryAddr, &localEntry, sizeof(FULL_LDR_DATA_TABLE_ENTRY), NULL)) { + printf("[-] Failed to read a module entry from the list.\n"); + break; + } + + USHORT nameLen = localEntry.BaseDllName.Length; + WCHAR* localBuffer = (WCHAR*)malloc(nameLen + sizeof(WCHAR)); + + if (localBuffer) { + ZeroMemory(localBuffer, nameLen + sizeof(WCHAR)); + + if (ReadProcessMemory(hProcess, localEntry.BaseDllName.Buffer, localBuffer, nameLen, NULL)) { + + // Formulate the line based on the user's formatting preference + if (namesOnly) { + // Raw string only + printf("%ws\n", localBuffer); + if (outputFile) { + fprintf(outputFile, "%ws\n", localBuffer); + } + } else { + // Standard Base Address + String + printf("[0x%p] %ws\n", localEntry.DllBase, localBuffer); + if (outputFile) { + fprintf(outputFile, "[0x%p] %ws\n", localEntry.DllBase, localBuffer); + } + } + } + free(localBuffer); + } + + currentLink = localEntry.InMemoryOrderLinks; + } + + // Wrap up file handles if open + if (outputFile) { + fclose(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 Dump the inventory out to a text file\n"); + printf(" -h, --help Show this help screen\n"); +} + +// command line args: output names only, output to a file? +int main(int argc, char *argv[]) { + bool namesOnly = false; + const char* outputFilePath = NULL; + DWORD targetPid; + + // Loop through command line parameters + 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 (i + 1 < argc) { + targetPid = atoi(argv[i + 1]); + i++; // Skip next argument since we consumed it here + } else { + printf("[-] Error: -p/--pid requires a target process ID.\n"); + PrintUsage(argv[0]); + return 1; + } + } + else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--names-only") == 0) { + namesOnly = 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 + } 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]); + return 1; + } + } + + // Locate target and execute + + if (targetPid == 0) { + printf("[-] Could not find target process execution context.\n"); + return 1; + } + + HANDLE pHandle = GetProcessHandle(targetPid); + if (!pHandle) { + printf("[-] Failed to open handle to target process.\n"); + return 1; + } + + InventoryRemoteDlls(pHandle, namesOnly, outputFilePath); + + CloseHandle(pHandle); + return 0; +} \ No newline at end of file