在某些ELF文件中,IDA无法识别库函数的签名。就会导致IDA加载的函数全是sub_xxxx的形式,这给我们的逆向工程造成极大的困难。
这个时候就可以利用IDA自带的FLIRT来帮助我们逆向。(也有finger,luman等工具可以实现这个需求)
库快速识别和鉴定技术,简称FLIRT,是IDA用于识别库代码的一组技术。
FLIRT的核心是各种模式匹配算法,这些算法使IDA能够迅速确定,一个经过反汇编的函数是否与IDA已知的许多签名中的某一个相匹配。
IDA/sig中包含一些常见的库。
在IDA中,File->Load File->FLIRT signature file可以打开可用的library窗口,这个窗口中的内容实际上就是IDA文件路径下sig中的pc文件夹内容。可以选择其中一个点击OK,导入相关库信息,IDA会自动识别可以识别的函数。
第二种方法就是Shift+F5打开Singatures窗口,然后右键点击Apply new signature,接着如上。
网络上有经过整合的sig文件:https://github.com/push0ebp/sig-database 各个架构各个版本的都有。
可以下载后选择合适的添加到IDA/sig/pc下,再到IDA中导入。
缺点:大多数情况下都不清楚目标文件所对应的库函数版本,可能需要多次尝试才能成功。
有个脚本,iscan.py可以匹配文件所对应的库文件(https://github.com/maroueneboubakri/lscan)本人实测,代码跑不了一直报错,所以这里不多做评价。(有没有路过的佬有解决办法的o(╥﹏╥)o)
IDA不可能自带所有的静态库的签名文件,使用现有的sig签名也很大可能得不到正确的结果。
因此,就要自己手动创建FLIRT签名文件。
IDA中的FLAIR工具集一般在IDA路径中包含,解压下来即可。FLAIR中包含几个文本文件,其中特别有用的如下:
四个步骤:
生成文件的第一步是确定你所需要的静态库。
有俩种办法;
第一种
根据你的文件找到它所依赖的库,你可以找到这个库的源代码,使用源代码创建你自己的静态库,然后使用这个库生成签名文件。
第二种
确定你所分析的二进制文件的真实来源,即具体的操作系统、操作系统版本和发行版本(如果适用)。根据这些信息,从一个配置完全相同的系统中复制相关的库。
使用第一种方法可能会导致你生成的静态库和目标库有所差异,所以导致签名文件不同,因此最好的方法是第二种。
接着问题:如何找到所需的静态库?
使用file
命令或者strings
命令。
file
命令可以显示文件的基本构建信息,这些信息提供了有关可能使用哪个操作系统和编译器来创建文件的线索。
例如:
file
命令显示 dacls_sample 是一个 64 位 ELF(可执行和链接格式),针对 GNU/Linux 3.2.0 进行静态链接和剥离。版本号 3.2.0 对应于用于编译示例的 ABI(应用程序二进制接口)版本。
strings
可以搜索二进制文件中的字符串,记得加上 -a
迫使strings
扫描整个二进制文件。
也可以使用readelf
命令,如
└─$ readelf -p .comment easyre
String dump of section '.comment':
[ 0] GCC: (Debian 11.2.0-13) 11.2.0
这里就显示了easyre文件是在Debian操作系统上使用GCC编译的,(Debian 11.2.0-13)这是Debian的版本信息,后面的11.2.0是GCC的版本信息。
因此若要制作easyre的签名,最好的办法就是创建一个Debian 11的操作系统,获取其中的静态库。
在FLAIR中的bin目录下可以找到以下解析器:
要为一个库创建一个模式文件,需要与指定的库的格式对应的解析器、你希望解析的库的名称以及生成的模式文件的名称。
例如,上面Debian是一种类Unix系统,要使用pelf,经过上一步也可以得到一个.a后缀的静态库文件。
┌──(kali?kali)-[/home/sigtest]
└─$ ./pelf libc.a examplelibc.pat
/home/sigtest/libc.a: skipped 14, total 2057
这里解析器会指出被解析的文件、被忽略的函数的数量(14)以及生成的签名模式的数量(2057)。
使用sigmake工具。
┌──(kali?kali)-[/home/sigtest]
└─$ ./sigmake examplelibc.pat examplelibc.sig
如果一切正常,就可以得到一个sig文件,将其复制到目录下,就OK了。但是一般情况下,在生成签名文件的过程中,会发生函数之间的冲突。
解析器一般会指出:
┌──(kali?kali)-[/home/sigtest]
└─$ ./sigmake examplelibc.pat examplelibc.sig
examplelibc.sig: modules/leaves: 1685/2034, COLLISIONS: 27
See the documentation to learn how to resolve collisions.
同时会产生一个exc排斥文件。
文件的开头通常是:
;--------- (delete these lines to allow sigmake to read this file)
; add '+' at the start of a line to select a module
; add '-' if you are not sure about the selection
; do nothing if you want to exclude all modules
__pthread_equal 00 0000 31C04839F70F94C0C3..............................................
thrd_equal 00 0000 31C04839F70F94C0C3..............................................
_IO_putc 2D D13A 41545589FD534889F34883EC10F64674800F84B9000000F70600800000746148
fputc 2D D13A 41545589FD534889F34883EC10F64674800F84B9000000F70600800000746148
__fseeko 04 749A 415541544189D4554889F5534889FB4883EC18F707008000007547488BBF8800
fseek 04 749A 415541544189D4554889F5534889FB4883EC18F707008000007547488BBF8800
......
解除冲突的方法就是先删除前4行的内容,之后可以在函数前面添加加号或者减号;如果希望数据库在匹配某一个签名的时候,使用该名字,那就在前面添加一个“+”号,如果你想在数据库匹配到一个签名时简单的添加一条注释,那你就在名字签名添加一个“-”号,如果你希望不应用任何名字,那就不要添加任何符号。
例如:
+___ntohs 00 0000 0FB744240486C4C3................................................
___htons 00 0000 0FB744240486C4C3................................................
_index 00 0000 538B4424088A4C240C908A1838D974074084DB75F531C05BC3..............
_strchr 00 0000 538B4424088A4C240C908A1838D974074084DB75F531C05BC3..............
_rindex 00 0000 538B5424088A4C240C31C0908A1A38D9750289D04284DB75F35BC3.......
-_strrchr 00 0000 538B5424088A4C240C31C0908A1A38D9750289D04284DB75F35BC3..........
这表示,第一个签名匹配时我们选择使用ntohs名字,第二个签名匹配时什么也不做,第三个签名匹配时添加strrchr为注释。
解决完冲突后再次运行sigmake
命令。
sigmake
命令还可以添加一条指令 -n
用于指定生成的库名称。
例如:
$ ./sigmake -n"FreeBSD 6.1 C standard library" libc_FreeBSD61.pat libc_FreeBSD61.sig
后言:
今天的一点点小结,其实还是一知半解的。写了笔记就顺便润色一下发出来,本来今天是想复现强网杯的easyre的,结果开局一个符号还原就差不多花了一天。。。还没有还原出来,做出来的第一个签名随便找到libc.a还原出了103个函数,其他的都只可以还原几个。好难啊,现在打算下个新的虚拟机搭个Debian11出来,希望明天可以复现出来。。。也不知道Debian可不可行。
有个WP大佬说finger符号还原,可是我的finger一点用都没有,实在搞不懂啊。学习真难o(╥﹏╥)o,碎碎念。今天还是圣诞节Merryykuisimen!