-
-
[原创]fstrm-capture 控制帧构造流程分析
-
发表于: 15小时前 83
-
作为一个资历尚浅的pwn手,我大概算是第一次独立逆向这种真实环境下的程序,本帖仅当记录一下逆向和调试过程,若有纰漏,还请多多指出。
程序名称:fstrm_capture
debian系下安装命令:apt install fstrm-bins,默认在/usr/bin目录下,是安装fstrm-bin的三个命令行工具之一
程序用途:监听一个套接字,接收Frame Streams协议格式的数据流,然后保存至文件中。

复制后ldd检查一下运行情况:

可以看到依赖一个libfstrm.so.0库,以及一个libevent-2.1.so.7库
file检查,确定符号表已经被剥离。
尝试先用strace确定使用了哪些系统调用,以便快速找到主要逻辑:

可以发现最上面的openat调用,更之前是mprotect和brk,以及一些初始化,这里注意到openat的字符串是尾缀为.fstrm的文件名,不难猜测这是程序正在打开文件
而最下面,程序卡在了epoll_wait处,想必是一个死循环
直接启动gdbserver和gdb,并且在open上下断点,同时查看bt,可以找到是谁调用了open




调用者的地址是0x5555 5555 9eaf,我们通过cat /proc/7502/maps和readelf快速锁定此函数的VA


用0x5555 5555 7000减掉代码段所在的LOAD相对于虚拟内存运行基址的VA 0x3000,得到映射在虚拟内存中的起始位置,用0x5555 5555 9eaf减去这跟起始位置的值,等于0x5eaf,也就是调用open的代码出现在这个相对VA上
这里我的办法稍微麻烦了一些,其实可以用IDA直接追踪一下open的调用,直接找到目标函数
打开IDA,目标函数是sub_5d10,IDA显示的VA也是0x5d10,简单分析后情况如下:


将sub_5010重命名为handle_it,并继续对它进行分析:
、其中fstrm_control_init,fstrm_control_set_type等几个函数是libfstrm.so的库函数,这里也把对它们的分析结果贴出来:


对于fstrm_control_set_type函数,它并没有标出自己的参数情况,所以它的参数是用gdb看的:

rdi寄存器和rsi寄存器负责保存前两个参数,所以参数分别是0x5555 5555 3550和0x2
总地来说,这一大堆逻辑,其实都是创建了这样一个内存链式结构:
修复的结构体的命名不太严谨,不过应该不影响阅读:

这里解释一下:
这是一个实现动态数组分配的机制
一块内存的类型是struct_35,该内存由fstrm_control_init在堆上分配;struct_35->ptr指向一个struct_33类型的内存,这段内存同样由fstrm_control_init分配,the_array_start_ptr代表一个结构体数组的头部指针,malloc_pos_ptr是游标,room_has_been_used表示当前结构体数组的元素数量,the_whole_room是当前最大可储存的元素数
该数组的每一个元素,都是struct_34类型,前八字节表示字符串长度,后八字节存储一个指针,指向字符串大小
它应该是为大型软件设计的,而fstrm_capture应用它仅仅是存一个普通字符串,也就是-t参数
fstrm_control_encode是一个编码函数,大概的过程是大小端序的转换,我只做了一半分析,有需求可自行查看
size[0].m128i_u64[1]属于某union(大小为16字节)的后半部分,前半部分就是size本身,这里应该也是编译器优化问题
程序最后调用fwrite,将size[0].m128i_u64[1]所存储的内容按size x 1写入文件之中
这里是最后的结果:

本来想抓个包再检验一下,但其实跟hexdump看的东西区别不大,只是经过编码后的情况,如果不深入编码逻辑的话,应该没必要细究
对我而言,难点主要来自没接触过frame stream协议,以及对动态数组的原理不熟悉
到此告一段落。
下面是附件,包含原装的libfstrm库和fstrm_capture,以及我分析得到的i64文件
[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。