乐于分享
好东西不私藏

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

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

官网:http://securitytech.cc

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

官网:http://securitytech.cc

HPUX 分支源码分析

概述

HPUX (HP-UX) 是惠普公司开发的专有 UNIX 操作系统,运行在 HP PA-RISC 和 Itanium 架构的服务器上。libsigar 在 HPUX 平台的实现主要通过 pstat 系列系统调用获取系统信息,同时结合 MIB (Management Information Base) 接口获取网络统计数据。

核心架构

1. sigar_t 结构体扩展

  1. structsigar_t{
  2.     SIGAR_T_BASE;// 基础结构
  3. struct pst_static pstatic;// 静态系统信息 (不随系统运行变化)
  4. time_t last_getprocs;// 最后一次获取进程信息的时间
  5. sigar_pid_t last_pid;// 最后查询的 PID
  6. struct pst_status *pinfo;// 进程状态信息缓存
  7. int mib;// MIB 文件描述符
  8. };

2. 核心数据结构

pst_static – 静态系统信息

在系统初始化时一次性获取,包含:

  • physical_memory: 物理内存页数
  • page_size: 页面大小
  • boot_time: 系统启动时间

pst_dynamic – 动态系统信息

  • psd_free: 可用内存页数
  • psd_proc_cnt: CPU 数量
  • psd_cpu_time[]: CPU 时间统计数组
  • psd_avg_1_min/5_min/15_min: 负载平均值

pst_status – 进程状态信息

  • pst_pid: 进程 ID
  • pst_ppid: 父进程 ID
  • pst_uid/pst_euid: 用户 ID
  • pst_gid/pst_egid: 组 ID
  • pst_utime/pst_stime: CPU 使用时间
  • pst_start: 启动时间
  • pst_nlwps: 线程数
  • pst_stat: 进程状态

核心技术

1. pstat 系统调用系列

HPUX 提供了一系列 pstat 函数用于获取系统统计信息:

函数
用途
数据结构
pstat_getstatic
静态系统信息
pst_static
pstat_getdynamic
动态系统信息
pst_dynamic
pstat_getprocessor
CPU 信息
pst_processor
pstat_getproc
进程信息
pst_status
pstat_getvminfo
虚拟内存信息
pst_vminfo
pstat_getswap
交换空间信息
pst_swapinfo
pstat_getfile2
打开的文件描述符
pst_fileinfo2
pstat_getpathname
文件路径
char[]
pstat_getlv
逻辑卷信息
pst_lvinfo

2. MIB (Management Information Base) 接口

用于获取网络统计信息,通过 /dev/ip 设备访问:

  1. int mib = open_mib("/dev/ip", O_RDONLY,0,0);
  2. // 获取网络接口数量
  3. int count;
  4. struct nmparms parms;
  5. parms.objid = ID_ifNumber;
  6. parms.buffer =&count;
  7. parms.len =&len;
  8. get_mib_info(mib,&parms);
  9. // 获取路由表
  10. mib_ipRouteEnt *routes;
  11. parms.objid = ID_ipRouteTable;
  12. parms.buffer = routes;
  13. parms.len =&len;

3. 架构兼容性处理

PA-RISC vs Itanium

  1. #ifdef _PSTAT64
  2. typedefint64_tpstat_int_t;// 64 位 Itanium
  3. #else
  4. typedefint32_tpstat_int_t;// 32 位 PA-RISC
  5. #endif
  6. #ifdef __ia64__
  7.     _lwp_info(&info);// LWP 信息 (仅 PA-RISC)
  8. #else
  9. return SIGAR_ENOTIMPL;// Itanium 不支持 LWP
  10. #endif

CPU 时间映射

HPUX 将 CPU 时间分为多个类别:

  1. cpu->user  = cpu_time[CP_USER];
  2. cpu->sys   = cpu_time[CP_SYS]+ cpu_time[CP_SSYS];
  3. cpu->nice  = cpu_time[CP_NICE];
  4. cpu->idle  = cpu_time[CP_IDLE];
  5. cpu->wait  = cpu_time[CP_SWAIT]+ cpu_time[CP_BLOCK];
  6. cpu->irq   = cpu_time[CP_INTR];

4. 进程信息缓存

通过 60 秒缓存减少 pstat_getproc 调用:

  1. staticint sigar_pstat_getproc(sigar_t*sigar,sigar_pid_t pid)
  2. {
  3. time_t timenow = time(NULL);
  4. if(sigar->last_pid == pid){
  5. if((timenow - sigar->last_getprocs)< SIGAR_LAST_PROC_EXPIRE){
  6. return SIGAR_OK;// 使用缓存
  7. }
  8. }
  9.     sigar->last_pid = pid;
  10.     sigar->last_getprocs = timenow;
  11. return pstat_getproc(sigar->pinfo,sizeof(*sigar->pinfo),0, pid);
  12. }

核心功能模块

1. 内存监控

  1. int sigar_mem_get(sigar_t*sigar,sigar_mem_t*mem)
  2. {
  3. struct pst_dynamic stats;
  4. struct pst_vminfo vminfo;
  5. // 物理内存总量
  6.     mem->total = sigar->pstatic.physical_memory * pagesize;
  7. // 动态内存统计
  8.     pstat_getdynamic(&stats,sizeof(stats),1,0);
  9.     mem->free = stats.psd_free * pagesize;
  10.     mem->used = mem->total - mem->free;
  11. // 内核动态内存
  12.     pstat_getvminfo(&vminfo,sizeof(vminfo),1,0);
  13.     kern = vminfo.psv_kern_dynmem * pagesize;
  14.     mem->actual_free = mem->free + kern;
  15.     mem->actual_used = mem->used - kern;
  16. }

2. 交换空间监控

  1. int sigar_swap_get(sigar_t*sigar,sigar_swap_t*swap)
  2. {
  3. struct pst_swapinfo swapinfo;
  4. int i =0;
  5. // 遍历所有交换设备
  6. while(pstat_getswap(&swapinfo,sizeof(swapinfo),1, i++)>0){
  7. // 转换为字节 (nfpgs 是 512 字节块)
  8.         swapinfo.pss_nfpgs *=4;
  9. // 累计交换空间
  10.         swap->total += swapinfo.pss_nblksenabled;
  11.         swap->free  += swapinfo.pss_nfpgs;
  12. }
  13. // 页换入/换出统计
  14.     pstat_getvminfo(&vminfo,sizeof(vminfo),1,0);
  15.     swap->page_in = vminfo.psv_spgin;
  16.     swap->page_out = vminfo.psv_spgout;
  17. }

3. CPU 监控

总体 CPU 统计

  1. int sigar_cpu_get(sigar_t*sigar,sigar_cpu_t*cpu)
  2. {
  3. struct pst_dynamic stats;
  4.     pstat_getdynamic(&stats,sizeof(stats),1,0);
  5.     sigar->ncpu = stats.psd_proc_cnt;
  6.     get_cpu_metrics(sigar, cpu, stats.psd_cpu_time);
  7. }

每个 CPU 统计

  1. int sigar_cpu_list_get(sigar_t*sigar,sigar_cpu_list_t*cpulist)
  2. {
  3. for(=0; i < sigar->ncpu; i++){
  4. struct pst_processor proc;
  5. if(pstat_getprocessor(&proc,sizeof(proc),1, i)<0){
  6. continue;
  7. }
  8.         get_cpu_metrics(sigar, cpu, proc.psp_cpu_time);
  9. }
  10. }

CPU 信息

  1. int sigar_cpu_info_list_get(sigar_t*sigar,sigar_cpu_info_list_t*cpu_infos)
  2. {
  3. struct pst_processor proc;
  4. // CPU 频率计算 (HPUX 11.31+)
  5. #ifdef PSP_MAX_CACHE_LEVELS
  6.         info->mhz = proc.psp_cpu_frequency /1000000;
  7. #else
  8.         info->mhz = ticks * proc.psp_iticksperclktick /1000000;
  9. #endif
  10. // 架构标识
  11. #ifdef __ia64__
  12.         SIGAR_SSTRCPY(info->vendor,"Intel");
  13.         SIGAR_SSTRCPY(info->model,"Itanium");
  14. #else
  15.         SIGAR_SSTRCPY(info->vendor,"HP");
  16.         SIGAR_SSTRCPY(info->model,"PA RISC");
  17. #endif
  18. }

4. 进程监控

进程列表

  1. int sigar_os_proc_list_get(sigar_t*sigar,sigar_proc_list_t*proclist)
  2. {
  3. int idx =0;
  4. struct pst_status proctab[PROC_ELTS];
  5. // 批量获取进程 (每次 16 个)
  6. while((num = pstat_getproc(proctab,sizeof(proctab[0]),
  7.                                 PROC_ELTS, idx))>0)
  8. {
  9. for(=0; i < num; i++){
  10.             SIGAR_PROC_LIST_GROW(proclist);
  11.             proclist->data[proclist->number++]= proctab[i].pst_pid;
  12. }
  13.         idx = proctab[num-1].pst_idx +1;// 下一次查询的索引
  14. }
  15. }

