Created
April 11, 2020 10:37
-
-
Save karliky/949bacbc49e7bf3994899f99b8b2e207 to your computer and use it in GitHub Desktop.
Robot-js fix to enable debug privilege
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////// | |
// -------------------------------------------------------------------------- // | |
// // | |
// (C) 2010-2016 Robot Developers // | |
// See LICENSE for licensing info // | |
// // | |
// -------------------------------------------------------------------------- // | |
//////////////////////////////////////////////////////////////////////////////// | |
//----------------------------------------------------------------------------// | |
// Prefaces // | |
//----------------------------------------------------------------------------// | |
#include "Process.h" | |
#include "Memory.h" | |
#include "Module.h" | |
#include "Window.h" | |
#include <algorithm> | |
using std::sort; | |
using std::replace; | |
using std::unique; | |
using std::string; | |
#include <regex> | |
using std::regex; | |
using std::regex_match; | |
#ifdef ROBOT_OS_LINUX | |
#include <wait.h> | |
#include <dirent.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <cstring> | |
#include <fstream> | |
using std::ios; | |
using std::ifstream; | |
using std:: fstream; | |
using std:: getline; | |
#include <sys/utsname.h> | |
// Path to proc directory | |
#define PROC_PATH "/proc/" | |
#endif | |
#ifdef ROBOT_OS_MAC | |
#include <sys/utsname.h> | |
#include <mach/task.h> | |
#include <mach/mach_vm.h> | |
// Apple process API | |
#include <libproc.h> | |
#include <ApplicationServices/ApplicationServices.h> | |
#ifndef EXC_MASK_GUARD | |
#define EXC_MASK_GUARD 0 | |
#endif | |
#endif | |
#ifdef ROBOT_OS_WIN | |
#define NOMINMAX | |
#define WIN32_LEAN_AND_MEAN | |
#include <Windows.h> | |
// Win process API | |
#include <Psapi.h> | |
#include <iostream> | |
using std::wstring; | |
using std::cout; | |
#endif | |
ROBOT_NS_BEGIN | |
//----------------------------------------------------------------------------// | |
// Locals // | |
//----------------------------------------------------------------------------// | |
#ifdef ROBOT_OS_WIN | |
#ifdef UNICODE | |
//////////////////////////////////////////////////////////////////////////////// | |
string _UTF8Encode (const wstring& value) | |
{ | |
// Do nothing if parameter is empty | |
if (value.empty()) return string(); | |
int size = 0; | |
// Compute size of the resulting string | |
size = WideCharToMultiByte (CP_UTF8, 0, | |
&value[0], (int) value.size(), | |
nullptr, 0, nullptr, nullptr); | |
string result (size, 0); | |
// Convert wide-string to a UTF8 string | |
size = WideCharToMultiByte (CP_UTF8, 0, | |
&value [0], (int) value.size(), | |
&result[0], size, nullptr, nullptr); | |
// Return result if encoding succeeded | |
return size > 0 ? result : string(); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
wstring _UTF8Decode (const string& value) | |
{ | |
// Do nothing if parameter is empty | |
if (value.empty()) return wstring(); | |
int size = 0; | |
// Compute size of resulting string | |
size = MultiByteToWideChar (CP_UTF8, | |
0, &value[0], (int) value.size(), | |
nullptr, 0); | |
wstring result (size, 0); | |
// Convert UTF8 string to wide-string | |
size = MultiByteToWideChar (CP_UTF8, | |
0, &value[0], (int) value.size(), | |
&result[0], size); | |
// Return result if encoding succeeded | |
return size > 0 ? result : wstring(); | |
} | |
#else | |
//////////////////////////////////////////////////////////////////////////////// | |
string _UTF8Encode (const string& value) | |
{ | |
return value; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
string _UTF8Decode (const string& value) | |
{ | |
return value; | |
} | |
#endif | |
#endif | |
//----------------------------------------------------------------------------// | |
// Classes Process // | |
//----------------------------------------------------------------------------// | |
//////////////////////////////////////////////////////////////////////////////// | |
struct Process::Data | |
{ | |
int32 ProcID; // The process ID | |
string Name; // Name of process | |
string Path; // Path of process | |
bool Is64Bit; // Process is 64-Bit | |
#ifdef ROBOT_OS_LINUX | |
uint32 Handle; // Unused handle | |
#endif | |
#ifdef ROBOT_OS_MAC | |
task_t Handle; // The mach task | |
#endif | |
#ifdef ROBOT_OS_WIN | |
HANDLE Handle; // Process handle | |
#endif | |
}; | |
#ifdef ROBOT_OS_MAC | |
//////////////////////////////////////////////////////////////////////////////// | |
struct AllImageInfo | |
{ | |
uint32 Version; | |
uint32 Count; | |
union | |
{ | |
uint32 Array32; | |
uint64 Array64; | |
}; | |
uint64 Pad[64]; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
struct ImageInfo32 | |
{ | |
uint32 Addr; | |
uint32 Path; | |
uint32 Date; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
struct ImageInfo64 | |
{ | |
uint64 Addr; | |
uint64 Path; | |
uint64 Date; | |
}; | |
#endif | |
//----------------------------------------------------------------------------// | |
// Constructors Process // | |
//----------------------------------------------------------------------------// | |
//////////////////////////////////////////////////////////////////////////////// | |
Process::Process (int32 pid) : mData (new Process::Data(), [](Process::Data* data) | |
{ | |
#ifdef ROBOT_OS_WIN | |
// Close the process handle | |
CloseHandle (data->Handle); | |
#endif | |
// Free data | |
delete data; | |
}) | |
{ | |
mData->ProcID = 0; | |
mData->Handle = 0; | |
mData->Is64Bit = false; | |
Open (pid); | |
} | |
//----------------------------------------------------------------------------// | |
// Functions Process // | |
//----------------------------------------------------------------------------// | |
//////////////////////////////////////////////////////////////////////////////// | |
bool SetPrivilege( HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege ) | |
{ | |
TOKEN_PRIVILEGES tp; | |
LUID luid; | |
TOKEN_PRIVILEGES tpPrevious; | |
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); | |
if(!LookupPrivilegeValue( NULL, lpszPrivilege, &luid )) | |
return false; | |
// 1) Get current privilege setting | |
tp.PrivilegeCount = 1; | |
tp.Privileges[0].Luid = luid; | |
tp.Privileges[0].Attributes = 0; | |
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious); | |
if (GetLastError() != ERROR_SUCCESS) | |
return false; | |
// 2) Set privilege based on previous setting | |
tpPrevious.PrivilegeCount = 1; | |
tpPrevious.Privileges[0].Luid = luid; | |
if (bEnablePrivilege) | |
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); | |
else | |
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); | |
AdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL ); | |
if (GetLastError() != ERROR_SUCCESS) | |
return false; | |
return true; | |
} | |
bool SetDebugPrivilege() | |
{ | |
HANDLE hToken; | |
bool bOK = false; | |
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) | |
{ | |
if (!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)) | |
{ | |
MessageBoxA(NULL, "Cannot set privilege", "Cannot set privilege", MB_OK); | |
} | |
else | |
bOK = true; | |
CloseHandle(hToken); | |
} | |
else | |
MessageBoxA(NULL, "Cannot OpenProcessToken", "Cannot OpenProcessToken", MB_OK); | |
return bOK; | |
} | |
bool Process::Open (int32 pid) | |
{ | |
// Close opened process | |
if (IsValid()) Close(); | |
#ifdef ROBOT_OS_LINUX | |
if (pid > 0 && (kill (pid, 0) == 0 || errno != ESRCH)) | |
{ | |
// Store the ProcID | |
mData->ProcID = pid; | |
#ifdef ROBOT_ARCH_64 | |
// Use default setting | |
mData->Is64Bit = true; | |
#endif | |
char exe[32], link[4096]; | |
// Build path to process's executable link | |
snprintf (exe, 32, PROC_PATH "%d/exe", pid); | |
// Determine arch by reading ELF | |
ifstream file (exe, ios::binary); | |
if (file) | |
{ | |
// Arch offset | |
file.seekg (4); | |
int8 format = 0; | |
if (file >> format) | |
// 64-Bit if the format is 2 | |
mData->Is64Bit = format == 2; | |
} | |
#ifdef ROBOT_ARCH_32 | |
// Don't attach to x64 processes from x86 apps | |
if (mData->Is64Bit) { Close(); return false; } | |
#endif | |
// Read symbolic link of the executable | |
auto len = readlink (exe, link, 4096); | |
if (len > 0) | |
{ | |
string name, path (link, (size_t) len); | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
// Store both the name and path values | |
mData->Name = name; mData->Path = path; | |
} | |
return true; | |
} | |
return false; | |
#endif | |
#ifdef ROBOT_OS_MAC | |
if (pid > 0 && (kill (pid, 0) == 0 || errno != ESRCH)) | |
{ | |
// Store the ProcID | |
mData->ProcID = pid; | |
#ifdef ROBOT_ARCH_64 | |
// Use default setting | |
mData->Is64Bit = true; | |
#endif | |
proc_bsdshortinfo info; | |
// Retrieve BSD info to determine process kind | |
if (proc_pidinfo (pid, PROC_PIDT_SHORTBSDINFO, 0, | |
&info, PROC_PIDT_SHORTBSDINFO_SIZE)) mData-> | |
Is64Bit = info.pbsi_flags & PROC_FLAG_LP64; | |
#ifdef ROBOT_ARCH_32 | |
// Don't attach to x64 processes from x86 apps | |
if (mData->Is64Bit) { Close(); return false; } | |
#endif | |
// Attempt to retrieve process path | |
char link[PROC_PIDPATHINFO_MAXSIZE]; | |
auto len = proc_pidpath (pid, link, | |
PROC_PIDPATHINFO_MAXSIZE); | |
if (len > 0) | |
{ | |
string name, path (link, (size_t) len); | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
// Store both the name and path values | |
mData->Name = name; mData->Path = path; | |
} | |
// Attempt to retrieve the mach task port for the process | |
if (task_for_pid (mach_task_self(), pid, &mData->Handle)) | |
mData->Handle = 0; | |
return true; | |
} | |
return false; | |
#endif | |
#ifdef ROBOT_OS_WIN | |
SetDebugPrivilege(); | |
mData->Handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); | |
// DWORD dw = GetLastError(); | |
// char buffer[256]={0}; | |
// int *p; | |
// int A = dw; | |
// p = &A; | |
// sprintf_s(buffer , 255, "Address of variable A is: Hex :%x (Decimal: %d)",p,&A);//p and &A are the same thing | |
//MessageBoxA(NULL, buffer, buffer, MB_OK); | |
// Check if handle is valid | |
if (mData->Handle != nullptr) | |
{ | |
// Store the ProcID | |
mData->ProcID = pid; | |
// Check if system 64-Bit | |
if (Process::IsSys64Bit()) | |
{ | |
BOOL is32Bit = TRUE; | |
// Set whether process is 64-Bit | |
mData->Is64Bit = IsWow64Process | |
(mData->Handle, &is32Bit) && | |
is32Bit == FALSE; | |
} | |
#ifdef ROBOT_ARCH_32 | |
// Don't attach to x64 processes from x86 apps | |
if (mData->Is64Bit) { Close(); return false; } | |
#endif | |
DWORD size = MAX_PATH; | |
TCHAR link [MAX_PATH]; | |
string name, path; | |
if (QueryFullProcessImageName | |
// Try and get process path name | |
(mData->Handle, 0, link, &size)) | |
{ | |
path = _UTF8Encode (link); | |
// Convert any backslashes to normal slashes | |
replace (path.begin(), path.end(), '\\', '/'); | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
// Store both the name and path values | |
mData->Name = name; mData->Path = path; | |
} | |
return true; | |
} | |
return false; | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
void Process::Close (void) | |
{ | |
#ifdef ROBOT_OS_WIN | |
// Close the process handle | |
CloseHandle (mData->Handle); | |
#endif | |
mData->ProcID = 0; | |
mData->Handle = 0; | |
mData->Is64Bit = false; | |
mData->Name.clear(); | |
mData->Path.clear(); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::IsValid (void) const | |
{ | |
#ifdef ROBOT_OS_LINUX | |
return mData->ProcID > 0 && | |
(kill (mData->ProcID, 0) | |
== 0 || errno != ESRCH); | |
#endif | |
#ifdef ROBOT_OS_MAC | |
return mData->ProcID > 0 && | |
(kill (mData->ProcID, 0) | |
== 0 || errno != ESRCH); | |
#endif | |
#ifdef ROBOT_OS_WIN | |
return mData->Handle != 0; | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::Is64Bit (void) const | |
{ | |
return mData->Is64Bit; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::IsDebugged (void) const | |
{ | |
// Check the process validity | |
if (!IsValid()) return false; | |
#ifdef ROBOT_OS_LINUX | |
char status[32]; | |
// Build path to the status file | |
snprintf (status, 32, PROC_PATH | |
"%d/status", mData->ProcID); | |
// Attempt to open status file | |
fstream file (status, ios::in); | |
if (!file) return false; | |
string line; | |
// Create the mappings list | |
while (getline (file, line)) | |
{ | |
// Check if reached tracer and return result | |
if (line.find ("TracerPid:") != string::npos) | |
return atoi (line.data() + 10) != 0; | |
} | |
return false; | |
#endif | |
#ifdef ROBOT_OS_MAC | |
// Verify whether mach task is valid | |
if (mData->Handle == 0) return false; | |
// Based on: stackoverflow.com/questions/2200277 | |
exception_mask_t masks [EXC_TYPES_COUNT]; | |
mach_port_t ports [EXC_TYPES_COUNT]; | |
exception_behavior_t behaviors[EXC_TYPES_COUNT]; | |
thread_state_flavor_t flavors [EXC_TYPES_COUNT]; | |
mach_msg_type_number_t count = 0; | |
static const exception_mask_t excMask = | |
EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD); | |
// Get send rights to task's exception ports | |
if (!task_get_exception_ports (mData->Handle, | |
excMask, masks, &count, ports, behaviors, flavors)) | |
{ | |
// A debugger is present if any mach port is valid | |
for (mach_msg_type_number_t i = 0; i < count; ++i) | |
if (MACH_PORT_VALID (ports[i])) return true; | |
} | |
return false; | |
#endif | |
#ifdef ROBOT_OS_WIN | |
BOOL res = FALSE; | |
// Is the process being debugged | |
return CheckRemoteDebuggerPresent | |
(mData->Handle, &res) && res; | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
int32 Process::GetPID (void) const | |
{ | |
return mData->ProcID; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
uintptr Process::GetHandle (void) const | |
{ | |
return (uintptr) | |
mData->Handle; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
string Process::GetName (void) const | |
{ | |
return mData->Name; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
string Process::GetPath (void) const | |
{ | |
return mData->Path; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
void Process::Exit (void) | |
{ | |
// Check process validity | |
if (!IsValid()) return; | |
#ifdef ROBOT_OS_LINUX | |
kill (mData->ProcID, SIGTERM); | |
#endif | |
#ifdef ROBOT_OS_MAC | |
kill (mData->ProcID, SIGTERM); | |
#endif | |
#ifdef ROBOT_OS_WIN | |
// Get every process window | |
auto list = Window::GetList | |
(nullptr, mData->ProcID); | |
// Close every open window in this process | |
for (uintptr i = 0; i < list.size(); ++i) | |
list[i].Close(); | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
void Process::Kill (void) | |
{ | |
// Check process validity | |
if (!IsValid()) return; | |
#ifdef ROBOT_OS_LINUX | |
kill (mData->ProcID, SIGKILL); | |
#endif | |
#ifdef ROBOT_OS_MAC | |
kill (mData->ProcID, SIGKILL); | |
#endif | |
#ifdef ROBOT_OS_WIN | |
TerminateProcess (mData->Handle, -1); | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::HasExited (void) const | |
{ | |
// Check the process validity | |
if (!IsValid()) return true; | |
#ifdef ROBOT_OS_LINUX | |
return false; | |
#endif | |
#ifdef ROBOT_OS_MAC | |
return false; | |
#endif | |
#ifdef ROBOT_OS_WIN | |
DWORD code = -1; | |
return !GetExitCodeProcess | |
(mData->Handle, &code) | |
|| code != STILL_ACTIVE; | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
ModuleList Process::GetModules (const char* name) const | |
{ | |
ModuleList result; | |
// Check the process validity | |
if (!IsValid()) return result; | |
// Check if the name is empty | |
bool empty = name == nullptr; | |
regex regexp; if (!empty) { | |
// Attempt to use a case-insensitive regex | |
try { regexp = regex (name, regex::icase); } | |
catch (...) { return result; } | |
} | |
#ifdef ROBOT_OS_LINUX | |
char maps[32]; | |
// Build path to PID maps file | |
snprintf (maps, 32, PROC_PATH | |
"%d/maps", mData->ProcID); | |
// Attempt to open maps file | |
fstream file (maps, ios::in); | |
if (!file) return result; | |
// Delegate for processing our modules | |
auto storeModule = [&] (uintptr start, | |
uintptr stop, const string& path) | |
{ | |
string name; | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
// Check if current module name matches | |
if (empty || regex_match (name, regexp)) | |
{ | |
result.push_back (Module | |
(*this, name, path, | |
start, stop - start)); | |
} | |
}; | |
char currentPath[1024]; | |
currentPath[0] = '\0'; | |
uintptr currentStart = 0; | |
uintptr currentStop = 0; | |
string line; | |
// Create the mappings list | |
while (getline (file, line)) | |
{ | |
size_t start; uint32 offset, inode; | |
size_t stop; uint16 devmaj, devmin; | |
char access[5]; char pathname[1024]; | |
// Parse the current line into a single complete mapping entry | |
if (sscanf (line.data(), "%zx-%zx %4s %x %hx:%hx %u %1023s", | |
&start, &stop, access, &offset, &devmaj, &devmin, &inode, | |
pathname) != 8) continue; | |
// Check if module continued from before | |
if (strcmp (currentPath, pathname) == 0) | |
{ currentStop = stop; continue; } | |
if (currentStart != 0) | |
storeModule (currentStart, currentStop, currentPath); | |
// Check whether the current pathname is valid | |
if (pathname[0] == '\0' || pathname[0] == '[') | |
{ currentStart = 0; currentPath[0] = '\0'; } | |
else | |
{ | |
currentStart = start; | |
currentStop = stop; | |
strncpy (currentPath, pathname, 1024); | |
currentPath[1023] = '\0'; | |
} | |
} | |
if (currentStart != 0) | |
// Append any modules that are at the end of the file | |
storeModule (currentStart, currentStop, currentPath); | |
// Sort modules using their address | |
sort (result.begin(), result.end()); | |
#endif | |
#ifdef ROBOT_OS_MAC | |
// Verify whether mach task is valid | |
if (mData->Handle == 0) return result; | |
task_dyld_info dyldInfo; | |
mach_msg_type_number_t count; | |
count = TASK_DYLD_INFO_COUNT; | |
mach_vm_size_t bytesRead = 0; | |
task_t task = mData->Handle; | |
// Find the task's dyld-info address | |
if (task_info (task, TASK_DYLD_INFO, | |
(task_info_t) &dyldInfo, &count)) | |
return result; | |
// This shouldn't happen, but if it does, avoid overflow | |
if (dyldInfo.all_image_info_size > sizeof (AllImageInfo)) | |
return result; | |
AllImageInfo allInfo; | |
// Read the all-image-info address | |
if (mach_vm_read_overwrite (task, | |
dyldInfo.all_image_info_addr, | |
dyldInfo.all_image_info_size, | |
(mach_vm_address_t) &allInfo, | |
&bytesRead)) return result; | |
if (allInfo.Count == 0 || bytesRead | |
!= dyldInfo.all_image_info_size) | |
return result; | |
// Delegate for processing our modules | |
auto storeModule = [&] (uint32 index, | |
uint64 imageAddr, uint64 imagePath) | |
{ | |
std::string path; std::string name; | |
// Check if module is executable | |
if (index == 0) path = mData->Path; | |
else | |
{ | |
char mPath[PATH_MAX]; | |
char rPath[PATH_MAX]; | |
// Attempt to read the file path of the current image | |
if (mach_vm_read_overwrite (task, (mach_vm_address_t) | |
imagePath, PATH_MAX, (mach_vm_address_t) mPath, | |
&bytesRead) || bytesRead != PATH_MAX) return; | |
// Convert path to a canonicalized absolute pathname | |
path = realpath (mPath, rPath) == 0 ? mPath : rPath; | |
} | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
// Check if current module name matches | |
if (empty || regex_match (name, regexp)) | |
{ | |
result.push_back (Module | |
(*this, name, path, | |
(uintptr) imageAddr, 0)); | |
} | |
}; | |
if (mData->Is64Bit) | |
{ | |
// Ensure array is valid | |
if (allInfo.Array64 == 0) | |
return result; | |
// Allocate enough data to store entire info array | |
ImageInfo64* info = new ImageInfo64[allInfo.Count]; | |
// Compute sizes of info array | |
mach_vm_size_t size64 = sizeof | |
(ImageInfo64) * allInfo.Count; | |
// Read the entire info array as single read operation | |
if (mach_vm_read_overwrite (task, (mach_vm_address_t) | |
allInfo.Array64, size64, (mach_vm_address_t) info, | |
&bytesRead) == KERN_SUCCESS && bytesRead == size64) | |
{ | |
// Iterate through all info array elements | |
for (uint32 i = 0; i < allInfo.Count; ++i) | |
{ | |
// Use delegate to process and add our module | |
storeModule (i, info[i].Addr, info[i].Path); | |
} | |
} | |
delete[] info; | |
} | |
else | |
{ | |
// Ensure array is valid | |
if (allInfo.Array32 == 0) | |
return result; | |
// Allocate enough data to store entire info array | |
ImageInfo32* info = new ImageInfo32[allInfo.Count]; | |
// Compute sizes of info array | |
mach_vm_size_t size32 = sizeof | |
(ImageInfo32) * allInfo.Count; | |
// Read the entire info array as single read operation | |
if (mach_vm_read_overwrite (task, (mach_vm_address_t) | |
allInfo.Array32, size32, (mach_vm_address_t) info, | |
&bytesRead) == KERN_SUCCESS && bytesRead == size32) | |
{ | |
// Iterate through all info array elements | |
for (uint32 i = 0; i < allInfo.Count; ++i) | |
{ | |
// Use delegate to process and add our module | |
storeModule (i, info[i].Addr, info[i].Path); | |
} | |
} | |
delete[] info; | |
} | |
// Sort modules using their address | |
sort (result.begin(), result.end()); | |
auto iterator = | |
// Remove duplicates in strange cases | |
unique (result.begin(), result.end()); | |
result.erase (iterator, result.end()); | |
#endif | |
#ifdef ROBOT_OS_WIN | |
// Save current process handle | |
HANDLE handle = mData->Handle; | |
// Retrieve current process modules | |
HMODULE list[2048]; DWORD size = 0; | |
if (!EnumProcessModulesEx (handle, | |
list, sizeof (list), &size, | |
LIST_MODULES_ALL)) return result; | |
// Loop through every process module | |
DWORD count = size / sizeof (HMODULE); | |
for (DWORD i = 0; i < count; ++i) | |
{ | |
std::string path, name; | |
TCHAR modPath[MAX_PATH]; | |
// Get the current modules path | |
if (GetModuleFileNameEx (handle, | |
list[i], modPath, MAX_PATH)) | |
{ | |
path = _UTF8Encode (modPath); | |
// Convert any backslashes to normal slashes | |
replace (path.begin(), path.end(), '\\', '/'); | |
// Retrieve the file part of the path | |
auto last = path.find_last_of ('/'); | |
if (last == string::npos) name = path; | |
else name = path.substr (last + 1); | |
} | |
// Check if current module name matches | |
if (empty || regex_match (name, regexp)) | |
{ | |
MODULEINFO info = { 0 }; | |
// Attempt to retrieve module info | |
if (GetModuleInformation (handle, | |
list[i], &info, sizeof (info))) | |
{ | |
result.push_back | |
(Module (*this, name, path, | |
(uintptr) info.lpBaseOfDll, | |
(uintptr) info.SizeOfImage)); | |
} | |
} | |
} | |
// Sort modules using their address | |
sort (result.begin(), result.end()); | |
#endif | |
return result; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
WindowList Process::GetWindows (const char* title) const | |
{ | |
// Check whether process is valid | |
if (!IsValid()) return WindowList(); | |
// Get results using the private window call | |
return Window::GetList (title, mData->ProcID); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
ProcessList Process::GetList (const char* name) | |
{ | |
ProcessList result; | |
// Check if the name is empty | |
bool empty = name == nullptr; | |
regex regexp; if (!empty) { | |
// Attempt to use a case-insensitive regex | |
try { regexp = regex (name, regex::icase); } | |
catch (...) { return result; } | |
} | |
#ifdef ROBOT_OS_LINUX | |
DIR* dir = opendir (PROC_PATH); | |
struct dirent* entry = nullptr; | |
// Iterate through the entire proc directory | |
while ((entry = readdir (dir)) != nullptr) | |
{ | |
// Check if this directory is all numbers | |
if (strspn (entry->d_name, "0123456789") | |
!= strlen (entry->d_name)) continue; | |
// Get the process id as integer | |
int32 pid = atoi (entry->d_name); | |
Process process; | |
// Attempt to open and match current process | |
if (process.Open (pid) && (empty == true || | |
regex_match (process.mData->Name, regexp))) | |
{ | |
// Append process to result | |
result.push_back (process); | |
} | |
} | |
closedir (dir); | |
return result; | |
#endif | |
#ifdef ROBOT_OS_MAC | |
pid_t list[4096]; | |
// Get current process list | |
int32 size = proc_listpids | |
(PROC_ALL_PIDS, 0, list, sizeof (list)); | |
if (size <= 0) return result; | |
// Loop through all system processes | |
int32 count = size / sizeof (int32); | |
for (uintptr i = 0; i < count; ++i) | |
{ | |
Process process; | |
// Attempt to open and match current process | |
if (process.Open (list[i]) && (empty == true || | |
regex_match (process.mData->Name, regexp))) | |
{ | |
// Append process to result | |
result.push_back (process); | |
} | |
} | |
return result; | |
#endif | |
#ifdef ROBOT_OS_WIN | |
// Get current process list | |
DWORD list[4096], size = 0; | |
if (!EnumProcesses (list, sizeof (list), &size)) | |
return result; | |
// Loop through all system processes | |
DWORD count = size / sizeof (DWORD); | |
for (uintptr i = 0; i < count; ++i) | |
{ | |
Process process; | |
// Attempt to open and match current process | |
if (process.Open (list[i]) && (empty == true || | |
regex_match (process.mData->Name, regexp))) | |
{ | |
// Append process to result | |
result.push_back (process); | |
} | |
} | |
return result; | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
Process Process::GetCurrent (void) | |
{ | |
#ifdef ROBOT_OS_LINUX | |
return Process (getpid()); | |
#endif | |
#ifdef ROBOT_OS_MAC | |
return Process (getpid()); | |
#endif | |
#ifdef ROBOT_OS_WIN | |
return Process | |
(GetCurrentProcessId()); | |
#endif | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::IsSys64Bit (void) | |
{ | |
// Initialize only once | |
static int8 is64Bit = -1; | |
if (is64Bit == -1) | |
{ | |
#if defined (ROBOT_OS_MAC) || \ | |
defined (ROBOT_OS_LINUX) | |
utsname unameData; | |
uname (&unameData); | |
is64Bit = !strcmp (unameData. | |
machine, "x86_64") ? 1:0; | |
#endif | |
#ifdef ROBOT_OS_WIN | |
SYSTEM_INFO info; | |
// Retrieve the system info | |
GetNativeSystemInfo (&info); | |
is64Bit = | |
info.wProcessorArchitecture == | |
PROCESSOR_ARCHITECTURE_AMD64 ? | |
1 : 0; | |
#endif | |
} | |
return is64Bit == 1; | |
} | |
//----------------------------------------------------------------------------// | |
// Operators Process // | |
//----------------------------------------------------------------------------// | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::operator == (const Process& process) const | |
{ | |
return mData->ProcID == process.mData->ProcID; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::operator != (const Process& process) const | |
{ | |
return mData->ProcID != process.mData->ProcID; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::operator == (int32 pid) const | |
{ | |
return mData->ProcID == pid; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
bool Process::operator != (int32 pid) const | |
{ | |
return mData->ProcID != pid; | |
} | |
ROBOT_NS_END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment