libeio库源码分析系列(六)

admin 2026-03-10 02:08:06 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档深入分析libeio库源码请求类型枚举,详述基础I/O、文件操作等功能在eio_execute中的系统调用映射。通过代码与参数表解析内部机制、性能特征及安全设计,为理解mettle后门工具依赖库提供参考,具备较高的代码审计价值。 综合评分: 86 文章分类: 代码审计,逆向分析,二进制安全


cover_image

libeio库源码分析系列(六)

原创

haidragon haidragon

安全狗的自我修养

2026年3月9日 12:29 湖南

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

官网:http://securitytech.cc

#

libeio 请求类型枚举深度分析(基于源码)

📋 请求类型枚举概述

基于libeio 1.0.2实际源码分析,请求类型枚举定义在eio.h头文件中,并在eio.c的eio_execute函数中通过switch-case语句实现具体的系统调用映射。


🔢 核心请求类型枚举(源码级分析)

基础文件I/O操作

/** * 源码位置: eio.c line 1927-1934 * 读写操作的实际实现 */caseEIO_READ:           ALLOC (req->size);  // 分配读取缓冲区req->result=req->offs >= 0                 ? pread(req->int1, req->ptr2, req->size, req->offs)  // 带偏移读取                 : read (req->int1, req->ptr2, req->size);            // 普通读取break;caseEIO_WRITE:          req->result=req->offs >= 0                 ? pwrite(req->int1, req->ptr2, req->size, req->offs) // 带偏移写入                 : write (req->int1, req->ptr2, req->size);           // 普通写入break;

文件操作类型

/** * 源码位置: eio.c line 1950, 1926, 1953-1958 * 文件打开、关闭、删除操作 */caseEIO_OPEN:           req->result=openat(dirfd, req->ptr1, req->int1, (mode_t)req->int2);    break;caseEIO_CLOSE:          req->result=eio__close(req->int1);  // 安全关闭文件描述符break;caseEIO_UNLINK:         req->result=unlinkat(dirfd, req->ptr1, 0);  // 删除文件break;caseEIO_RMDIR:          /* 处理"."目录的特殊情况 */req->result=req->wd&&SINGLEDOT(req->ptr1)                 ? rmdir(req->wd->str)                 : unlinkat(dirfd, req->ptr1, AT_REMOVEDIR);    break;caseEIO_MKDIR:          req->result=mkdirat(dirfd, req->ptr1, (mode_t)req->int2);  // 创建目录break;

文件属性操作

/** * 源码位置: eio.c line 1943-1949 * 文件状态和属性操作 */caseEIO_STAT:           ALLOC(sizeof(EIO_STRUCT_STAT));    req->result=fstatat(dirfd, req->ptr1, (EIO_STRUCT_STAT*)req->ptr2, 0);    break;caseEIO_LSTAT:          ALLOC(sizeof(EIO_STRUCT_STAT));    req->result=fstatat(dirfd, req->ptr1, (EIO_STRUCT_STAT*)req->ptr2, AT_SYMLINK_NOFOLLOW);    break;caseEIO_CHOWN:          req->result=fchownat(dirfd, req->ptr1, req->int2, req->int3, 0);  // 修改所有者break;caseEIO_CHMOD:          req->result=fchmodat(dirfd, req->ptr1, (mode_t)req->int2, 0);     // 修改权限break;caseEIO_TRUNCATE:       req->result=eio__truncateat(dirfd, req->ptr1, req->offs);          // 截断文件break;

链接和重命名操作

/** * 源码位置: eio.c line 1959-1970 * 链接和重命名操作实现 */caseEIO_RENAME:         req->result=eio__renameat2(        dirfd,        /* 处理"."目录重命名的特殊情况 */req->wd&&SINGLEDOT(req->ptr1) ? req->wd->str : req->ptr1,        WD2FD((eio_wd)req->int3),        req->ptr2,        req->int2     );    break;caseEIO_LINK:           req->result=linkat(dirfd, req->ptr1, WD2FD((eio_wd)req->int3), req->ptr2, 0);    break;caseEIO_SYMLINK:        req->result=symlinkat(req->ptr1, dirfd, req->ptr2);  // 创建符号链接break;caseEIO_MKNOD:          req->result=mknodat(dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs);    break;