进程内存

  1. int sigar_proc_mem_get(sigar_t*sigar,sigar_pid_t pid,sigar_proc_mem_t*procmem)
  2. {
  3. struct pst_status *pinfo = sigar->pinfo;
  4. // 虚拟内存大小 = text + data + stack + shm + mmap + u-area + io
  5.     procmem->size =
  6.         pinfo->pst_vtsize +// text
  7.         pinfo->pst_vdsize +// data
  8.         pinfo->pst_vssize +// stack
  9.         pinfo->pst_vshmsize +// shared memory
  10.         pinfo->pst_vmmsize +// mem-mapped files
  11.         pinfo->pst_vusize +// U-Area & K-Stack
  12.         pinfo->pst_viosize;// I/O dev mapping
  13.     procmem->resident = pinfo->pst_rssize * pagesize;
  14.     procmem->share = pinfo->pst_vshmsize * pagesize;
  15.     procmem->minor_faults = pinfo->pst_minorfaults;
  16.     procmem->major_faults = pinfo->pst_majorfaults;
  17. }

进程状态

  1. int sigar_proc_state_get(sigar_t*sigar,sigar_pid_t pid,sigar_proc_state_t*procstate)
  2. {
  3. struct pst_status *pinfo = sigar->pinfo;
  4.     procstate->name = pinfo->pst_ucomm;
  5.     procstate->ppid = pinfo->pst_ppid;
  6.     procstate->tty = makedev(pinfo->pst_term.psd_major,
  7.                             pinfo->pst_term.psd_minor);
  8.     procstate->priority = pinfo->pst_pri;
  9.     procstate->nice = pinfo->pst_nice;
  10.     procstate->threads = pinfo->pst_nlwps;
  11.     procstate->processor = pinfo->pst_procnum;
  12. // 状态映射
  13. switch(pinfo->pst_stat){
  14. case PS_SLEEP:  procstate->state ='S';break;
  15. case PS_RUN:    procstate->state ='R';break;
  16. case PS_STOP:   procstate->state ='T';break;
  17. case PS_ZOMBIE: procstate->state ='Z';break;
  18. case PS_IDLE:   procstate->state ='D';break;
  19. }
  20. }

进程参数 (命令行)

  1. int sigar_os_proc_args_get(sigar_t*sigar,sigar_pid_t pid,sigar_proc_args_t*procargs)
  2. {
  3. #ifdef PSTAT_GETCOMMANDLINE  // HPUX 11i v2+
  4. char buf[1024];// 内核限制
  5. if(pstat_getcommandline(buf,sizeof(buf),sizeof(buf[0]), pid)==-1){
  6. return errno;
  7. }
  8.         args = buf;
  9. #else
  10. struct pst_status status;
  11.         pstat_getproc(&status,sizeof(status),0, pid);
  12.         args = status.pst_cmd;// 旧版本方法
  13. #endif
  14. // 解析空格分隔的参数
  15. while(*args &&(arg = sigar_getword(&args,' '))){
  16.         SIGAR_PROC_ARGS_GROW(procargs);
  17.         procargs->data[procargs->number++]= arg;
  18. }
  19. }

进程文件描述符

  1. int sigar_proc_fd_get(sigar_t*sigar,sigar_pid_t pid,sigar_proc_fd_t*procfd)
  2. {
  3. struct pst_status status;
  4. int idx =0, n;
  5. struct pst_fileinfo2 psf[16];
  6.     pstat_getproc(&status,sizeof(status),0, pid);
  7. // HPUX 11.31 移除了已弃用的 pstat_getfile,使用 pstat_getfile2
  8. while((= pstat_getfile2(psf,sizeof(psf[0]),
  9. sizeof(psf)/sizeof(psf[0]),
  10.                                idx, pid))>0)
  11. {
  12.         procfd->total += n;
  13.         idx = psf[n-1].psf_fd +1;
  14. }
  15. }

