SimpleProcStat getProcStat(const std::string& pid) { SimpleProcStat stat; std::string content; if (readFile(getProcAttr("stat", pid), content).ok()) { auto detail_start = content.find_last_of(")"); // Start parsing stats from ") <MODE>..." auto details = osquery::split(content.substr(detail_start + 2), " "); stat.state = details.at(0); stat.parent = details.at(1); stat.group = details.at(2); stat.user_time = details.at(11); stat.system_time = details.at(12); stat.nice = details.at(16); stat.start_time = TEXT(AS_LITERAL(BIGINT_LITERAL, details.at(19)) / 100); } if (readFile(getProcAttr("status", pid), content).ok()) { for (const auto& line : osquery::split(content, "\n")) { // Status lines are formatted: Key: Value....\n. auto detail = osquery::split(line, ":", 1); if (detail.size() != 2) { continue; } // There are specific fields from each detail. if (detail.at(0) == "Name") { stat.name = detail.at(1); } else if (detail.at(0) == "VmRSS") { detail[1].erase(detail.at(1).end() - 3, detail.at(1).end()); // Memory is reported in kB. stat.resident_size = detail.at(1) + "000"; } else if (detail.at(0) == "VmSize") { detail[1].erase(detail.at(1).end() - 3, detail.at(1).end()); // Memory is reported in kB. stat.phys_footprint = detail.at(1) + "000"; } else if (detail.at(0) == "Gid") { // Format is: R E - - auto gid_detail = osquery::split(detail.at(1), "\t"); if (gid_detail.size() == 4) { stat.real_gid = gid_detail.at(0); stat.effective_gid = gid_detail.at(1); } } else if (detail.at(0) == "Uid") { auto uid_detail = osquery::split(detail.at(1), "\t"); if (uid_detail.size() == 4) { stat.real_uid = uid_detail.at(0); stat.effective_uid = uid_detail.at(1); } } } } return stat; }
inline std::string readProcLink(const std::string& attr, const std::string& pid) { // The exe is a symlink to the binary on-disk. auto attr_path = getProcAttr(attr, pid); std::string result; char link_path[PATH_MAX] = {0}; auto bytes = readlink(attr_path.c_str(), link_path, sizeof(link_path) - 1); if (bytes >= 0) { result = std::string(link_path); } return result; }
inline std::string readProcCMDLine(const std::string& pid) { auto attr = getProcAttr("cmdline", pid); std::string content; readFile(attr, content); // Remove \0 delimiters. std::replace_if(content.begin(), content.end(), [](const char& c) { return c == 0; }, ' '); // Remove trailing delimiter. boost::algorithm::trim(content); return content; }
void genProcessMap(const std::string& pid, QueryData& results) { auto map = getProcAttr("maps", pid); std::string content; readFile(map, content); for (auto& line : osquery::split(content, "\n")) { auto fields = osquery::split(line, " "); // If can't read address, not sure. if (fields.size() < 5) { continue; } Row r; r["pid"] = pid; if (!fields[0].empty()) { auto addresses = osquery::split(fields[0], "-"); if (addresses.size() >= 2) { r["start"] = "0x" + addresses[0]; r["end"] = "0x" + addresses[1]; } else { // Problem with the address format. continue; } } r["permissions"] = fields[1]; try { auto offset = std::stoll(fields[2], nullptr, 16); r["offset"] = (offset != 0) ? BIGINT(offset) : r["start"]; } catch (const std::exception& e) { // Value was out of range or could not be interpreted as a hex long long. r["offset"] = "-1"; } r["device"] = fields[3]; r["inode"] = fields[4]; // Path name must be trimmed. if (fields.size() > 5) { boost::trim(fields[5]); r["path"] = fields[5]; } // BSS with name in pathname. r["pseudo"] = (fields[4] == "0" && !r["path"].empty()) ? "1" : "0"; results.push_back(std::move(r)); } }
void genProcessEnvironment(const std::string& pid, QueryData& results) { auto attr = getProcAttr("environ", pid); std::string content; readFile(attr, content); const char* variable = content.c_str(); // Stop at the end of nul-delimited string content. while (*variable > 0) { auto buf = std::string(variable); size_t idx = buf.find_first_of("="); Row r; r["pid"] = pid; r["key"] = buf.substr(0, idx); r["value"] = buf.substr(idx + 1); results.push_back(r); variable += buf.size() + 1; } }
void genProcessMap(const std::string& pid, QueryData& results) { auto map = getProcAttr("maps", pid); std::string content; readFile(map, content); for (auto& line : osquery::split(content, "\n")) { auto fields = osquery::split(line, " "); Row r; r["pid"] = pid; // If can't read address, not sure. if (fields.size() < 5) { continue; } if (fields[0].size() > 0) { auto addresses = osquery::split(fields[0], "-"); r["start"] = "0x" + addresses[0]; r["end"] = "0x" + addresses[1]; } r["permissions"] = fields[1]; r["offset"] = BIGINT(std::stoll(fields[2], nullptr, 16)); r["device"] = fields[3]; r["inode"] = fields[4]; // Path name must be trimmed. if (fields.size() > 5) { boost::trim(fields[5]); r["path"] = fields[5]; } // BSS with name in pathname. r["pseudo"] = (fields[4] == "0" && r["path"].size() > 0) ? "1" : "0"; results.push_back(r); } }