Android ELF文件根据函数名查找函数位置

时间:2024-04-01 10:07:45

一、前言

最近一段时间,工作比较空闲,准备研究下so文件上的函数加密和函数名混淆,首先从根据函数名找到对应代码开始。记得很早之前,自己写过一个ELF解析工具,到现在都忘得差不多了,趁现在这个机会,顺便复习下。本文给出两种方法来查找函数代码位置,第一种是直接遍历动态符号表,取出字符串与目标函数名比较,找到之后,根据里面的字段来得到函数代码位置。第二种是根据ELF文件中的hash节来遍历动态符号表,android源码中用的是第二种方法。我们先讲第一种方法。

 

二、直接遍历动态符号表

首先找到ELF头,ELF头里包含两我们所需的字段,节区头数组的起始偏移和该数组的大小,e_shoff表示节区头数组的偏移 e_shnum表示数组的大小

Android ELF文件根据函数名查找函数位置

接着根据节区头数组的起始偏移和该数组的大小遍历节区头,在这里我们找到节区头的sh_type字段为dynsyn的节头,找到对应节头之后,在节头中找到节的偏移(sh_offset),和节的大小(sh_size)。

Android ELF文件根据函数名查找函数位置

找到dynsyn的节后,里面是一个结构体数组,可以看到这个结构体中有个st_name字段,它就是我们要找的函数名,但它的数据类型却是一个Elf_32_word(其实就是一个unsigned int),并不是一个字符串,其实它是一个字符串的偏移,这个字符串也存储在一个节中,要找到这个节,当然也要遍历节头数组,跟找类型为dynsyn的节头的方法是一样的,只是这里的类型为dynstr。找打节头后,找到对应节的偏移再加上面提到的st_name,就找到了对应的字符串,接着根据这个方法遍历结构体数组中的所有字符串跟我们自己的目标函数字符串做比较,找打所需的结构体,根据里面的结构体里的字段st_value和st_size,分别找到对应代码的首地址和代码的大小。最后,我们还需要做代码修正,因为目标函数是arm指令,还是thumb指令,对其所做的操作是不一样的。下面的第四部分会介绍代码的修正,这里先不介绍。

Android ELF文件根据函数名查找函数位置

 

三、根据.hash节遍历动态符号表

首先遍历节区头,找到type字段为.hash的节区头,根据节区头找到对应的节区,这个节区是一个无符号整数数组,首先该数组的第一个数(索引为0)是nbucket,代表bucket数组的大小,第二个数(索引为1)是nchain,代表chain数组的大小。chain数组紧跟bucket数组。如下图所示。

Android ELF文件根据函数名查找函数位置

知道了数据结构,接下来就要看怎么使用了,首先将我们要查找的函数名用hash算法进行计算,hash算法在android4.4源码中的linker.cpp中有给出,它的参数是我们给的函数名,返回一个无符号整数。

Android ELF文件根据函数名查找函数位置

得到elfhash函数的返回值后,用这个返回值对nbucket取余,得到值mod,接着得到Y = bucket[mod],比较Y是否为0,不为0的话,将Y做为索引去动态符号表上查找数据,找到符号表的结构后,取出函数名进行比较,假如不是的话,将Y值做为索引在chain数组上查找下一个数。代码如下。

Android ELF文件根据函数名查找函数位置

 

四、代码修正

本来代码的编写就到此为止了,但本人将同样的ELF文件拖入到IDA Pro中(一款反编译工具)和自己所编写的解析工具中,发现IDA  Pro中显示的函数起始地址比自己解析出来的少1个字节的偏移。

我的:

Android ELF文件根据函数名查找函数位置

ida的:

Android ELF文件根据函数名查找函数位置

这是因为在arm体系架构中,通常arm指令的字节数都是4字节的,还有一种叫做thumb的指令集通常为两字节的。后来又出了一种叫thumb-2的,两字节和四字节混搭的,但是不管几字节,从arm模式转换到thumb模式时,会执行一条跳转指令(BLX或者BX),处理器会检查目标地址的最后一位是否为1,为1的话说明需要切换到thumb模式。同理thumb模式切换到arm模式,会检查最后一位是否为0,为0就切换到arm模式。这时候就明白了,自己解析出来的函数地址,需要减一才是函数执行的起始地址,多出来的1是为了程序在执行的时候能区分出arm模式切换到thumb模式。这也解决了以前看IDA Pro中的thumb代码总感觉不对,因为IDA Pro显示的是真实跳转地址。

五、总结

做为一个从事android逆向人员,对ELF文件都应该了解,更需要编写代码来实践。本文是对以前ELF文件的复习和扩展,也为以后编写so文件加密打下一个基础。