进程可执行文件路径

  1. int sigar_proc_exe_get(sigar_t*sigar,sigar_pid_t pid,sigar_proc_exe_t*procexe)
  2. {
  3. #ifdef __pst_fid  // HPUX 11.11+
  4. struct pst_status status;
  5.         pstat_getproc(&status,sizeof(status),0, pid);
  6. // 工作目录
  7.         pstat_getpathname(procexe->cwd,sizeof(procexe->cwd),
  8. &status.pst_fid_cdir);
  9. // 可执行文件
  10.         pstat_getpathname(procexe->name,sizeof(procexe->name),
  11. &status.pst_fid_text);
  12. // 根目录
  13.         pstat_getpathname(procexe->root,sizeof(procexe->root),
  14. &status.pst_fid_rdir);
  15.         procexe->arch = sigar_elf_file_guess_arch(sigar, procexe->name);
  16. #else
  17. return SIGAR_ENOTIMPL;// HPUX 11.00 不支持
  18. #endif
  19. }

线程 CPU 使用 (仅 PA-RISC)

  1. int sigar_thread_cpu_get(sigar_t*sigar,sigar_uint64_t id,sigar_thread_cpu_t*cpu)
  2. {
  3. #ifdef __ia64__
  4. return SIGAR_ENOTIMPL;// Itanium 不支持
  5. #else
  6. struct lwpinfo info;
  7. if(id !=0){
  8. return SIGAR_ENOTIMPL;// 仅支持主线程
  9. }
  10.         _lwp_info(&info);
  11.         cpu->user  = TIME_NSEC(info.lwp_utime);
  12.         cpu->sys   = TIME_NSEC(info.lwp_stime);
  13.         cpu->total = cpu->user + cpu->sys;
  14. #endif
  15. }

5. 文件系统监控

文件系统列表

  1. int sigar_file_system_list_get(sigar_t*sigar,sigar_file_system_list_t*fslist)
  2. {
  3. FILE*fp = setmntent(MNT_MNTTAB,"r");
  4. while((ent = getmntent(fp))){
  5. // 跳过 swap (devname == "...")
  6. if(strEQ(ent->mnt_type,"swap")){
  7. continue;
  8. }
  9.         fsp->dir_name = ent->mnt_dir;
  10.         fsp->dev_name = ent->mnt_fsname;
  11.         fsp->sys_type_name = ent->mnt_type;
  12.         fsp->options = ent->mnt_opts;
  13. }
  14.     endmntent(fp);
  15. }

文件系统使用情况

  1. int sigar_file_system_usage_get(sigar_t*sigar,constchar*dirname,
  2. sigar_file_system_usage_t*fsusage)
  3. {
  4.     sigar_statvfs(sigar, dirname, fsusage);
  5. // 从逻辑卷获取磁盘 I/O 统计
  6. if(stat(dirname,&sb)==0){
  7. struct pst_lvinfo lv;
  8. struct stat devsb;
  9. char*devname;
  10.         ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
  11. if(stat(ent->value,&devsb)==0){
  12.             pstat_getlv(&lv,sizeof(lv),0,(int)devsb.st_rdev);
  13.             fsusage->disk.reads  = lv.psl_rxfer;
  14.             fsusage->disk.writes = lv.psl_wxfer;
  15.             fsusage->disk.read_bytes  = lv.psl_rcount;
  16.             fsusage->disk.write_bytes = lv.psl_wcount;
  17. }
  18. }
  19. }

文件系统类型

  1. int sigar_os_fs_type_get(sigar_file_system_t*fsp)
  2. {
  3. switch(*fsp->sys_type_name){
  4. case'h':
  5. if(strEQ(fsp->sys_type_name,"hfs")){
  6.                 fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
  7. }
  8. break;
  9. case'c':
  10. if(strEQ(fsp->sys_type_name,"cdfs")){
  11.                 fsp->type = SIGAR_FSTYPE_CDROM;
  12. }
  13. break;
  14. }
  15. }

6. 网络监控

网络接口统计

  1. int sigar_net_interface_stat_get(sigar_t*sigar,constchar*name,
  2. sigar_net_interface_stat_t*ifstat)
  3. {
  4.     mib_ifEntry mib;
  5.     get_mib_ifstat(sigar, name,&mib);
  6.     ifstat->rx_bytes    = mib.ifInOctets;
  7.     ifstat->rx_packets  = mib.ifInUcastPkts + mib.ifInNUcastPkts;
  8.     ifstat->rx_errors   = mib.ifInErrors;
  9.     ifstat->rx_dropped  = mib.ifInDiscards;
  10.     ifstat->tx_bytes    = mib.ifOutOctets;
  11.     ifstat->tx_packets  = mib.ifOutUcastPkts + mib.ifOutNUcastPkts;
  12.     ifstat->tx_errors   = mib.ifOutErrors;
  13.     ifstat->tx_dropped  = mib.ifOutDiscards;
  14.     ifstat->speed       = mib.ifSpeed;
  15. }

