您的位置:首页 > 其它

从零打造简单的SODUMP工具

2014-11-18 22:35 309 查看
从零打造简单的SODUMP工具
Author: ThomasKing
最近翻看之前的帖子,发现基于linker init_array加密的SO文件的静态分析稍微麻烦。虽然原理很清楚,但是需要dump之后再进行section修复才能放入ida。可以看到,上述两步骤其实很机械。那么应该可以实现一个自动化工具,帮助我们解决上述问题,让我们可以精力专注于其他地方,提高效率。实现上述工具需要解决两个问题:1> 应对各种加密算法 2> section重建。Section 重建在http://bbs.pediy.com/showthread.php?t=192874
已经讨论,就不再赘述,仅仅改进一些不足之处。

一、应对各种加密算法策略

http://bbs.pediy.com/showthread.php?t=192020&viewgoodnees=1&prefixid= 等帖子中提到的SO文件都基于init_array实现。为了静态分析,不得不分析出算法,并实现对SO解密,以便静态分析。而且,不同的SO采用不同的加密算法。这个步骤时间的花费,取决于分析人员对各种常用的加密算法RC4、TED等了解程度,这是比较纠结的事情。
那如何应对各种加密算法,成为工具实现的关键。直接实现各种算法,这个显然是不行的。那只能通过某种方法来绕过。想了很久,也没有很好的解决策略。不过有一点,熟悉SO机制的读者都知道,linker可是应对自如!那看来只能借linker之手,来帮助我们实现。
Linker除了在程序运行初加载外,还有就是通过dl函数会调用,即dlopen、dlsym、dlerr和dlclose。啰嗦下dlopen和dlsym函数原型:
void *dlopen( const char * pathname, int mode);
void*dlsym(void*handle,constchar*symbol);
通常,使用dlopen打开加载某SO后,会返回一个handle对象,然后根据handle对象调用dlsym查找某函数符号,实现调用。仔细分析可以发现,这个过程和程序在运行初是类似的;另外,linker只会加载某一S0一次,那么linker应该维护了一个数据表来记录。进一步分析还可以发现,这个void *handle对象应该指向了当前打开SO的数据对象。有了这个思路,翻看dl函数源码(位于:\bionic\linker\dlfcn.c,不是在bionic\libdl\libdl.c),dlopen源码:
void *dlopen(const char *filename, int flag)
{
soinfo*ret;
pthread_mutex_lock(&dl_lock);
ret = find_library(filename);
if(unlikely(ret == NULL)) {
set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
}else {
ret->refcount++;
}
pthread_mutex_unlock(&dl_lock);
return ret;
}
标红部分可以看到,ret就是handle。翻看linker源码,其实际为:soinfo结构体(截取部分结构)
struct soinfo
{
const char name[SOINFO_NAME_LEN];
Elf32_Phdr *phdr; //Elf32_Phdr 实际内存地址
intphnum;
unsigned entry;
unsigned base; //SO起始
unsigned size; //内存对齐后占用大小

intunused; // DO NOT USE, maintained forcompatibility.
unsigned *dynamic; //.dynamic实际内存地址

unsigned wrprotect_start; //mprotect调用
unsigned wrprotect_end;

soinfo *next; //下一个soinfo
unsigned flags;

const char *strtab; //.strtab实际内存地址
Elf32_Sym *symtab; //. symtab实际内存地址

//hash起始位置:bucket – 2 * sizeof(int)
unsigned nbucket; //size = nbucket * sizeof(int)
unsigned nchain; //size = nchain * sizeof(int)
unsigned *bucket;
unsigned *chain;

unsigned *plt_got; //对应.dynamic: DT_PLTGOT

Elf32_Rel *plt_rel; //函数重定位表
unsigned plt_rel_count;

Elf32_Rel *rel; //符号重定位表
unsigned rel_count;
….
};
从这个结构中,已经可以得到各种信息,直接用于后续重建。另外,还有一点:dlopen返回soinfo时,linker已经执行了init_array中的函数。换句话说,已经实现了自解密,直接dump就是OK。
二、改进PLT和GOT重建

http://bbs.pediy.com/showthread.php?t=192874帖子中,PLT和GOT section并不能直接从.dynamic中获取。重建时,通过section之间的排列关系,间接的进行修正。如果想对位置变化,这种重建是无意义的。影响相对位置变化主要有:链接脚本的细微区别和SO经过DIY。比如,不同版本的ndk存在细微差异:

图 1

图2
另外,GOT结构也不同,相应链接脚本中也存在顺序不一致。比如:.got : { *(.got.plt) *(.igot.plt)*(.got) *(.igot) } 就是函数符号在前,其他符号在后,和之前讨论的是相反的。由于存在上述原因,对PLT和GOT的重建进行如下改进。

2.1PLT section

由于优化,PLT结构前四项是固定代码。

图 3
借鉴window内核中搜索未导出符号的思路,通过搜索前16个字节来确定plt。恰好这里刚好够16个字节(真是无巧不成书),即:
staticunsigned g_plt_start[] = {

0xe52de004, 0xe59fe004, 0xe08fe00e,0xe5bef008 };

这样就可以得到plt section的起始地址。Size前面帖子中已经说明,这里就不在赘述。

2.2GOT section

前面已经提到GOT表存在两种结构。另外,.got与.rel的对应关系并不像.got.plt与.rel.plt的对应关系那么稳定,受到诸如指针间址寻址影响。但始终有一点:.got中的项一定出现在.rel section中。那么重建的思路就是:
Step1:读取DT_PLTGOT,获取__global_offset_table__地址,记为:plt_got
Step2:读取plt_got – 4地址的数值,在.rel表中进行搜索。如果匹配,说明GOT结构式:{.got, .got.plt},转3.1;否则为{.got.plt, .got}转3.2
Step3.1:继续向前搜索,直到搜索到起始位置。
Step3.2:调整搜索起始位置:plt_got + 4 * (3 + rel_plt_count),向后搜索,搜索到末尾。这里,存在一种情况:若下面.data也有重定位项且处于.data起始连续位置,也会被搜索到。但对于.got和.data都对应到.rel重定位中,重定位方式相同,统一处理也是合理的,实测不存在问题。
通过搜索,即可准确获取GOT起始地址和长度,完成重建。
另外,对于.data和.rodata的重建目前没有很好的思路,仅只通过相对位置重定位。如果有更好的思路,请告知我学习学习,衷心感谢。
三、 SODUMP出炉

经过上面讨论,SODUMP工具基本成型,剩下的就是添砖添瓦,做成一个apk。通过EditText和Button配合,将待dumpSO进行处理,记得使用dlclose关闭,最好使用dlerr把错误信息打印出来便于定位问题。废话不多说,上几张测试图:
此贴http://bbs.pediy.com/showthread.php?t=190384&viewgoodnees=1&prefixid=
SO文件脱壳如下,http://bbs.pediy.com/showthread.php?t=188793&viewgoodnees=1&prefixid= 帖子类似,都为某公司一种模式,就不贴了。

图4 脱壳前

图5 脱壳后
一朋友给的某手游游戏,据说是美杜莎壳。当然,这仅仅只是该壳子的一个很小方面,这壳子很生猛的。

图6 脱壳前

图7 脱壳后
四、参考文献

Linker.c、dlfcn.c源码

http://bbs.pediy.com/showthread.php?t=192874

http://bbs.pediy.com/showthread.php?t=190384&viewgoodnees=1&prefixid=
http://bbs.pediy.com/showthread.php?t=193720&viewgoodnees=1&prefixid=
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: