加密so文件中指定的函数

来源:互联网 发布:vb app 编辑:程序博客网 时间:2024/04/30 15:16

加密so文件中指定的函数

作者: 0n1y3nd丶 分类: 逆向学习 发布时间: 2014-09-04 22:24 ė 61条评论

前言

         上一篇文章中详细分析了对so文件中自定义section的加密,这一篇来分析下对so文件中自定义函数的加密
          原文地址:http://bbs.pediy.com/showthread.php?t=191649

0×1

        需要加密的函数是 : Java_com_example_shelldemo2_MainActivity_getString

0×2

加密

a、整个加密过程中最重要的便是在文件中找到指定函数的位置,然后去做加密处理,最后将加密过后的数据写入原位置

b、从一个ELF动态链接库文件中,根据已知的函数名称,找到相应的函数起始地址的过程如下:

从ELF的header找到文件的偏移ehdr->e_phoff。找到d_tag为PT_DYNAMICpargram header
一个phdr对应一个Segment。包含了好几个节
从这个Segment开始位置找到名为:DT_DYNAMIC的节,然后从这个节中找到Elf32_Sym这个一个结构
根据结构的成员变量st_name,来和函数名称比较,相符,就用st_valuest_size两个变量找到函数的数据
c、结合代码详细分析此流程
①、main函数:

②、findTargetSectionAddr 函数,根据section名称找到对应的section位置,这里就不做详细介绍了,上一篇中已经详细提到过。

③、getTargetFuncInfo 函数,根据函数名称,寻找函数地址及大小
该函数返回包含函数信息的结构体funcInfo
st_value代表位置,st_size代表大小,根据位置和大小 去读取函数的信息。
d、文字叙述:
根据e_phoff找到第一个program header
根据p_type 找到 p_type == PT_DYNAMIC 的这个phdr  [数组元素给出动态链接信息]
此段包含.dynamic这个section
通过.dynamic这个里面的p_offset就能找到Elf32_Dyn这样一个结构体
根据d_tag标识,找到标识为 d_tag == DT_SYMTAB、d_tag == DT_HASH、d_tag ==DT_STRTAB、d_tag == DT_STRSZ、的这一系列section。
申请大小为d_uu.d_val的内存空间,为读取.dynstr做准备
可以借助readelf查看.dynstr这个节里的内容
可以知道.dynstr这个section中保存的正是所有函数的名称
通过函数名称,调用elfhash函数,计算出一个hash值
读取hash表里面的一些信息
读取.hash这个section的前四字节。保存在nbucket
读取.hash这个section的第4-8字节。保存在nchain
那么,这两个数值有什么用呢
这得从hash表的组织结构说起
hash表的结构如下:
nbucket
nchain
bucket[nbucket]
chain[nchain]
4部分,nbucket,nchain,bucket数组,chain数组
两个数组中都保存着符号表索引。
hash函数根据函数名称得到一个hash值,设为X,则bucket[X % nbucket]给出了一个索引,设为Y
该索引可用于符号表,也可用于chain表,如果符号表项不是所需要的,那么chain[Y]则给出了具有相同hash值的下一个符号表项
我们就可以根据chain这个类似于链的结构,一直向下搜索。直到找到所需的符号表项。或者chain项中包含值STN_UNDEF。
通过hash表,能够找到一系列的符号表
符号表结构如下
通过st_name来判断找到的符号表正是我们需要的
所有有了下面这样一个循环
这个循环的发生是在bucket数组中没有找到我们需要的符号表才进入的。也就是说,这个过程其实是在遍历chain这个数组
 lseek(fd, dyn_hash + 4 * (2 + nbucket + funIndex), SEEK_SET);
其中funIndex是函数的索引值
hash表前两项是 nbucket 和 nchain 两个int型数据。
还有一个int型数组bucket[] 长度是nbucket
所以,根据dyn_hash + (2 + nbucket + funIndex) * 4 便实现了根据索引定位到chain数组中函数的位置
然后再去dyn_symtab中找到对应的Elf32_Sym结构
根据其中的st_name来进行判断,循环查找

0×3

解密
a、解密的过程和加密过程基本上一致的,只是说我们必须得到内存中去寻找那一系列的地址。
大致过程是:
在内存中找到so文件被加载到的地址,记为base
寻找函数
修改内存页属性
解密函数数据
还原内存页属性
b、解密入口函数如下:

里面用到了getLibAddr,getTargetFuncInfo两个函数。

getLibAddr函数用来在程序的内存空间中找到so被加载到的位置。

getTargetFuncInfo函数是用来在程序内存空间中的so中找到需要解密的函数。

可以看到,和加密过程中寻找函数地址是一样的。只是在定位过程中得计算偏移地址。

0×4

 加密程序执行效果:
解密过程效果:

0 0
原创粉丝点击