意义

在网络取证中,获取主机驱动信息对于理解系统的配置和行为至关重要。可列举以下几点:

  • 确定系统组件:驱动程序是操作系统与硬件设备之间的桥梁,获取驱动信息可以帮助识别连接到系统的所有硬件设备,包括网络卡、存储设备、图形卡等 。
  • 分析潜在风险:某些驱动程序可能包含已知的安全漏洞,通过分析驱动信息,取证专家可以识别可能被利用的脆弱点 。
  • 检测恶意软件活动:攻击者有时会安装或修改驱动程序以隐藏其活动或获得对系统的更高权限。审查驱动程序可以帮助发现这些恶意更改 。
  • 系统行为分析:驱动程序影响系统的行为和性能。通过审查驱动程序,可以了解系统在正常和异常情况下的行为模式 。
  • 追踪网络活动:网络驱动程序特别重要,因为它们处理所有网络通信。取证专家可以通过分析网络驱动程序来追踪网络连接和数据流 。
  • 支持法律程序:在法律诉讼中,可能需要提供系统驱动程序的信息作为证据,以证明或反驳与案件相关的技术方面的论点 。
  • 系统恢复和重建:在事件响应中,获取驱动信息有助于重建受损系统的原始状态,这对于恢复服务和防止未来的攻击至关重要 。
  • 兼容性和性能优化:驱动程序信息有助于确定系统组件之间的兼容性问题,并进行必要的调整以优化系统性能 。

windows上实现

定义要查找的进程名称:

1
pe_name = "WinDriver.exe"

这行代码定义了一个字符串 pe_name,其值为 “WinDriver.exe”,即要查找的进程名称。

遍历所有进程:

1
2
3
4
5
6
7
8
9
10
11
12
for process in psutil.process_iter():
try:
name = process.name()
except:
name = ""
try:
if name == pe_name:
setting.log.error("检测到%s已在运行, 正在终止重启" % name)
process.terminate()
except Exception as e:
setting.log.error("终止失败,原因: %s" % str(e))
return

这段代码使用 psutil.process_iter() 遍历所有正在运行的进程。对于每个进程,它尝试获取进程的名称,并检查该名称是否与 pe_name 相匹配。如果匹配,它会尝试终止该进程,并记录错误信息。

获取驱动程序信息:

1
2
pe_path = os.path.join(setting.PROJ_PATH, pe_name)
process = exe_cmd(pe_path)

这两行代码首先构建了 WinDriver.exe 的完整路径,然后使用 exe_cmd 函数执行该程序,以获取驱动程序的信息。

处理驱动程序信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while True:
item = process.stdout.readline().decode("gbk") # type: ignore
if item:
line = item.split("|")
source_data = {
"Name": line[0],
"Path": line[1],
"Address": line[2],
"Description": line[3],
"Company": line[4],
"Version": line[5],
"Type": line[6],
"Md5": line[7]
}
clean_data = get_line(self, source_data, self.display)
data = json.dumps(clean_data, ensure_ascii=False)
write_file(self.file, data)
elif process.poll() is not None:
break

这段代码使用一个无限循环来读取 WinDriver.exe 进程的标准输出。对于每一行输出,它将其分割成多个部分,并将这些部分存储在 source_data 字典中。然后,它调用 get_line 方法处理 source_data,并将处理后的数据转换为 JSON 格式,然后写入到输出文件中。如果 process.poll() 返回非空值,则表示进程已经结束,循环也随之结束。

Linux上实现

执行 lsmod 命令:

1
t = exe_cmd("lsmod").split("\n")

这行代码执行 lsmod 命令,该命令用于列出当前系统中已加载的内核模块。执行结果以字符串形式返回,并通过 split("\n") 方法分割成多行。

遍历输出结果:

1
2
3
4
for line in t[1:]:
if not line:
continue
module, size, depend = line.split(maxsplit=2)

这段代码遍历 lsmod 命令的输出结果,跳过第一行(通常是标题行)。对于每一行,它使用 split(maxsplit=2) 方法将其分割成最多三个部分:模块名、大小和依赖项。

构建源数据字典:

1
2
3
4
5
source_data = {
"Module": module,
"Size": size,
"Depend": depend
}

这行代码将获取到的模块名、大小和依赖项封装成一个字典,其中键对应于 display_list 中的 output 字段。

处理数据并写入文件:

1
2
3
clean_data = get_line(self, source_data, self.display_list)
data = json.dumps(clean_data, ensure_ascii=False)
write_file(self.file, data)

这行代码调用 get_line 方法处理 source_data,并将处理后的数据转换为 JSON 格式,然后写入到输出文件中。

拓展-lsmod

lsmod 是一个用于在 Linux 系统上列出已加载内核模块的命令。内核模块是可加载的代码块,它们可以在系统运行时动态地插入到内核中,以提供额外的功能,比如硬件驱动程序、文件系统支持、网络协议等。

lsmod 命令的输出通常包含以下列:

  • Module: 模块的名称。
  • Size: 模块占用的内存大小(以字节为单位)。
  • Used by: 依赖于该模块的其他模块数量。

lsmod 命令的输出结果类似于以下示例:

1
2
3
4
Module                  Size  Used by
nls_iso8859_1 16384 1
vfat 20480 1
fat 73728 1 vfat

在这个示例中,nls_iso8859_1vfatfat 是已加载的内核模块名称,Size 列显示了每个模块占用的内存大小,Used by 列显示了依赖于该模块的其他模块数量。