运行时修改内存中的Dalvik指令来改变代码逻辑

一、前言
最近在弄脱壳的时候发现有些加固平台的加固方式是修改了dex文件结构,然后在加载dex到内存的时候,在进行dex格式修复,从而达到了apk保护的效果,那么在dex加载到内存的时候,如何进行dex格式的修复呢?其实原理就是基于运行时修改内存中的Dalvik数据,本文就来用一个简单的例子来介绍一下如何在内存中去修改Dalvik指令代码来改变代码本生的运行逻辑。
首先来说一下案例场景:

本文的案例就是将一个类的方法改变他的运行逻辑,原来的逻辑是加法操作,现在改成乘法操作。

二、案例介绍
这里在TestAdd类中有一个加法的操作方法,然后我们在native层去修改Dalvik指令,修改这个方法为乘法操作
这里写图片描述
这里我们可以看看TestAdd类的实现:
这里写图片描述
只是一个简单的加法操作,下面来调用运行测试:
这里写图片描述
测试结果如下:
这里写图片描述
看到了测试结果,发现是乘法,而不是加法的结过,好了,到这里我们就演示完了项目结构,下面来开始说说如何修改的。
三、代码解析
这里把修改指令的逻辑代码放在了native层做的,其实放到Java层也是可以的,但是会发现在操作内存字节的时候,Java会显得很无力,因为他没有指针,指针真的很好很强大,特别是在操作文件和内存字节的时候,那写代码都很爽的。
在MainActivity中定义了一个native方法:

public static native int modifyBytecode();

我们使用javah指令产生头文件:
这里写图片描述
运行命令的时候,注意目录和类全名没有后缀。
把产生的头文件拷贝到工程中:
这里写图片描述
四、原理解析
先说一下dex的文件结构

到这里我们就介绍完了上面几种数据结构,下面来总结一下:
首先用一张图来看看:

1》首先介绍了Uleb128数据结构,这个数据结构是贯穿所有的数据结构的,所以这个数据结构是最基本的。
2》然后介绍了string_ids_item数据结构,这里需要把dex中所有的字符串解析出来存放在一个常量池中,后续的数据结构会通过索引值来获取。比如type_ids_item数据结构中的idx字段指向的就是这个索引值。
3》然后介绍了type_ids_item数据结构,这里的字段主要就是指向字符串常量池的索引值,解析完这个数据结构之后也是需要用一个常量池存储索引值,后续的数据结构会通过索引值来获取,比如class_idx信息。
4》然后介绍了class_def_item数据结构,这里的字段主要是类的具体数据的偏移地址,类的索引值class_idx(这个是通过TypeId池获取)。
5》然后介绍了method_id_item数据结构,这里主要是开始解析方法id内容,其中name_idx字段是字符串常量池中的值(通过StringId池获取),以及这个方法所在类的class_idx值。
6》然后介绍了class_data_item数据结构,这个结构主要存储的是这个类对应代码的元信息,其中direct_methods thod字段和virtual_methods字段就是存储的是类对应的指令元信息。他们的结构是encoded_method。
7》然后介绍了encoded_method数据结构,这个结构中主要存储的是这个方法对应的元信息,其中method_idx_diff字段是上面得到的Method类型的id常量池索引值,code_off字段是这个方法指令对应的相对地址。
8》最后介绍了code_item数据结构,其中insns字段就是存储的是方法的指令数据。
来看看各个数据结构之间的关系:
这里写图片描述
这里就算全部解析完了本文需要用到的数据结构,以及这些结构相互引用关系,这里还需要注意的是:这里的一些结构的解析地址是存放在dex的头部信息中的:
这里写图片描述
下面我们在看看代码怎么去实现它,首先我们通过上面的例子看到,有一个字符串索引常量池,而我们现在如果想改一个方法的指令代码的话,肯定得找到他对应的code_off地址即可,现在我们有的入口条件就是:方法名+类名,所以思路是这样的:
类名=》字符串索引常量池=》类型TypeId=》类的定义元信息ClassDefItem=》类的代码元信息ClassDataItem

方法名=》字符串索引常量池+类的TypeId=》方法Id

方法Id+类代码元信息ClassDataItem=》方法的元信息EncodeMethod=》方法的指令代码结构Code
有了这个思路,下面来看具体代码吧:

第一步:获取应用的内存数据地址,读取/proc/pid/maps文件
这里写图片描述
第二步:解析出dex文件的内存地址
因为我们知道一个进程的maps内存中是有很多数据的,所以这里需要先找到dex数据对应的起始地址:
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值