乐于分享
好东西不私藏

跨平台系统信息获取库libsigar源码分析系列(五)

跨平台系统信息获取库libsigar源码分析系列(五)

官网:http://securitytech.cc

源码分析mettle后门工具学习 所使用的依赖库

官网:http://securitytech.cc

libsigar NetBSD 平台源码分析

概述

libsigar 在 NetBSD 平台的实现主要通过 sysctl 系统调用和 kvm 库获取系统信息。NetBSD 是一个专注于设计简洁性和可移植性的开源 UNIX 操作系统。

核心架构

sigar_t 结构体

NetBSD 与 FreeBSD 共享相同的头文件 sigar_os.h (sigar_os.h:54-75)。

  1. structsigar_t{
  2.     SIGAR_T_BASE;
  3. int pagesize;// 页面大小
  4. time_t last_getprocs;// 最后获取进程时间
  5. sigar_pid_t last_pid;// 最后处理的 PID
  6. bsd_pinfo_t*pinfo;// 进程信息缓冲区
  7. int lcpu;// 每个物理 CPU 的逻辑 CPU 数
  8. size_t argmax;// 参数最大长度
  9. kvm_t*kmem;// kvm 句柄
  10. unsignedlong koffsets[KOFFSET_MAX];// 内核符号偏移量
  11. int proc_mounted;// /proc 是否挂载
  12. };

内核符号偏移量 (sigar_os.h:38-46)

  1. enum{
  2.     KOFFSET_CPUINFO,// CPU 时间统计
  3.     KOFFSET_VMMETER,// 虚拟内存统计
  4.     KOFFSET_TCPSTAT,// TCP 统计
  5.     KOFFSET_TCBTABLE,// TCP 控制块表
  6.     KOFFSET_MAX
  7. };

进程信息类型 (sigar_os.h:49-52)

  1. #if defined(__OpenBSD__) || defined(__NetBSD__)
  2. typedefstruct kinfo_proc2 bsd_pinfo_t;
  3. #else
  4. typedefstruct kinfo_proc bsd_pinfo_t;
  5. #endif

NetBSD 使用 kinfo_proc2 结构,这是 NetBSD 特有的扩展进程信息结构。

核心技术

1. sysctl 系统调用

NetBSD 的 sysctl 系统调用类似于 FreeBSD,提供了统一的内核信息访问接口。

基本用法

  1. int mib[2];
  2. size_t len;
  3. mib[0]= CTL_HW;
  4. mib[1]= HW_PAGESIZE;
  5. len =sizeof(pagesize);
  6. sysctl(mib,2,&pagesize,&len, NULL,0);

2. kvm 库

NetBSD 的 kvm 库提供了访问内核内存和数据的能力。

初始化

  1. (*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);

读取内核数据

  1. staticint kread(sigar_t*sigar,void*data,int size,long offset)
  2. {
  3. if(!sigar->kmem){
  4. return SIGAR_EPERM_KMEM;
  5. }
  6. if(kvm_read(sigar->kmem, offset, data, size)!= size){
  7. return errno;
  8. }
  9. return SIGAR_OK;
  10. }