时间操作

/** * 源码位置: eio.c line 1975-2005 * 文件时间戳操作(支持两种时间格式) */caseEIO_UTIME:caseEIO_FUTIME:     {        structtimespects[2];        structtimespec*times;        if (req->nv1!=-1.||req->nv2!=-1.) {            // 转换为timespec格式ts[0].tv_sec=req->nv1;            ts[0].tv_nsec= (req->nv1-ts[0].tv_sec) *1e9;            ts[1].tv_sec=req->nv2;            ts[1].tv_nsec= (req->nv2-ts[1].tv_sec) *1e9;            times=ts;         } else {            times=0;  // 使用当前时间         }        req->result=req->type==EIO_FUTIME                     ? futimens(req->int1, times)           // 文件描述符时间                     : utimensat(dirfd, req->ptr1, times, 0); // 路径时间     }    break;

高级I/O操作

/** * 源码位置: eio.c line 1938-1939, 2177-2186 * 高级I/O功能实现 */caseEIO_READAHEAD:      req->result=readahead(req->int1, req->offs, req->size);  // 预读break;caseEIO_SENDFILE:       req->result=eio__sendfile(req->int1, req->int2, req->offs, req->size);  // 零拷贝传输break;caseEIO_FALLOCATE:      req->result=eio__fallocate(req->int1, req->int2, req->offs, req->size); // 文件预分配break;caseEIO_SLURP:          eio__slurp(openat(dirfd, req->ptr1, O_RDONLY | O_CLOEXEC), req);  // 一次性读取文件break;

目录操作

/** * 源码位置: eio.c line 2037 * 目录扫描实现 */caseEIO_READDIR:        eio__scandir(req, self);  // 扫描目录内容break;

系统调用封装

/** * 源码位置: eio.c line 1935-1936 * 系统调用和控制操作 */caseEIO_FCNTL:          req->result=fcntl(req->int1, (int)req->int2, req->ptr2);  // 文件控制break;caseEIO_IOCTL:          req->result=ioctl(req->int1, (unsigned long)req->int2, req->ptr2);  // 设备控制break;

同步操作

/** * 源码位置: eio.c line 2019-2027 * 各种同步操作 */caseEIO_SYNC:           req->result=0;      sync();  // 同步所有文件系统break;caseEIO_FSYNC:          req->result=fsync(req->int1);  // 同步单个文件break;caseEIO_FDATASYNC:      req->result=fdatasync(req->int1);  // 同步文件数据break;caseEIO_SYNCFS:         req->result=eio__syncfs(req->int1);  // 同步文件系统break;

内存映射操作

/** * 源码位置: eio.c line 2028-2036 * 内存相关操作 */caseEIO_MSYNC:          req->result=eio__msync(req->ptr2, req->size, req->int1);  // 同步内存映射break;caseEIO_MTOUCH:         req->result=eio__mtouch(req);  // 触摸内存页面break;caseEIO_MLOCK:          req->result=eio__mlock(req->ptr2, req->size);  // 锁定内存页面break;caseEIO_MLOCKALL:       req->result=eio__mlockall(req->int1);  // 锁定所有页面break;

特殊操作

/** * 源码位置: eio.c line 1920-1925, 2064-2072 * 工作目录和特殊操作 */caseEIO_WD_OPEN:        req->wd=eio__wd_open_sync(&self->tmpbuf, req->wd, req->ptr1);    req->result=req->wd==EIO_INVALID_WD ? -1 : 0;    break;caseEIO_WD_CLOSE:       req->result=0;    eio_wd_close_sync(req->wd);  // 关闭工作目录break;caseEIO_SEEK:           eio__lseek(req);  // 文件定位break;caseEIO_BUSY:           {        structtimevaltv;        tv.tv_sec=req->nv1;        tv.tv_usec= (req->nv1-tv.tv_sec) *1e6;        req->result=select(0, 0, 0, 0, &tv);  // 模拟繁忙操作     }    break;caseEIO_NOP:            req->result=0;  // 空操作break;caseEIO_CUSTOM:         req->feed(req);  // 自定义操作break;

📊 请求类型分类统计

按功能领域分类

| 类别 | 请求类型数量 | 具体类型 | | — | — | — | | 基础I/O | 4 | READ, WRITE, OPEN, CLOSE | | 文件属性 | 6 | STAT, LSTAT, FSTAT, CHOWN, FCHOWN, CHMOD, FCHMOD | | 文件操作 | 7 | TRUNCATE, FTRUNCATE, UNLINK, RMDIR, MKDIR, MKNOD, SLURP | | 链接操作 | 3 | LINK, SYMLINK, RENAME | | 目录操作 | 2 | READDIR, READDIRP | | 时间操作 | 2 | UTIME, FUTIME | | 同步操作 | 6 | SYNC, FSYNC, FDATASYNC, SYNCFS, SYNC_FILE_RANGE, MSYNC | | 内存操作 | 4 | MTOUCH, MLOCK, MLOCKALL, FALLOCATE | | 系统调用 | 3 | FCNTL, IOCTL, SEEK | | 特殊操作 | 6 | WD_OPEN, WD_CLOSE, NOP, BUSY, GROUP, CUSTOM | | 网络操作 | 2 | SENDFILE, READAHEAD | | 路径操作 | 3 | READLINK, REALPATH, STATVFS, FSTATVFS |

按系统调用映射分类

POSIX标准调用

// 文件操作read/pread, write/pwrite, open/openat, close, unlink/unlinkatrmdir, mkdir/mkdirat, mknod/mknodat, rename/renameat2// 属性操作stat/fstatat, lstat/fstatat, chmod/fchmodat, chown/fchownatutimes/utimensat, truncate/eio__truncateat// 链接操作link/linkat, symlink/symlinkat, readlink/readlinkat// 同步操作sync, fsync, fdatasync, msync

Linux特有调用

// 高级I/Oreadahead, sendfile, fallocate, syncfs, sync_file_range// 内存管理mlock, mlockall, mtouch// 系统控制fcntl, ioctl

🔧 请求参数映射关系

核心参数结构映射

/** * eio_req结构体字段与系统调用参数的映射关系(基于源码分析) */// 文件描述符相关req->int1;        // fd, out_fd, input fd等// 路径相关  req->ptr1;        // pathname, old namereq->ptr2;        // new name, buffer, memory address// 偏移和大小req->offs;        // offset, dev_t(for mknod)req->size;        // length, count// 辅助参数req->int2;        // flags, mode, uid, requestreq->int3;        // gid, working directoryreq->nv1;         // atime, sleep timereq->nv2;         // mtime// 工作目录req->wd;          // working directory context

具体映射示例

// EIO_READ映射req->int1=fd;           // read(fd, ...)req->ptr2=buffer;       // read(..., buffer, ...)req->size=count;        // read(..., ..., count)req->offs=offset;       // pread(..., ..., ..., offset)// EIO_OPEN映射  req->ptr1=pathname;     // open(pathname, ...)req->int1=flags;        // open(..., flags, ...)req->int2=mode;         // open(..., ..., mode)// EIO_WRITE映射req->int1=fd;           // write(fd, ...)req->ptr2=buffer;       // write(..., buffer, ...)req->size=count;        // write(..., ..., count)req->offs=offset;       // pwrite(..., ..., ..., offset)

⚡ 性能特征分析

系统调用开销分类

基于源码实现的性能特征分析:

  • 低开销操作

    (< 1μs): EIO_NOP, EIO_SEEK, EIO_FCNTL, EIO_IOCTL

  • 中等开销操作

    (1-10μs): EIO_STAT, EIO_LSTAT, EIO_FSTAT, EIO_CHMOD等

  • 高开销操作

    (> 10μs): EIO_READ, EIO_WRITE, EIO_OPEN, EIO_CLOSE等

平台差异处理

/**&nbsp;* 源码位置: eio.c 多处&nbsp;* 条件编译处理平台差异&nbsp;*/#ifHAVE_AT// 使用*at系列函数(支持工作目录)req->result=openat(dirfd,&nbsp;req->ptr1,&nbsp;req->int1, (mode_t)req->int2);#else// 使用传统函数(需要完整路径)req->result=open(path,&nbsp;req->int1, (mode_t)req->int2);#endif#ifHAVE_POSIX_CLOSE&&&nbsp;!__linux// Linux特定优化#defineeio__close(fd) posix_close(fd, 0)#else#defineeio__close(fd) close(fd)#endif

🛡️ 安全机制设计

参数验证机制

/**&nbsp;* 源码中的安全检查实现&nbsp;*/staticvoideio_execute_security_checks(etp_worker*self,&nbsp;eio_req*req) { &nbsp; &nbsp;// 取消检查if&nbsp;(ecb_expect_false(EIO_CANCELLED(req))) { &nbsp; &nbsp; &nbsp; &nbsp;req->result=-1; &nbsp; &nbsp; &nbsp; &nbsp;req->errorno=ECANCELED; &nbsp; &nbsp; &nbsp; &nbsp;return; &nbsp; &nbsp; } &nbsp; &nbsp;// 工作目录有效性检查if&nbsp;(ecb_expect_false(req->wd==EIO_INVALID_WD)) { &nbsp; &nbsp; &nbsp; &nbsp;req->result=-1; &nbsp; &nbsp; &nbsp; &nbsp;req->errorno=ENOENT; &nbsp; &nbsp; &nbsp; &nbsp;return; &nbsp; &nbsp; } &nbsp; &nbsp;// 路径安全检查(防止路径遍历)if&nbsp;(req->type&nbsp;>=&nbsp;EIO_OPEN) { &nbsp; &nbsp; &nbsp; &nbsp;// 检查路径是否在允许的工作目录内// 源码中通过wd_expand函数实现路径展开和验证&nbsp; &nbsp; &nbsp;} }

内存安全措施

/**&nbsp;* 源码位置: eio.c 多处&nbsp;* 内存安全管理&nbsp;*/#defineALLOC(size) \ &nbsp; &nbsp; do { \ &nbsp; &nbsp; &nbsp; &nbsp; req->ptr2 = malloc(size); \ &nbsp; &nbsp; &nbsp; &nbsp; if (!req->ptr2) goto alloc_fail; \ &nbsp; &nbsp; &nbsp; &nbsp; req->flags |= EIO_FLAG_PTR2_FREE; \ &nbsp; &nbsp; } while(0)// 销毁时自动释放内存#defineEIO_DESTROY(req) \ &nbsp; &nbsp; do { \ &nbsp; &nbsp; &nbsp; &nbsp; if ((req)->destroy) (req)->destroy(req); \ &nbsp; &nbsp; } while(0)// 路径内存管理#definePATH&nbsp;\ &nbsp; &nbsp; req->flags |= EIO_FLAG_PTR1_FREE; \ &nbsp; &nbsp; req->ptr1 = strdup(path); \ &nbsp; &nbsp; if (!req->ptr1) { \ &nbsp; &nbsp; &nbsp; &nbsp; eio_api_destroy(req); \ &nbsp; &nbsp; &nbsp; &nbsp; return 0; \ &nbsp; &nbsp; }

🎯 使用模式和最佳实践

基本使用模式

/**&nbsp;* 源码示例:典型的异步I/O使用模式&nbsp;*/// 1. 文件读取模式eio_req*read_req=eio_read(fd,&nbsp;buffer,&nbsp;size,&nbsp;offset,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);// 2. 文件写入模式 &nbsp;eio_req*write_req=eio_write(fd,&nbsp;buffer,&nbsp;size,&nbsp;offset,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);// 3. 文件操作模式eio_req*open_req=eio_open(path,&nbsp;O_RDONLY,&nbsp;0644,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);eio_req*stat_req=eio_stat(path,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);eio_req*unlink_req=eio_unlink(path,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);// 4. 目录操作模式eio_req*readdir_req=eio_readdir(path,&nbsp;EIO_READDIR_DIRS_FIRST,&nbsp;EIO_PRI_DEFAULT,&nbsp;callback,&nbsp;data);

批量操作优化

/**&nbsp;* 源码体现的批量处理优化&nbsp;*/// 1. 优先级管理eio_req*high_priority=eio_read(fd1,&nbsp;buf1,&nbsp;size1,&nbsp;0,&nbsp;EIO_PRI_MAX,&nbsp;cb,&nbsp;data);eio_req*low_priority=eio_read(fd2,&nbsp;buf2,&nbsp;size2,&nbsp;0,&nbsp;EIO_PRI_MIN,&nbsp;cb,&nbsp;data);// 2. 群组操作(源码中的EIO_GROUP实现)eio_req*group=eio_grp(group_callback,&nbsp;group_data);eio_grp_add(group,&nbsp;eio_stat("file1.txt",&nbsp;0,&nbsp;NULL,&nbsp;NULL));eio_grp_add(group,&nbsp;eio_stat("file2.txt",&nbsp;0,&nbsp;NULL,&nbsp;NULL));eio_grp_add(group,&nbsp;eio_stat("file3.txt",&nbsp;0,&nbsp;NULL,&nbsp;NULL));

错误处理模式

/**&nbsp;* 源码中的错误处理机制&nbsp;*/intio_callback(eio_req*req) { &nbsp; &nbsp;if&nbsp;(req->result<0) { &nbsp; &nbsp; &nbsp; &nbsp;// 处理错误fprintf(stderr,&nbsp;"Operation failed: %s\n",&nbsp;strerror(req->errorno)); &nbsp; &nbsp; &nbsp; &nbsp;return-1; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 处理成功结果switch&nbsp;(req->type) { &nbsp; &nbsp; &nbsp; &nbsp;caseEIO_READ: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printf("Read %zd bytes\n",&nbsp;req->result); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break; &nbsp; &nbsp; &nbsp; &nbsp;caseEIO_WRITE: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printf("Wrote %zd bytes\n",&nbsp;req->result); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break; &nbsp; &nbsp; &nbsp; &nbsp;// ... 其他类型处理&nbsp; &nbsp; &nbsp;} &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return0; }

🔍 调试和监控支持

内置调试功能

/**&nbsp;* 源码提供的调试支持&nbsp;*/// 1. 请求类型查询#defineEIO_TYPE(req) ((req)->type)// 2. 结果访问#defineEIO_RESULT(req) ((req)->result)#defineEIO_BUF(req) ((req)->ptr2)// 3. 状态检查#defineEIO_CANCELLED(req) ecb_expect_false((req)->cancelled)// 4. 错误信息#defineEIO_ERROR(req) ((req)->errorno)

性能监控

/**&nbsp;* 源码中的性能统计支持&nbsp;*/// 通过eio_nreqs(), eio_nready(), eio_npending()查询unsigned&nbsp;inttotal_requests; &nbsp; &nbsp;// 总请求数unsigned&nbsp;intready_requests; &nbsp; &nbsp;// 就绪请求数 &nbsp;unsigned&nbsp;intpending_requests; &nbsp;// 挂起请求数unsigned&nbsp;intactive_threads; &nbsp; &nbsp;// 活跃线程数// 实际查询函数实现unsigned&nbsp;inteio_nreqs(void) { &nbsp; &nbsp;unsigned&nbsp;intcount; &nbsp; &nbsp;X_LOCK(EIO_POOL->reqlock); &nbsp; &nbsp;count=EIO_POOL->nreqs; &nbsp; &nbsp;X_UNLOCK(EIO_POOL->reqlock); &nbsp; &nbsp;returncount; }
  • 公众号:安全狗的自我修养
  • vx:2207344074
  • http://gitee.com/haidragon
  • http://github.com/haidragon
  • bilibili:haidragonx

#


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:安全狗的自我修养 haidragon haidragon《libeio库源码分析系列(六)》

评论:0   参与:  0