路由表

  1. int sigar_net_route_list_get(sigar_t*sigar,sigar_net_route_list_t*routelist)
  2. {
  3.     mib_ipRouteEnt *routes;
  4. // 获取路由表数量
  5.     parms.objid = ID_ipRouteNumEnt;
  6.     get_mib_info(sigar,&parms);
  7. // 获取路由表
  8.     parms.objid = ID_ipRouteTable;
  9.     parms.buffer = routes;
  10.     get_mib_info(sigar,&parms);
  11. for(=0; i < count; i++){
  12.         sigar_net_address_set(route->destination, routes[i].Dest);
  13.         sigar_net_address_set(route->mask, routes[i].Mask);
  14.         sigar_net_address_set(route->gateway, routes[i].NextHop);
  15.         sigar_if_indextoname(sigar, route->ifname, routes[i].IfIndex);
  16.         route->flags = SIGAR_RTF_UP;
  17. if(routes[i].Dest==0&& routes[i].Mask==0){
  18.             route->flags |= SIGAR_RTF_GATEWAY;
  19. }
  20. }
  21. }

UDP 监听连接

  1. staticint net_conn_get_udp_listen(sigar_net_connection_walker_t*walker)
  2. {
  3.     mib_udpLsnEnt *entries;
  4. // 获取 UDP 监听连接数量
  5.     parms.objid = ID_udpLsnNumEnt;
  6.     get_mib_info(sigar,&parms);
  7. // 获取 UDP 监听连接列表
  8.     parms.objid = ID_udpLsnTable;
  9.     parms.buffer = entries;
  10.     get_mib_info(sigar,&parms);
  11. }

IPv6 接口配置

  1. int sigar_net_interface_ipv6_config_get(sigar_t*sigar,constchar*name,
  2. sigar_net_interface_config_t*ifconfig)
  3. {
  4. int sock = socket(AF_INET6, SOCK_DGRAM,0);
  5. struct if_laddrreq iflr;
  6.     SIGAR_SSTRCPY(iflr.iflr_name, name);
  7. // 获取 IPv6 地址
  8.     ioctl(sock, SIOCGLIFADDR,&iflr);
  9. struct in6_addr *addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr);
  10.     sigar_net_address6_set(ifconfig->address6, addr);
  11. // 获取子网掩码
  12.     ioctl(sock, SIOCGLIFNETMASK,&iflr);
  13.     ifconfig->prefix6_length =10;// XXX
  14.     close(sock);
  15. }

技术亮点

1. pstat 统一接口

  • 单一函数家族提供所有系统信息
  • 避免访问 /proc 文件系统
  • 批量操作减少系统调用

2. 架构自适应

  • _PSTAT64 宏检测 32/64 位
  • IA64 和 PA-RISC 分支处理
  • 版本特定的 API 检测

3. 双模式网络统计

  • MIB 接口提供高效网络统计
  • Socket ioctl 提供补充信息
  • 避免解析 /proc/net

4. 逻辑卷集成

  • pstat_getlv 获取磁盘 I/O
  • 直接与文件系统关联
  • 提供读写字节数

5. 批量进程获取

  • PROC_ELTS 控制批量大小
  • 减少 pstat_getproc 调用
  • 使用索引遍历

6. 版本兼容性

  • HPUX 11.00 基础支持
  • HPUX 11.11 文件路径支持
  • HPUX 11.31 CPU 频率支持

未实现功能

以下功能在 HPUX 上未实现:

  • sigar_system_stats_get – 系统统计
  • sigar_proc_env_get – 进程环境变量
  • sigar_proc_modules_get – 进程模块
  • sigar_disk_usage_get – 磁盘使用情况
  • sigar_sys_info_get_uuid – 系统 UUID

总结

HPUX 分支的实现特点:

  1. 统一的 pstat 接口 – 所有系统统计通过 pstat 系列函数获取
  2. MIB 网络统计 – 使用 MIB 接口获取网络信息
  3. 架构兼容 – 支持 PA-RISC 和 Itanium 两种架构
  4. 版本适配 – 针对不同 HPUX 版本的 API 差异处理
  5. 高效缓存 – 进程信息缓存减少系统调用
  6. 逻辑卷集成 – 文件系统和磁盘 I/O 统计关联

HPUX 作为专有 UNIX 系统,其独特的 pstat 接口和 MIB 系统使得实现相对独立且高效。

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

猜你喜欢

  • 暂无文章