3. 初始化流程

  1. int sigar_os_open(sigar_t**sigar)
  2. {
  3. int mib[2];
  4. int ncpu;
  5. size_t len;
  6. struct timeval boottime;
  7. struct stat sb;
  8. // 1. 获取 CPU 数量
  9.     len =sizeof(ncpu);
  10.     mib[0]= CTL_HW;
  11.     mib[1]= HW_NCPU;
  12.     sysctl(mib,2,&ncpu,&len, NULL,0);
  13. // 2. 获取启动时间
  14.     len =sizeof(boottime);
  15.     mib[0]= CTL_KERN;
  16.     mib[1]= KERN_BOOTTIME;
  17.     sysctl(mib,2,&boottime,&len, NULL,0);
  18. // 3. 打开 kvm
  19. *sigar = malloc(sizeof(**sigar));
  20. (*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
  21. // 4. 检查 /proc 是否挂载
  22. if(stat("/proc/curproc",&sb)<0){
  23. (*sigar)->proc_mounted =0;
  24. }
  25. else{
  26. (*sigar)->proc_mounted =1;
  27. }
  28. // 5. 获取内核符号偏移量
  29.     get_koffsets(*sigar);
  30. // 6. 初始化其他字段
  31. (*sigar)->ncpu = ncpu;
  32. (*sigar)->pagesize = getpagesize();
  33. (*sigar)->ticks = sysconf(_SC_CLK_TCK);
  34. return SIGAR_OK;
  35. }

核心功能模块

1. 内存监控

NetBSD 的内存监控与 FreeBSD 类似,使用 sysctl 获取物理内存和虚拟内存统计。

内存信息获取

  1. int sigar_mem_get(sigar_t*sigar,sigar_mem_t*mem)
  2. {
  3. sigar_uint64_t kern =0;
  4. unsignedlong mem_total;
  5. struct vmmeter vmstat;
  6. int mib[2];
  7. size_t len;
  8. // 获取页面大小
  9.     mib[0]= CTL_HW;
  10.     mib[1]= HW_PAGESIZE;
  11.     len =sizeof(sigar->pagesize);
  12.     sysctl(mib,2,&sigar->pagesize,&len, NULL,0);
  13. // 获取物理内存总量
  14.     mib[1]= HW_PHYSMEM;
  15.     len =sizeof(mem_total);
  16.     sysctl(mib,2,&mem_total,&len, NULL,0);
  17.     mem->total = mem_total;
  18. // 获取虚拟内存统计
  19. if((status = sigar_vmstat(sigar,&vmstat))== SIGAR_OK){
  20.         kern = vmstat.v_cache_count + vmstat.v_inactive_count;
  21.         kern *= sigar->pagesize;
  22.         mem->free = vmstat.v_free_count;
  23.         mem->free *= sigar->pagesize;
  24. }
  25.     mem->used = mem->total - mem->free;
  26.     mem->actual_free = mem->free + kern;
  27.     mem->actual_used = mem->used - kern;
  28.     sigar_mem_calc_ram(sigar, mem);
  29. return SIGAR_OK;
  30. }

2. CPU 监控

NetBSD 的 CPU 统计使用 sysctl 或 kvm 读取内核的 cp_time 数组。

  1. int sigar_cpu_get(sigar_t*sigar,sigar_cpu_t*cpu)
  2. {
  3. int status;
  4. cp_time_t cp_time[CPUSTATES];
  5. size_t size =sizeof(cp_time);
  6. // 优先使用 sysctl
  7. if(sysctlbyname("kern.cp_time",&cp_time,&size, NULL,0)==-1){
  8. // 回退到 kmem
  9.         status = kread(sigar,&cp_time,sizeof(cp_time),
  10.                        sigar->koffsets[KOFFSET_CPUINFO]);
  11. }
  12. else{
  13.         status = SIGAR_OK;
  14. }
  15. if(status != SIGAR_OK){
  16. return status;
  17. }
  18.     cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
  19.     cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
  20.     cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
  21.     cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
  22.     cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
  23. return SIGAR_OK;
  24. }

3. 进程监控

NetBSD 使用 kvm_getproc2 获取进程列表,这是 NetBSD 特有的扩展函数。

  1. int sigar_os_proc_list_get(sigar_t*sigar,sigar_proc_list_t*proclist)
  2. {
  3. int count, i;
  4. struct kinfo_proc2 *pinfo;
  5. // 获取所有进程 (NetBSD 特定接口)
  6.     pinfo = kvm_getproc2(sigar->kmem, KERN_PROC_ALL,0,
  7. sizeof(struct kinfo_proc2),&count);
  8. for(i=0; i<count; i++){
  9.         proclist->data[proclist->number++]= pinfo[i].p_pid;
  10. }
  11. return SIGAR_OK;
  12. }

4. 网络监控

NetBSD 的网络监控通过 sysctl 和内核结构实现。

网络接口统计

  1. int sigar_net_interface_stat_get(sigar_t*sigar,constchar*name,
  2. sigar_net_interface_stat_t*ifstat)
  3. {
  4. int mib[6];
  5. struct if_msghdr *ifm;
  6. struct if_data ifdata;
  7. char*buf,*lim,*next;
  8. size_t len;
  9.     mib[0]= CTL_NET;
  10.     mib[1]= PF_ROUTE;
  11.     mib[2]=0;
  12.     mib[3]= AF_INET;
  13.     mib[4]= NET_RT_IFLIST;
  14.     mib[5]=0;
  15. // 获取接口列表
  16. if(sysctl(mib,6, NULL,&len, NULL,0)<0){
  17. return errno;
  18. }
  19.     buf = malloc(len);
  20. if(sysctl(mib,6, buf,&len, NULL,0)<0){
  21.         free(buf);
  22. return errno;
  23. }
  24.     lim = buf + len;
  25. for(next = buf; next < lim; next += ifm->ifm_msglen){
  26.         ifm =(struct if_msghdr *)next;
  27. if(ifm->ifm_type == RTM_IFINFO){
  28.             ifdata = ifm->ifm_data;
  29. if(strcmp(ifm->ifm_name, name)==0){
  30.                 ifstat->rx_packets = ifdata.ifi_ipackets;
  31.                 ifstat->tx_packets = ifdata.ifi_opackets;
  32.                 ifstat->rx_bytes = ifdata.ifi_ibytes;
  33.                 ifstat->tx_bytes = ifdata.ifi_obytes;
  34.                 ifstat->rx_errors = ifdata.ifi_ierrors;
  35.                 ifstat->tx_errors = ifdata.ifi_oerrors;
  36. break;
  37. }
  38. }
  39. }
  40.     free(buf);
  41. return SIGAR_OK;
  42. }

性能优化

1. sysctl 优先使用

优先使用 sysctl 获取信息,只有在必要时才使用 kvm

2. 进程信息批量获取

使用 kvm_getproc2 一次性获取所有进程信息。

特殊技术

1. kinfo_proc2 结构

NetBSD 使用扩展的进程信息结构 kinfo_proc2,包含更多字段。

  1. struct kinfo_proc2 {
  2. struct proc kp_proc;
  3. struct eproc eproc;
  4. // 更多 NetBSD 特定字段
  5. };

2. 进程状态映射

NetBSD 进程状态到通用状态的映射。

  1. #define PIDL_IDLE      'I'
  2. #define PIDL_RUN       'R'
  3. #define PIDL_SLEEP     'S'
  4. #define PIDL_STOP      'T'
  5. #define PIDL_ZOMBIE    'Z'
  6. #define PIDL_DEAD      'X'

技术亮点

1. 设计简洁性

NetBSD 以设计简洁著称,代码结构清晰易懂。

2. 可移植性

NetBSD 的代码具有良好的可移植性,易于在其他平台上运行。

3. 扩展性

使用 kinfo_proc2 等扩展结构提供更多功能。

限制和挑战

1. kmem 权限

访问 /dev/kmem 需要 root 权限。

2. /proc 可选

NetBSD 的 /proc 文件系统是可选的。

3. 文档不足

NetBSD 的某些 API 文档较少。

总结

libsigar NetBSD 实现充分利用了 NetBSD 的 sysctl、 kvm 库和扩展的进程信息结构,提供了全面的系统监控功能。其设计特点包括:

  1. 简洁设计: 代码结构清晰,易于理解和维护
  2. 扩展结构: 使用 kinfo_proc2 等扩展结构提供更多信息
  3. 双模式: 同时支持 sysctl 和 kvm 两种方式
  4. 可移植性: 良好的可移植性设计

这种实现方式展示了 NetBSD 系统架构的特点,强调了简洁性和可移植性。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 跨平台系统信息获取库libsigar源码分析系列(五)

猜你喜欢

  • 暂无文章