加密so文件中指定的函数

130 篇文章 4 订阅
34 篇文章 0 订阅

加密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
 加密程序执行效果:
解密过程效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值