返回

从正在运行的进程中检查加载的共享库

Linux

如何在运行时检查给定进程加载了哪些共享库?

问题陈述

获取正在运行进程加载的库信息是一个常见的任务。但是,使用传统工具(如readelf或ldd)可能会遗漏通过dlopen动态加载的库。本文将探索如何从正在运行的进程中提取此信息。

解决方案

有三种主要方法可以检查进程加载的共享库:

1. 使用procfs

procfs是一个伪文件系统,提供有关正在运行进程的信息。要使用procfs:

  • 打开/proc/[pid]/maps文件。 此文件包含进程使用的所有内存映射。
  • 查找包含"r-xp"标志的行。 这些行表示可执行代码段,通常对应于共享库。
  • 提取"path"字段。 它包含加载的库的路径。

2. 使用ptrace

ptrace允许一个进程检查和控制另一个进程。要使用ptrace:

  • 附加到目标进程。
  • 获取目标进程的寄存器。
  • 查找动态链接器寄存器。 它指向动态链接器结构。
  • 解析动态链接器结构。 以获取有关加载的共享库的信息。

3. 使用系统工具

某些系统工具可以提供有关共享库的信息:

  • lsof: 列出打开的文件和套接字。
  • truss: 跟踪系统调用。
  • dtruss: 仅跟踪动态链接库调用。

代码示例

使用procfs:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
    return EXIT_FAILURE;
  }

  int pid = atoi(argv[1]);
  char path[256];
  snprintf(path, sizeof(path), "/proc/%d/maps", pid);

  FILE *f = fopen(path, "r");
  if (f == NULL) {
    perror("fopen");
    return EXIT_FAILURE;
  }

  char line[1024];
  while (fgets(line, sizeof(line), f)) {
    if (strstr(line, "r-xp") != NULL) {
      char *path = strstr(line, "path: ");
      if (path != NULL) {
        printf("%s", path + 6);
      }
    }
  }

  fclose(f);
  return EXIT_SUCCESS;
}

使用ptrace:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/user.h>

int main(int argc, char *argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
    return EXIT_FAILURE;
  }

  int pid = atoi(argv[1]);
  struct user_regs_struct regs;

  if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
    perror("ptrace");
    return EXIT_FAILURE;
  }

  if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) {
    perror("ptrace");
    return EXIT_FAILURE;
  }

  ElfW(Dyn) *dyn = (ElfW(Dyn) *)regs.r[PT_LD_0];
  while (dyn->d_tag != DT_NULL) {
    if (dyn->d_tag == DT_NEEDED) {
      printf("%s\n", (char *)dyn->d_un.d_val);
    }
    dyn++;
  }

  if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
    perror("ptrace");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

注意: 检查共享库可能需要root权限。

结论

本文介绍了三种检查正在运行的进程加载了哪些共享库的方法。这些方法提供了获取进程内存使用情况的宝贵见解,可以用于调试、安全分析和其他开发任务。

常见问题解答

1. 这些方法是否适用于所有平台?

这些方法主要适用于Linux和类Unix系统。其他平台可能有不同的机制来管理共享库。

2. 检查共享库的性能影响是什么?

procfs和ptrace方法可能对性能产生轻微影响。使用系统工具通常更快。

3. 我可以过滤特定库吗?

是的,可以使用grep或其他工具对输出进行过滤。例如:

cat /proc/[pid]/maps | grep 'lib.*\.so'

4. 这些方法可以用来检测恶意共享库吗?

是的,通过检查加载的库是否来自可信来源,可以帮助识别恶意共享库。

5. 我可以修改进程加载的共享库吗?

是的,可以使用dlopen和dlsym等函数动态加载和卸载共享库。