ELF section修复的一些思考
2017-06-15 21:09
141 查看
原文地址
http://bbs.pediy.com/thread-192874.htm
终于抽出时间整理了。。。
限于本菜水平有限,难免会有很多错误和不足之处,请各位大牛指正,小弟感激不尽。
-------------------------------------------------------------------------------------------
一、 概述
相信各位读者对so分析都采用静态和动态相结合的方式,静态分析常用readelf、objdump、ida等工具,这些工具对so文件的分析都会使用到Section信息。从这篇帖子中http://bbs.pediy.com/showthread.php?t=191649 知道,程序并不需要section信息。现很多so文件对section信息都进行了处理,导致常用分析工具无法使用。以下讨论前段时间对section修复的一些思考,若有不足或错误之处,请各位大大指正,小弟感激不尽!
二、 仅处理so文件头
在上文提到的帖子中,给出了一种section处理的一种简单方式。这里在罗嗦下,即将Elf32_Ehdr中的e_shoff, e_shnum, e_shstrndx, e_shentsize字段处理。修复公式:e_shstrndx = e_shnum -1; e_shnum = (file_size – e_shoff) / sizeof(Elf32_Shdr)。在那篇帖子中作为修复的数字so文件,并未处理e_shoff字段,故用上式修复可行。那如果都处理掉,则上式中存在两个未知数,无法利用。
一种简单的思路是,手动查找so文件中一些稳定且标志性的数据作为参考来修复。这里,我选择shstrtab表,这样比较简单。因为shshtrtab后面就是section头信息,这样就间接找到e_shoff位置,即可利用上式修复。
手动查找当然可行,毕竟麻烦。作为程序猿,应该通过程序来解决问题。借鉴手动修复的思路,只要程序能找到shstrtab即可实现修复。从观察或e_shstrndx知道,shstrtab section为最后一个section,即处于文件末尾。那直接移动到末尾读取到shstrtab section,则e_shoff = sh_offset + sh_zize(这里还需对e_shoff 4字节对齐处理)。
三、 无section信息
现阶段,我遇到的很多so文件的section修复都采用上述方法,还未遇到无section信息的so,即直接将so文件中的section直接删除,或者替换section内容(比如填充隐藏代码或者垃圾数据之类的)。直接删除section信息,即可节省空间,又可让静态工具“蛋疼”(有点好奇为什么不对so作如此处理)。另外,直接从内存中dump出来的so文件,也是没有section信息的(因为section没有被加载到内存中)。当然,从内存中dump的so文件,由于内存对齐的原因,需要作下简单处理,这里就不赘述。
从内存dump出的so文件已经经过解密,直接拿来分析,能获得事半功倍的效果。但没有section信息,静态分析很是不爽。如果原so文件有section信息,则只需要把原so文件中的section信息复制过来并修复Elf32_Ehdr即可。那如果原so无section信息,我的理解是需要对section信息进行重建(虽然现阶段还没用到,处于问题思考的完整性,讨论这种情况)。
使用readelf –S 查看一个完整的so文件section如下图所示:
![](http://bbs.pediy.com/upload/attach/201409/627520_tlo8o0755bhtj31.png)
使用readelf –l 如图所示:
![](http://bbs.pediy.com/upload/attach/201409/627520_psx2z2kev1eln5s.png)
从segment信息可以看出, 对.dynamic和.arm_exidx的section重建很简单,即读取即可。
通过.dynamic,可以对大部分section进行重建,具体如下:
1. 通过DT_SYMTAB,DT_STRTAB,DT_STRSZ,DT_REL,DT_RELSZ,DT_JMPREL, DT_PLTRELSZ,DT_INIT_ARRAY,DT_INIT_ARRAYSZ,DT_FINI_ARRAY,DT_FINI_ARRAYSZ 得到.dynsym,.dynstr, rel.dyn, rel.plt, init_array, fini_array 相应的section vaddr 和 size信息,完成对上述section的重建。这里需要注意,处于load2中的section,offset
= vaddr – 0x1000
2. 通过DT_HASH得到hash section的vaddr,然后读入前两项得到nbucket和nchain的值,得到hashsz = (nbucket + nchain + 2) * sizeof(int), 完成对hash表重建
3. Plt的起始位置即为rel.plt的末尾,通过1中的对rel.plt的处理,即可得到plt的offset和vaddr信息。通过plt的结构知道,plt由固定16字节 + 4字节的__global__offset_table变量和n个需要重定位的函数地址构成,函数地址又与rel.plt中的结构一一对应。故size = (20 + 12 * (rel.plt.size) / sizeof(Elf32_Rel)。
4. 从DT_PLTGOT可以得到__global_offset_table的偏移位置。由got表的结构知道,__global_offset_table前是rel.dyn重定位结构,之后为rel.plt重定位结构,都与rel一一对应。则got表的重建具体为:通过已重建的.dynamic得到got起始位置,通过__global_offset_table 偏移 + 4 * (rel.plt.size) / sizeof(Elf32_Rel)(这里还需要添加2个int的填充位置)得到got的末尾,通过首尾位置得到got的size,完成重建
5. 通过got的末尾,得到data的起始位置,再通过load2_vaddr + load2_filesz得到load2的末尾(load2即第二个LOAD),即data的末尾位置,计算长度,完成修正。可能读者会问,bss才是load2的最后一个section。的确,但bss为NOBITS,即可把data看作load2最后一个section。
6. 对bss的修正就很简单,offset和vaddr即为load2末尾。由于未NOBITS类型,长度信息无关紧要。
7. 到这里,读者可能已经发现,还没对text和ARM.extab修正。限于本人水平,还没能找到方法区分开这两个section。现处理是将之合并,作为text & ARM.extab节。具体修正:offset和vaddr通过plt末尾得到,长度通过ARM.exidx的起始位置和plt末尾位置计算得到。
至此,绝大部分section信息已经重建完成。最后,在将shstrtab添加,并修正Elf32_Ehdr,完成section重建。虽然未100%重建,但已经能够帮助分析了。重建后的如图所示,图中红色部分即是未分离的test & ARM.extab section。
![](http://bbs.pediy.com/upload/attach/201409/627520_w8iyncqz9yap2ku.png)
使用ida也能正常打开,只是会将ARM.extab的数据转换成错误代码,其他均正常。
![](http://bbs.pediy.com/upload/attach/201410/627520_ixtllg9gc9b7aw4.png)
---------------------------------------------------------------------------------------
最后,便于理解,给出附件测试。具体详解附件的说明文档,这里就不赘述了。
-------------------------------------------------------------------------------------
2014.10.10:
由于文件操作不当,导致修复后的Elf32头未写入文件,现将附件更新
上传的附件:
1.png (31.24kb,70次下载)
2.png (15.37kb,46次下载)
3.png (26.11kb,46次下载)
4.png (15.27kb,42次下载)
elf section的一些思考.pdf (211.23kb,521次下载)
附件.zip (101.68kb,586次下载)
62
收藏
![](http://bbs.pediy.com/view/img/dashang.png)
![](http://bbs.pediy.com/bbs_qrcode-http_3A_2F_2Fbbs_2epediy_2ecom_2Fthread_2d192874_2ehtm.htm)
本主题帖已收到 0 次赞赏,累计¥0.00
http://bbs.pediy.com/thread-192874.htm
终于抽出时间整理了。。。
限于本菜水平有限,难免会有很多错误和不足之处,请各位大牛指正,小弟感激不尽。
-------------------------------------------------------------------------------------------
一、 概述
相信各位读者对so分析都采用静态和动态相结合的方式,静态分析常用readelf、objdump、ida等工具,这些工具对so文件的分析都会使用到Section信息。从这篇帖子中http://bbs.pediy.com/showthread.php?t=191649 知道,程序并不需要section信息。现很多so文件对section信息都进行了处理,导致常用分析工具无法使用。以下讨论前段时间对section修复的一些思考,若有不足或错误之处,请各位大大指正,小弟感激不尽!
二、 仅处理so文件头
在上文提到的帖子中,给出了一种section处理的一种简单方式。这里在罗嗦下,即将Elf32_Ehdr中的e_shoff, e_shnum, e_shstrndx, e_shentsize字段处理。修复公式:e_shstrndx = e_shnum -1; e_shnum = (file_size – e_shoff) / sizeof(Elf32_Shdr)。在那篇帖子中作为修复的数字so文件,并未处理e_shoff字段,故用上式修复可行。那如果都处理掉,则上式中存在两个未知数,无法利用。
一种简单的思路是,手动查找so文件中一些稳定且标志性的数据作为参考来修复。这里,我选择shstrtab表,这样比较简单。因为shshtrtab后面就是section头信息,这样就间接找到e_shoff位置,即可利用上式修复。
手动查找当然可行,毕竟麻烦。作为程序猿,应该通过程序来解决问题。借鉴手动修复的思路,只要程序能找到shstrtab即可实现修复。从观察或e_shstrndx知道,shstrtab section为最后一个section,即处于文件末尾。那直接移动到末尾读取到shstrtab section,则e_shoff = sh_offset + sh_zize(这里还需对e_shoff 4字节对齐处理)。
三、 无section信息
现阶段,我遇到的很多so文件的section修复都采用上述方法,还未遇到无section信息的so,即直接将so文件中的section直接删除,或者替换section内容(比如填充隐藏代码或者垃圾数据之类的)。直接删除section信息,即可节省空间,又可让静态工具“蛋疼”(有点好奇为什么不对so作如此处理)。另外,直接从内存中dump出来的so文件,也是没有section信息的(因为section没有被加载到内存中)。当然,从内存中dump的so文件,由于内存对齐的原因,需要作下简单处理,这里就不赘述。
从内存dump出的so文件已经经过解密,直接拿来分析,能获得事半功倍的效果。但没有section信息,静态分析很是不爽。如果原so文件有section信息,则只需要把原so文件中的section信息复制过来并修复Elf32_Ehdr即可。那如果原so无section信息,我的理解是需要对section信息进行重建(虽然现阶段还没用到,处于问题思考的完整性,讨论这种情况)。
使用readelf –S 查看一个完整的so文件section如下图所示:
![](http://bbs.pediy.com/upload/attach/201409/627520_tlo8o0755bhtj31.png)
使用readelf –l 如图所示:
![](http://bbs.pediy.com/upload/attach/201409/627520_psx2z2kev1eln5s.png)
从segment信息可以看出, 对.dynamic和.arm_exidx的section重建很简单,即读取即可。
通过.dynamic,可以对大部分section进行重建,具体如下:
1. 通过DT_SYMTAB,DT_STRTAB,DT_STRSZ,DT_REL,DT_RELSZ,DT_JMPREL, DT_PLTRELSZ,DT_INIT_ARRAY,DT_INIT_ARRAYSZ,DT_FINI_ARRAY,DT_FINI_ARRAYSZ 得到.dynsym,.dynstr, rel.dyn, rel.plt, init_array, fini_array 相应的section vaddr 和 size信息,完成对上述section的重建。这里需要注意,处于load2中的section,offset
= vaddr – 0x1000
2. 通过DT_HASH得到hash section的vaddr,然后读入前两项得到nbucket和nchain的值,得到hashsz = (nbucket + nchain + 2) * sizeof(int), 完成对hash表重建
3. Plt的起始位置即为rel.plt的末尾,通过1中的对rel.plt的处理,即可得到plt的offset和vaddr信息。通过plt的结构知道,plt由固定16字节 + 4字节的__global__offset_table变量和n个需要重定位的函数地址构成,函数地址又与rel.plt中的结构一一对应。故size = (20 + 12 * (rel.plt.size) / sizeof(Elf32_Rel)。
4. 从DT_PLTGOT可以得到__global_offset_table的偏移位置。由got表的结构知道,__global_offset_table前是rel.dyn重定位结构,之后为rel.plt重定位结构,都与rel一一对应。则got表的重建具体为:通过已重建的.dynamic得到got起始位置,通过__global_offset_table 偏移 + 4 * (rel.plt.size) / sizeof(Elf32_Rel)(这里还需要添加2个int的填充位置)得到got的末尾,通过首尾位置得到got的size,完成重建
5. 通过got的末尾,得到data的起始位置,再通过load2_vaddr + load2_filesz得到load2的末尾(load2即第二个LOAD),即data的末尾位置,计算长度,完成修正。可能读者会问,bss才是load2的最后一个section。的确,但bss为NOBITS,即可把data看作load2最后一个section。
6. 对bss的修正就很简单,offset和vaddr即为load2末尾。由于未NOBITS类型,长度信息无关紧要。
7. 到这里,读者可能已经发现,还没对text和ARM.extab修正。限于本人水平,还没能找到方法区分开这两个section。现处理是将之合并,作为text & ARM.extab节。具体修正:offset和vaddr通过plt末尾得到,长度通过ARM.exidx的起始位置和plt末尾位置计算得到。
至此,绝大部分section信息已经重建完成。最后,在将shstrtab添加,并修正Elf32_Ehdr,完成section重建。虽然未100%重建,但已经能够帮助分析了。重建后的如图所示,图中红色部分即是未分离的test & ARM.extab section。
![](http://bbs.pediy.com/upload/attach/201409/627520_w8iyncqz9yap2ku.png)
使用ida也能正常打开,只是会将ARM.extab的数据转换成错误代码,其他均正常。
![](http://bbs.pediy.com/upload/attach/201410/627520_ixtllg9gc9b7aw4.png)
---------------------------------------------------------------------------------------
最后,便于理解,给出附件测试。具体详解附件的说明文档,这里就不赘述了。
-------------------------------------------------------------------------------------
2014.10.10:
由于文件操作不当,导致修复后的Elf32头未写入文件,现将附件更新
上传的附件:
1.png (31.24kb,70次下载)
2.png (15.37kb,46次下载)
3.png (26.11kb,46次下载)
4.png (15.27kb,42次下载)
elf section的一些思考.pdf (211.23kb,521次下载)
附件.zip (101.68kb,586次下载)
62
收藏
![](http://bbs.pediy.com/view/img/dashang.png)
本主题帖已收到 0 次赞赏,累计¥0.00
最新回复 (25) | |
---|---|
![]() 4 | 我是小三 2014-10-1 10:46 2 楼 感谢分享。沙发是我的.. |
![]() 2 | 万抽抽 2014-10-1 11:26 3 楼 那我就只要坐板凳了 |
![]() 5 | boyliang 2014-10-1 20:26 4 楼 满满的干货,顶一个 |
![]() 1 | 鬼谷子c 2014-10-2 00:17 5 楼 好文章“! 4楼广告位出租! 学习elf的进阶篇,赞一个! |
![]() 6 | ThomasKing 2014-10-2 09:31 6 楼 多谢大大支持! |
![]() 6 | ThomasKing 2014-10-2 09:32 7 楼 多谢鬼哥支持! |
![]() | SANCDAYE 2014-10-7 23:41 8 楼 支持一下,good job |
![]() | SpaceDye 2014-10-10 13:41 9 楼 支持一下,不错的教程。 |
![]() | netsniffer 2014-10-10 15:56 10 楼 LZ看看附件两个elf文件,改了section entry size和number of sections,strsection index,IDA可以正常解析,否则原始的ori文件加载会失败 IDA解开看,貌似有壳,怎么破? 上传的附件: analysis.rar (171.41kb,19次下载) |
![]() | zrhai 2014-10-10 16:00 11 楼 多谢分享! 测试了下工具,貌似 e_shentzise 好像没强制修改为 0x28 |
![]() 6 | ThomasKing 2014-10-10 19:45 12 楼 额,这个应该是被加过密。。。脱壳得靠你自己了。 |
![]() 6 | ThomasKing 2014-10-10 19:47 13 楼 多谢反馈。 由于文件操作不当,导致未将修复后的Elf头写入文件。 已更新附件 |
![]() | jeffycf 2014-10-23 09:57 14 楼 技术才是硬道理 |
![]() | Colbert仔 2015-6-25 12:00 15 楼 顶一个!! |
![]() | Colbert仔 2015-6-25 17:05 16 楼 发现有个问题: 通过 DT_HASH 得到 hash section 的 vaddr,然后读入前两项得到 nbucket 和 nchain 的值,得到 hashsz = (nbucket + nchain + 2) * sizeof(int), 完成对 hash 表重建 我用LZ提供的工具修复so后,hashsz=327F17DCh,导致IDA报错,010editor也解析不出来,是因为算法有误吗? 这so就是MSC第四题: http://bbs.pediy.com/showthread.php?t=198529 http://bbs.pediy.com/showthread.php?t=197235 LOG: 默认读入文件名:dump_new.so, 输出文件:dump_new_full.so 如需更改,请修改.bat文件输入参数 ************Begin******************* [0] Find e_phnum = 8 [1] Find load1, offset = 0x0, length = 0xd2e6 [2] Find load2, offset = 0x28000, vaddr = 0x39000, length = 0x296b [3] Start rebuilding section info [4] Rebuilding success |
![]() | jieniruyan 2016-2-16 17:11 17 楼 学习了。 |
![]() | frozenrain 2016-4-9 18:00 18 楼 .data的偏移是0x1000对齐的,由此可以修正got的大小。 .bss的大小是load节的实际大小和内存大小之差 .text和exid的大小可由.finit的偏移算出来。 |
![]() 2 | 大王叫我挖坟 2016-5-2 20:33 19 楼 文章很好,好可惜哦,没有提供源码,不能对elf文件结构做深入了解了,网上关于elf文件的说明也只是简单停留在section层面上,而linux的elf又跟android 的elf有区别,哎,想找份完整的资料都难 |
![]() 2 | 大王叫我挖坟 2016-5-2 21:56 20 楼 哈哈大大没有加密exe文件,丢ida结合已有的知识,大概可以写出源码来,如果有疑惑的建议先看大大http://bbs.pediy.com/showthread.php?t=193279这篇文件,弄懂了,就可以还原大大的exe啦 |
![]() | 古往今来 2016-11-16 16:20 21 楼 dump之后怎么修复对齐问题? |
![]() | OnlyForU 2016-11-16 16:26 22 楼 学习! 感谢楼主! |
![]() | 古往今来 2016-11-25 21:02 23 楼 感谢楼主大大,学习了楼主的思路,用了大大的程序,.fini_array和.init_array段修复的有些问题,其他的还行。我根据楼主的思路写了个修复工具,修复SO后GOT略有问题 |
![]() | 田darren 2017-3-1 14:40 24 楼 init_array段 修复, 有很大帮助. |
![]() | 狂奔的鸡骨架 2017-3-1 18:52 25 楼 mark |
![]() | 无所从来 2017-5-15 14:25 26 楼 restoreSection.bat 中的apkso.so是什么? |
相关文章推荐
- ELF section修复的一些思考
- ELF section修复的一些思考
- 从动态表单得到的一些思考
- andriod 自定义来电界面功能实现的一些思考。
- 一些思考:嵌入式软件设计公司合理的组织结构
- 延迟渲染的一些思考
- 关于宇宙宿命论的一些思考
- 图像处理代码的一些思考
- 作为教师的一些思考(一)
- 作为老师的一些思考(二)
- 关于公司招聘的一些思考
- 关于国产科学(计算)软件的一些思考
- 高可用的一些思考和理解
- SLAM应用的一些思考
- 对jQuery的事件绑定的一些思考(补充)
- 数学建模的一些思考
- 关于线上的bug什么时候修复的思考
- iOS开发:从新手到专家的一些建议,思考你是否想要成为程序员
- 关于测试用例冗余的一些思考
- 关于程序员的一些思考