05_osquery_源码解读_os_version


1. 表

osquery所有的表的定义都是位于/specs下面,其表的实现都是位于/osquery/tables下面

1.1. os_version

os_version是用于查看操作系统相关信息的表。其查询结果如下:

osquery> select * from os_version;
+--------------+--------------------------------------+-------+-------+-------+-------+----------+---------------+----------+
| name         | version                              | major | minor | patch | build | platform | platform_like | codename |
+--------------+--------------------------------------+-------+-------+-------+-------+----------+---------------+----------+
| CentOS Linux | CentOS Linux release 7.9.2009 (Core) | 7     | 9     | 2009  |       | rhel     | rhel          |          |
+--------------+--------------------------------------+-------+-------+-------+-------+----------+---------------+----------+
  • major 系统主版本号
  • minor 系统小版本号
  • build (Windows)系统内部版本号

1.2. os_version表的定义

其表的定义是在specs/os_version.table。

table_name("os_version")
description("A single row containing the operating system name and version.")
schema([
    Column("name", TEXT, "Distribution or product name"),
    Column("version", TEXT, "Pretty, suitable for presentation, OS version"),
    Column("major", INTEGER, "Major release version"),
    Column("minor", INTEGER, "Minor release version"),
    Column("patch", INTEGER, "Optional patch release"),
    Column("build", TEXT, "Optional build-specific or variant string"),
    Column("platform", TEXT, "OS Platform or ID"),
    Column("platform_like", TEXT, "Closely related platforms"),
    Column("codename", TEXT, "OS version codename"),
    Column("arch", TEXT, "OS Architecture"),
])
extended_schema(WINDOWS, [
    Column("install_date", BIGINT, "The install date of the OS."),
])
extended_schema(LINUX, [
    Column("pid_with_namespace", INTEGER, "Pids that contain a namespace", additional=True, hidden=True),
    Column("mount_namespace_id", TEXT, "Mount namespace id", hidden=True),
])
implementation("system/os_version@genOSVersion")
fuzz_paths([
    "/System/Library/CoreServices/SystemVersion.plist",
])

