KittyMemoryEx.hpp
1 #pragma once 2 3 #include "KittyUtils.hpp" 4 #include <unordered_map> 5 6 /** 7 * @brief Provides utility functions for process memory. 8 */ 9 namespace KittyMemoryEx 10 { 11 /** 12 * @brief Represents a mapping of a memory region. 13 */ 14 class ProcMap 15 { 16 public: 17 pid_t pid; 18 uintptr_t startAddress; 19 uintptr_t endAddress; 20 size_t length; 21 int protection; 22 bool readable, writeable, executable; 23 bool is_private, is_shared; 24 bool is_ro, is_rw, is_rx; 25 uintptr_t offset; 26 std::string dev; 27 unsigned long inode; 28 std::string pathname; 29 30 ProcMap() 31 : pid(0), startAddress(0), endAddress(0), length(0), protection(0), readable(false), writeable(false), 32 executable(false), is_private(false), is_shared(false), is_ro(false), is_rw(false), is_rx(false), 33 offset(0), inode(0) 34 { 35 } 36 37 inline bool operator==(const ProcMap &other) const 38 { 39 return (pid == other.pid && startAddress == other.startAddress && endAddress == other.endAddress && 40 protection == other.protection && is_private == other.is_private && is_shared == other.is_shared && 41 offset == other.offset && dev == other.dev && inode == other.inode && pathname == other.pathname); 42 } 43 44 inline bool operator!=(const ProcMap &other) const 45 { 46 return (pid != other.pid || startAddress != other.startAddress || endAddress != other.endAddress || 47 protection != other.protection || is_private != other.is_private || is_shared != other.is_shared || 48 offset != other.offset || dev != other.dev || inode != other.inode || pathname != other.pathname); 49 } 50 51 /** 52 * @brief Checks if the map is valid. 53 */ 54 inline bool isValid() const 55 { 56 return (startAddress && endAddress && length); 57 } 58 59 /** 60 * @brief Checks if the map is unknown (i.e., no pathname). 61 */ 62 inline bool isUnknown() const 63 { 64 return pathname.empty(); 65 } 66 67 /** 68 * @brief Checks if the map contains a specific address. 69 * 70 * @param address Address to check. 71 * @return True if the address is within the map, false otherwise. 72 */ 73 inline bool contains(uintptr_t address) const 74 { 75 return address >= startAddress && address < endAddress; 76 } 77 78 /** 79 * @brief Converts the map to a string representation.. 80 */ 81 inline std::string toString() const 82 { 83 return KittyUtils::String::fmt("%" PRIxPTR "-%" PRIxPTR " %c%c%c%c %" PRIxPTR " %s %lu %s", 84 startAddress, 85 endAddress, 86 readable ? 'r' : '-', 87 writeable ? 'w' : '-', 88 executable ? 'x' : '-', 89 is_private ? 'p' : 's', 90 offset, 91 dev.c_str(), 92 inode, 93 pathname.c_str()); 94 } 95 }; 96 97 /** 98 * @brief Retrieves the name of the process by its process ID. 99 * 100 * This function reads the command line of the process identified by the given process ID and returns 101 * the process name. 102 * 103 * @param pid The process ID of the process. 104 * @return The name of the process. 105 */ 106 std::string getProcessName(pid_t pid); 107 108 /** 109 * @brief Retrieves a list of process IDs that match a given process name. 110 * 111 * This function searches for all processes whose command line matches the specified process name 112 * and returns their process IDs in a vector. 113 * 114 * @param processName The name of the process to match. 115 * @return A vector of process IDs that match the specified process name. 116 */ 117 std::vector<pid_t> getProcessIDs(const std::string &processName); 118 119 /** 120 * @brief Retrieves the process ID that matches a given process name. 121 * 122 * This function searches for the first process whose command line matches the specified process name 123 * and returns its process ID. 124 * 125 * @param processName The name of the process to match. 126 * @return The process ID that matches the specified process name. 127 */ 128 pid_t getProcessID(const std::string &processName); 129 130 /** 131 * @brief Retrieves a list of thread IDs for a given process ID. 132 * 133 * This function retrieves the thread IDs of all threads associated with the specified process ID 134 * by examining the `/proc/[pid]/task` directory. 135 * 136 * @param pid The process ID of the process. 137 * @return A vector of thread IDs for the specified process. 138 */ 139 std::vector<pid_t> getAllThreads(pid_t pid); 140 141 /** 142 * @brief Class to retrieve process status information. 143 */ 144 class ProcStatus 145 { 146 pid_t _pid, _tid; 147 std::unordered_map<std::string, std::string> data; 148 static bool parse(const std::string &path, ProcStatus *out); 149 150 public: 151 ProcStatus() : _pid(-1), _tid(-1) 152 { 153 } 154 ~ProcStatus() 155 { 156 data.clear(); 157 } 158 159 /** 160 * @brief Parses the status of a process given its PID. 161 * 162 * @param pid The PID of the process to parse. 163 * @param out A pointer to the ProcStatus object where the parsed data will be stored. 164 * @return True if parsing was successful, false otherwise. 165 */ 166 inline static bool parse(pid_t pid, ProcStatus *out) 167 { 168 if (pid <= 0 || !out) 169 return false; 170 171 out->_pid = pid; 172 return parse("/proc/" + std::to_string(pid) + "/status", out); 173 } 174 175 /** 176 * @brief Parses the status of a process given its PID and thread ID. 177 * 178 * @param pid The PID of the process. 179 * @param tid The thread ID of the process. 180 * @param out A pointer to the ProcStatus object where the parsed data will be stored. 181 * @return True if parsing was successful, false otherwise. 182 */ 183 inline static bool parse(pid_t pid, pid_t tid, ProcStatus *out) 184 { 185 if (pid <= 0 || tid <= 0 || !out) 186 return false; 187 188 out->_pid = pid; 189 out->_tid = tid; 190 return parse("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/status", out); 191 } 192 193 /** 194 * @brief Refreshes the process status. 195 * 196 * If the tid is less than or equal to 0, it calls the parse function with the pid. 197 * If the tid is greater than 0, it calls the parse function with the pid and tid. 198 * 199 * @return True if refreshing was successful, false otherwise. 200 */ 201 inline bool refresh() 202 { 203 return _tid <= 0 ? parse(_pid, this) : parse(_pid, _tid, this); 204 } 205 206 /** 207 * @brief Checks if the process status data contains a specific key. 208 * 209 * @param key The key to check. 210 * @return True if the key exists, false otherwise. 211 */ 212 inline bool contains(const std::string &key) const 213 { 214 return data.find(key) != data.end(); 215 } 216 217 /** 218 * @brief Retrieves the string value associated with a key. 219 * 220 * @param key The key to retrieve. 221 * @return The string value associated with the key, or an empty string if the key is not found. 222 */ 223 inline std::string getString(const std::string &key) const 224 { 225 auto it = data.find(key); 226 return (it != data.end()) ? it->second : ""; 227 } 228 229 /** 230 * @brief Retrieves the integer value associated with a key. 231 * 232 * @param key The key to retrieve. 233 * @return The integer value associated with the key, or 0 if the key is not found. 234 */ 235 inline long long getInt(const std::string &key) const 236 { 237 auto it = data.find(key); 238 if (it == data.end()) 239 return 0; 240 241 return std::strtoll(it->second.c_str(), nullptr, 10); 242 } 243 244 /** 245 * @brief Retrieves the boolean value associated with a key. 246 * 247 * @param key The key to retrieve. 248 * @return True if the key's value is 1, false otherwise. 249 */ 250 inline bool getBool(const std::string &key) const 251 { 252 return getInt(key) == 1; 253 } 254 }; 255 256 /** 257 * @brief Enumerates the filter types for finding memory maps. 258 */ 259 enum class EProcMapFilter 260 { 261 Equal, 262 Contains, 263 StartWith, 264 EndWith, 265 Regex 266 }; 267 268 /** 269 * @brief Retrieves information about all memory maps in a remote process. 270 * 271 * @param pid The remote process ID 272 * @return Vector of ProcMap objects representing all memory maps. 273 */ 274 std::vector<ProcMap> getAllMaps(pid_t pid); 275 276 /** 277 * @brief Retrieves information about all memory maps in a remote process. 278 * 279 * @param pid The remote process ID 280 * @param filter Filter type to use. 281 * @param name Name to filter by. 282 * @param maps The vector of cached process maps (optional). 283 * @return Vector of ProcMap objects that match the filter. 284 */ 285 std::vector<ProcMap> getMaps(pid_t pid, 286 EProcMapFilter filter, 287 const std::string &name, 288 const std::vector<ProcMap> &maps = std::vector<ProcMap>()); 289 290 /** 291 * @brief Retrieves the map information for a specific address in the current process. 292 * 293 * @param pid The remote process ID 294 * @param address Address to search for. 295 * @param maps The vector of cached process maps (optional). 296 * @return ProcMap object representing the map for the address, or an invalid map if not found. 297 */ 298 ProcMap getAddressMap(pid_t pid, uintptr_t address, const std::vector<ProcMap> &maps = std::vector<ProcMap>()); 299 300 #ifdef __ANDROID__ 301 /** 302 * @brief Retrieves the Android app directory. 303 * 304 * @param pkg The app's package name 305 * @return App directory 306 */ 307 std::string getAppDirectory(const std::string &pkg); 308 #endif 309 } // namespace KittyMemoryEx