Skip to content

Commit 49047fe

Browse files
feat: add all flag
1 parent f47db28 commit 49047fe

1 file changed

Lines changed: 273 additions & 1 deletion

File tree

main.cpp

Lines changed: 273 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ std::unordered_map<int, std::string> errorHints = {
186186

187187
struct Statuses {
188188
bool verbose;
189+
bool all;
189190
// will probably add more later
190191
};
191192

@@ -1750,6 +1751,8 @@ void FindProcessPorts(DWORD targetPid) {
17501751

17511752

17521753
void PIDinspect(const std::vector<DWORD>& pids, const std::vector<std::string>& names, HANDLE hshot, Statuses stats, int related ) {
1754+
if (!stats.all) {
1755+
17531756
//^^^ ooh guys look i'm in the void
17541757
DWORD pid = pids[0];
17551758
std::unordered_map<DWORD, PROCESSENTRY32> pidMap;
@@ -2013,6 +2016,270 @@ std::string FRAM = ""; // fram means formatted ram, i'm so creative at var namin
20132016

20142017
CloseHandle(hProcess);
20152018

2019+
} else {
2020+
DWORD pid = pids[0];
2021+
std::unordered_map<DWORD, PROCESSENTRY32> pidMap;
2022+
PROCESSENTRY32 pe32{};
2023+
pe32.dwSize = sizeof(PROCESSENTRY32);
2024+
if (Process32First(hshot, &pe32)) {
2025+
do {
2026+
pidMap.emplace(pe32.th32ProcessID, pe32);
2027+
} while (Process32Next(hshot, &pe32));
2028+
}
2029+
std::string procName = GetProcessNameFromPid(pid, hshot);
2030+
if (virtualTerminalEnabled) {
2031+
if (procName == ""){
2032+
std::cout << "\033[34mTarget:\033[0m N/A\n\033[34mProcess:\033[0m N/A\n";
2033+
} else {
2034+
std::cout << "\033[34mTarget:\033[0m " << procName << "\033[0m" << std::endl;
2035+
std::cout << "\033[34mProcess:\033[0m " << procName << "\033[90m (pid " << std::to_string(pid) << ")\033[0m" << std::endl;
2036+
}
2037+
} else {
2038+
if (procName == ""){
2039+
std::cout << "Target: N/A\nProcess: N/A\n";
2040+
} else {
2041+
std::cout << "Target: " << procName << std::endl;
2042+
std::cout << "Process: " << procName << " (pid " << std::to_string(pid) << ")" << std::endl;
2043+
}
2044+
}
2045+
2046+
2047+
2048+
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
2049+
// The above little handle opener is currently a somwehat "agressive" flag, since it
2050+
// Requests read access directly to the process' actual memory. This can get us rejected if called
2051+
// on a very high privilege process, such as lsass.exe This means that we can't read the memory
2052+
// even WITH SeDebugPrivilege enabled. Windows doesn't want ya sneaking around in that!
2053+
// So for that reason, I've added a fallback that only requests limited memory access,
2054+
// which should hopefully allow us to read some informatoin about hte process
2055+
if (!hProcess && GetLastError() == ERROR_ACCESS_DENIED) {
2056+
// This lets us know if the error was denied specifically for access reasons. THis will initiate our little fallback.
2057+
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); // poor little guy getting limited of his full power
2058+
// This has been tested and it does let us get info about lsass.exe and even System! Woohoo!
2059+
// But of course, you need to be running as admin for this to work.
2060+
}
2061+
int errorCode = 0;
2062+
bool queryError = false;
2063+
if (!hProcess) {
2064+
errorCode = GetLastError();
2065+
2066+
2067+
if (virtualTerminalEnabled) {
2068+
2069+
queryError = true;
2070+
std::cerr << "\033[1;31mError:\033[0m Could not open process with PID "
2071+
<< pid << ". Error code: " << errorCode
2072+
<< "\nMaybe it doesn't exist or access is denied." << std::endl;
2073+
2074+
} else {
2075+
queryError = true;
2076+
std::cerr << "Error: Could not open process with PID "
2077+
<< pid << ". Error code: " << errorCode
2078+
<< "\nMaybe it doesn't exist or access is denied." << std::endl;
2079+
2080+
}
2081+
if (queryError) {
2082+
PrintErrorHints(errorCode, hshot);
2083+
}
2084+
2085+
2086+
}
2087+
2088+
2089+
char exePath[MAX_PATH] = {0};
2090+
DWORD size = MAX_PATH;
2091+
2092+
if (QueryFullProcessImageNameA(hProcess, 0, exePath, &size)) {
2093+
if (virtualTerminalEnabled) {
2094+
std::cout << "\033[34mExecutable Path:\033[0m " << exePath << std::endl;
2095+
} else {
2096+
std::cout << "Executable Path: " << exePath << std::endl;
2097+
}
2098+
} else {
2099+
2100+
errorCode = GetLastError();
2101+
if (virtualTerminalEnabled) {
2102+
queryError = true;
2103+
std::cerr << "\033[1;31mError:\033[0m Unable to query executable path. Error code: "
2104+
<< errorCode
2105+
<< "\n Maybe Access is Denied or the process is running entirely in RAM." << std::endl;
2106+
} else {
2107+
queryError = true;
2108+
std::cerr << "Error: Unable to query executable path. Error code: "
2109+
<< errorCode
2110+
<< "\n Maybe Access is Denied or the process is running entirely in RAM." << std::endl;
2111+
}
2112+
if (queryError) {
2113+
PrintErrorHints(errorCode, hshot);
2114+
// it might seem like overkill to call the function every time there's an error,
2115+
// but if you remember we have a fallback for opening processes, so there are multiple
2116+
// places where an error can occur.
2117+
// for example, when testing this, the hint for error 5 (access denied) didn't show up
2118+
// since immediately after it was overwritten by error code 6 (valid but insufficient permissions) created by the fallback
2119+
// with the limited process info
2120+
}
2121+
2122+
2123+
}
2124+
2125+
// Use our little lookup table to give hints for specific errors
2126+
auto user = GetUserNameFromProcess(pid); // dang it dude it feels like such a war crime using auto in c++ 😭✌️
2127+
if (user.has_value()) {
2128+
if (virtualTerminalEnabled) {
2129+
std::cout << "\033[34mUser\033[0m: " << WideToString(user.value()) << std::endl;
2130+
} else {
2131+
std::cout << "User: " << WideToString(user.value()) << std::endl;
2132+
}
2133+
2134+
} else {
2135+
if (virtualTerminalEnabled) {
2136+
std::cout << "\033[1;34mUser\033[0m: \033[1;31mN/A (Failed to access info)\033[0m" << std::endl;
2137+
} else {
2138+
std::cout << "User: N/A (Failed to access info)" << std::endl;
2139+
}
2140+
}
2141+
2142+
std::string command = GetCommandLine(hProcess);
2143+
2144+
2145+
if (virtualTerminalEnabled) {
2146+
std::cout << "\033[1;32mCommand\033[0m: " << command << std::endl;
2147+
} else {
2148+
std::cout << "Command: " << command << std::endl;
2149+
}
2150+
std::string workdir = GetWorkingDir(hProcess);
2151+
2152+
2153+
2154+
if (virtualTerminalEnabled) {
2155+
std::cout << "\033[1;32mWorking Directory\033[0m: " << workdir << std::endl;
2156+
} else {
2157+
std::cout << "Working Directory: " << workdir << std::endl;
2158+
}
2159+
2160+
// to get memory usage,
2161+
// we have to use psapi.h
2162+
// the metric we want is WorkingSetSize because the api spits out a bunch of other metrics we don't need
2163+
// hopefully this doesn't tank performance for yet another api call
2164+
// the command and working dir don't affect it because PEB walks take like 5 ms idk
2165+
// reference: https://learn.microsoft.com/en-us/windows/win32/psapi/collecting-memory-usage-information-for-a-process
2166+
2167+
PROCESS_MEMORY_COUNTERS pmc;
2168+
if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) {
2169+
// in the original snippet from windows
2170+
// THE BRACKET IS AFTER THE IF IN THE LINE DOWN
2171+
// i can't be talking about code organization but MICROSOFT WHAT
2172+
size_t RAM = pmc.WorkingSetSize; //should be fine for this, unless you have like 10 exabytes of RAM for a single process somehow
2173+
2174+
std::string FRAM = ""; // fram means formatted ram, i'm so creative at var naming
2175+
if (RAM < 1000) {
2176+
// if less than 1000 bytes (which is a kilobyte) then just return bytes
2177+
FRAM = std::to_string(RAM) + " B";
2178+
}
2179+
else if (RAM < 1000ULL * 1000) {
2180+
2181+
FRAM = std::to_string(RAM / 1000) + " KB";
2182+
}
2183+
else if (RAM < 1000ULL * 1000 * 1000) {
2184+
2185+
FRAM = std::to_string(RAM /( 1000ULL * 1000)) + " MB";
2186+
}
2187+
else if (RAM < 1000ULL * 1000 * 1000 * 1000) {
2188+
FRAM = std::to_string(RAM /( 1000ULL * 1000 * 1000)) + " GB";
2189+
}
2190+
else {
2191+
FRAM = std::to_string(RAM /( 1000ULL * 1000 * 1000 * 1000)) + " TB";
2192+
// if someone actually reaches this i'm concerned
2193+
}
2194+
2195+
2196+
2197+
2198+
if (virtualTerminalEnabled) {
2199+
std::cout << "\033[1;32mRAM Usage\033[0m: " << FRAM << std::endl;
2200+
// I know RAM is technically a "nerdy tech term" or whatever and it'd be more logical
2201+
// to say "memory" but I feel like at this point everyone knows what RAM means
2202+
// especially with the RAM shortage, it should be ingrained in their brains
2203+
2204+
} else {
2205+
std::cout << "RAM Usage: " << FRAM << std::endl;
2206+
}
2207+
}
2208+
2209+
2210+
2211+
2212+
2213+
2214+
2215+
2216+
2217+
2218+
// TODO: add color text
2219+
2220+
if (virtualTerminalEnabled) {
2221+
std::cout << "\n\033[1;35mWhy It Exists:\033[0m\n";
2222+
} else {
2223+
std::cout << "\nWhy It Exists:\n";
2224+
}
2225+
PrintAncestry(pid, hshot, pidMap);
2226+
2227+
FindProcessPorts(pid);
2228+
2229+
2230+
2231+
2232+
2233+
if (virtualTerminalEnabled) {
2234+
std::cout << "\n\033[1;35mStarted:\033[0m " << GetReadableFileTime(pid, pidMap) << std::endl;
2235+
} else {
2236+
std::cout << "\nStarted: " << GetReadableFileTime(pid, pidMap) << std::endl;
2237+
}
2238+
2239+
if (pids.size() > 1) {
2240+
if (virtualTerminalEnabled) {
2241+
std::cout << "\033[1;35mRelated Processes:\033[0m\n";
2242+
} else {
2243+
std::cout << "Related Processes:\n";
2244+
}
2245+
2246+
for (size_t i = 1; i < pids.size(); i++) {
2247+
std::string relatedProcName = names[i];
2248+
if (virtualTerminalEnabled) {
2249+
std::cout << "\t\033[36m" << relatedProcName << "\033[90m (PID " << pids[i] << ")\033[0m\n";
2250+
} else {
2251+
std::cout << "\t" << relatedProcName << " (PID " << pids[i] << ")\n";
2252+
}
2253+
2254+
}
2255+
}
2256+
/*
2257+
TODO:
2258+
This definitely needs a lot more details to be complete like witr. Unfortunately, windows needs even more shenanigans and a whole
2259+
lotta more code and admin access to get the same details. I will explain this some other day.
2260+
2261+
This is the output from witr for reference:
2262+
Target : node
2263+
2264+
Process : node (pid 14233)
2265+
User : pm2
2266+
Command : node index.js
2267+
Started : 2 days ago (Mon 2025-02-02 11:42:10 +05:30)
2268+
Restarts : 1
2269+
2270+
Why It Exists :
2271+
systemd (pid 1) → pm2 (pid 5034) → node (pid 14233)
2272+
2273+
Source : pm2
2274+
2275+
Working Dir : /opt/apps/expense-manager
2276+
Git Repo : expense-manager (main)
2277+
Listening : 127.0.0.1:5001
2278+
*/
2279+
2280+
CloseHandle(hProcess);
2281+
2282+
}
20162283
}
20172284

20182285
struct ProcInfos {
@@ -2107,6 +2374,10 @@ int main(int argc, char* argv[]) {
21072374
if (i == 0 && args.size() > 1) {
21082375
continue;
21092376
}
2377+
2378+
if (args[i] == "-a" || args[i] == "-all") {
2379+
s.all = true;
2380+
}
21102381

21112382

21122383

@@ -2131,6 +2402,7 @@ int main(int argc, char* argv[]) {
21312402
std::cout << " \033[1;33m--port <port>\033[0m Specify the port to check" << std::endl;
21322403
std::cout << " \033[1;33m--pid <pid>\033[0m Specify the PID to check" << std::endl;
21332404
std::cout << " \033[1;33m <name>\033[0m Specify the process name to check" << std::endl;
2405+
std::cout << " \033[1;33m-a, --all\033[0m Performs more detailed lookup " << std::endl;
21342406

21352407
} else {
21362408
if (IsProcessElevated()) {
@@ -2145,7 +2417,7 @@ int main(int argc, char* argv[]) {
21452417
std::cout << " --port <port> Specify the port to check" << std::endl;
21462418
std::cout << " --pid <pid> Specify the PID to check" << std::endl;
21472419
std::cout << " <name> Specify the process name to check" << std::endl;
2148-
2420+
std::cout << " -a, --all Performs more detailed lookup" << std::endl;
21492421

21502422
}
21512423
return 0; // exit after printing help because it might try to process -help as a process name otherwise

0 commit comments

Comments
 (0)