os_version.table中已经定义了相关信息,表名、描述、属性、附加属性、函数接口位置等;
其C++定义文件是os_version.cpp中的genOSVersion()函数;
os_version的Cpp文件路径位于```osquery/tables/system/[Linux|windows|freebsd]/os_version.cpp。所以其实现代码是在多个平台都进行了实现,本文主要以Linux为例;

1.3. os_version数据来源

1.3.1. Linux系统中的来源

os_version表在Linux中的获取是依靠文件(/etc/os-release)来获取操作系统配置的。
如下是Centos7的配置文件。

NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

1.3.2. Windows系统中的查询

在windows中osquery使用的时WMI进行的查询,获取的时WMI中“Win32_OperatingSystem”的数据,其原理及使用方式可看我其他博文
下图是在本机执行下列语句查询的结果。
SELECT CAPTION,VERSION,INSTALLDATE,OSARCHITECTURE FROM Win32_OperatingSystem

在这里插入图片描述

1.4 os_version.cpp(Linux的实现)

其在源码中的路径为osquery/tables/system/linux/os_version.cpp
如下是os_version.cpp的声明内容:

//存储不同Linux下os-release文件的路径
const std::string kOSRelease = "/etc/os-release";
const std::string kRedhatRelease = "/etc/redhat-release";
const std::string kGentooRelease = "/etc/gentoo-release";

1.4.1 genOSVersion()

分析os_version.cpp的入口函数genOSVersion();

QueryData genOSVersion(QueryContext& context) {
  if (hasNamespaceConstraint(context)) {
    return generateInNamespace(context, "osversion", genOSVersionImpl);
  } else {
    GLOGLogger logger;
    return genOSVersionImpl(context, logger);
  }
}

1.4.2. genOSVersionImpl()

genOSVersionImpl()函数如下:

QueryData genOSVersionImpl(QueryContext& context, Logger& logger) {
    //定义了一个row对象,用于存储输出结果,Row是一个Map结构
    Row r;

  //给r设置默认的值
  r["name"] = "Unknown";
  r["major"] = "0";
  r["minor"] = "0";
  r["patch"] = "0";
  r["platform"] = "posix";
  r["pid_with_namespace"] = "0";

  //判断是否存在os-version
  if (isReadable(kOSRelease)) {
    boost::system::error_code ec;
    // Funtoo has an empty os-release file.
    if (boost::filesystem::file_size(kOSRelease, ec) > 0) {
      genOSRelease(r);
    }
  }

  struct utsname uname_buf {};

  if (uname(&uname_buf) == 0) {
    r["arch"] = TEXT(uname_buf.machine);
  } else {
    LOG(INFO) << "Failed to determine the OS architecture, error " << errno;
  }

  std::string content;
  if (readFile(kRedhatRelease, content).ok()) {
    r["platform"] = "rhel";
    r["platform_like"] = "rhel";
  } else if (readFile(kGentooRelease, content).ok()) {
    r["platform"] = "gentoo";
    r["platform_like"] = "gentoo";
  } else {
    return {r};
  }

  boost::algorithm::trim_all(content);

  // This is an older version of a Redhat-based OS.
  auto rx = std::regex("([\\w+\\s]+) .* ([0-9]+)\\.([0-9]+)\\.?(\\w+)?");
  std::smatch matches;
  for (const auto& line : osquery::split(content, "\n")) {
    if (std::regex_search(line, matches, rx)) {
      r["name"] = matches[1];
      r["major"] = matches[2];
      r["minor"] = matches[3];
      r["patch"] = matches[4];
      if (r["patch"].empty()) {
        r["patch"] = "0";
      }
      break;
    }
  }

  r["version"] = content;

  // No build name.
  r["build"] = "";

  if (r["platform"] == "") {
    // Try to detect CentOS from the name. CentOS6 does not have all of the
    // keys we expect above that platform is typically extracted from.
    if (!boost::algorithm::ifind_first(r["name"], "centos").empty()) {
      r["platform"] = "centos";
    }
  }

  return {r};
}

1.4.3. genOSRelease()

genOSRelease()是针对于os_version文件存放路径为/etc/os-release的处理函数。

void genOSRelease(Row& r) {
  // This will parse /etc/os-version according to the systemd manual.
  std::string content;
  if (!readFile(kOSRelease, content).ok()) {                
    return;
  }

  for (const auto& line : osquery::split(content, "\n")) {
    auto fields = osquery::split(line, '=', 1);
    if (fields.size() != 2) {
      continue;
    }

    auto column = std::ref(kOSReleaseColumns.at("VERSION_CODENAME"));
    if (kOSReleaseColumns.count(fields[0]) != 0) {
      column = std::ref(kOSReleaseColumns.at(fields[0]));
    } else if (fields[0].find("CODENAME") == std::string::npos) {
      // Some distros may attach/invent their own CODENAME field.
      continue;
    }

    r[column] = std::move(fields[1]);
    if (!r.at(column).empty() && r.at(column)[0] == '"') {
      // This is quote-enclosed string, make it pretty!
      r[column] = r[column].substr(1, r.at(column).size() - 2);
    }

    if (column.get() == "_id") {
      auto parts = osquery::split(r.at(column), '.', 2);
      switch (parts.size()) {
      case 3:
        r["patch"] = parts[2];
      case 2:
        r["minor"] = parts[1];
      case 1:
        r["major"] = parts[0];
        break;
      }
    }
  }

  return;
}

1.5 os_version.cpp(Windows的实现)

genOSVersion()函数:其在源码中的路径为:osquery/tables/system/windows/os_version.cpp 通过WMI获取查询结果,在解析出想要的数据,代码是非常的简单易懂的。

QueryData genOSVersion(QueryContext& context) {
  Row r;
  std::string version_string;

  const std::string kWmiQuery =
      "SELECT CAPTION,VERSION,INSTALLDATE,OSARCHITECTURE FROM "
      "Win32_OperatingSystem";
  
  //通过WMI查询获取
  const WmiRequest wmiRequest(kWmiQuery);
  const std::vector<WmiResultItem>& wmiResults = wmiRequest.results();

  if (wmiResults.empty()) {
    return {};
  }

  std::string osName;
  wmiResults[0].GetString("Caption", osName);                   //获取wmiResults[0]中“Caption”的内容给osName
  r["name"] = osName;
  r["codename"] = osName;

  std::string cimInstallDate{""};
  wmiResults[0].GetString("InstallDate", cimInstallDate);
  r["install_date"] = BIGINT(cimDatetimeToUnixtime(cimInstallDate));

  wmiResults[0].GetString("Version", version_string);
  auto version = osquery::split(version_string, ".");

  switch (version.size()) {
  case 3:
    r["build"] = SQL_TEXT(version[2]);
  case 2:
    r["minor"] = INTEGER(version[1]);
  case 1:
    r["major"] = INTEGER(version[0]);
    break;
  default:
    break;
  }

  wmiResults[0].GetString("OSArchitecture", r["arch"]);

  r["platform"] = "windows";
  r["platform_like"] = "windows";
  r["version"] = r["major"] + "." + r["minor"] + "." + r["build"];

  return {r};
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fantongl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值