带你开发一款给Apk中自动注入代码工具icodetools(开凿篇)

Android技术篇 尼古拉斯.赵四 13946℃ 0评论

一、前言

从这篇开始咋们开始一个全新的静态方式逆向工具icodetools的实现过程,这个也是我自己第一次写的个人觉得比较有用的小工具,特别是在静态方式逆向apk找关键点的时候,后续会分为三篇来详细介绍这个工具实现:

第一篇:开凿篇,简单介绍实现原理以及简单的初次方案实现简单的apk注入代码功能

第二篇:填坑篇,这一篇是在前一篇的基础上对工具的优化,可以应对市面上大部分的apk代码注入功能实现

第三篇:生产篇,这一篇是在前两篇的基础上利用这个工具来实际操刀如何进行快速定位应用的关键方法功能

还记得那一年咋们 静态方式破解应用,为了更好的追踪代码位置,手动反编译成smali文件,然后添加smali日志代码,在回编译,查看日志信息来定位关键点。那种操作现在回想是苦不堪言,操作非常复杂。那么就尝试想想如果有一个工具可以在自动为每个方法注入日志代码,这样就可以很快速的定位到我们想要的方法,所以本文就来介绍一下这个工具的实现原理,我将其命名为icodetools

 

二、实现方案

首先咋们来看一下具体实现原理吧,这个工具最终的形态应该是这样的,就是输入一个apk,然后在为apk中每个类的每个方法添加一段打印此方法的堆栈信息日志,然后在重新签名打包成新的apk。所以这个过程中我们最关键的地方就是如何把日志代码插入到已经编译好的apk中。我们可能想到的有两个方案:

第一个方案:首先利用apktool进行反编译成smali文件,然后解析smali文件找到每个方法的位置,添加指定smali日志代码。那么这里有一个很大的问题,就是如何分析smali文件,如何定位到每个方法?这个过程工作量就比较大了,所以这个方案就废弃了。

第二个方案:利用dex2jar获取到apk中的dex转化之后的jar文件,然后在解析jar文件获取到每个class文件,解析class文件进行方法的信息获取。这里会发现这个方案很靠谱,因为我们解析class文件比解析smali文件方便多了。而且在这个过程中会发现有一个更大的惊喜,就是dex2jar这个工具是开源的,其实内部实现原理就是解析dex文件格式,然后借助asm工具将其变成class文件的,这里又出现了一个非常重要的工具asm,这个工具下面会详细介绍。

说明:

1》这里非常感谢dex2jar的作者Claud大神的开源精神,这个工具的地址:https://github.com/pxb1988/dex2jar,是纯java代码,所以大家一定要先解读这个工具源码,内部实现原理自己研读,本文不会详细介绍的。

2》这里有的同学会想到,能不能直接解析dex文件格式,然后在找到每个类的每个方法添加日志信息,虽然我们在前面有详细介绍dex文件格式:Dex文件格式详解,但是如果想在每个类每个方法中添加日志代码这个工作量感觉比操作smali还要复杂,所以直接将其转化成class文件进行操作就非常方便了,因为我们有asm工具。

 


三、方案实现

上面已经探讨了方案了,在上面提到了很多次一个非常重要的工具就是asm,那么这个工具到底是干嘛的呢?这个工具非常有用,他的表现之处在JavaWeb开发中的Spring框架就有用到,可以动态的解析class文件,然后可以操作这个类,比如添加类成员,方法等等操作。所以下面不多解释了,直接用一个简单的案例来看看他的强大之处,我们实现给一个类添加一个成员字段,方法,给每个方法调用前添加一行代码。

第一、asm库基本使用

这里借助ClassReader来读取一个类,使用ClassVisitor来进行类信息操作,ClassWriter将操作完之后的类写入文件中


第二、添加类成员字段

上面看到了一个主要的类ClassVistor,他主要就是用来操作一个类:

这里看到的是继承了ClassAdapter,然后在构造方法中可以添加类成员信息包括字段,方法等,这里我们添加一个字段mJW,类型是String的。看看如何添加的:

借助ClassVisitor的visitField方法就可以进行字段的添加了。然后我们运行程序之后,使用JD-GUI工具查看保存本地的class文件信息:

看到了吧,这里成功的定义了一个字段mJW。

第三、为类的所有方法前添加代码

这里我们需要借助另外一个类了MethodVisitor了,他是用来操作方法信息的:

在ClassAdapter的visitMethod回调方法中可以获取方法信息,然后进行操作:

在visitCode回调方法中利用MethodVisitor开始添加代码:

这里看到可以利用visitFieldInsn方法方法System类的静态变量out,然后在使用visitLdcInsn从常量池中获取值,最后在利用visitMethodInsn方法来调用PrintStream类的成员方法println来打印信息,运行程序之后继续借助JD-GUI来查看class文件:

看到了,类中所有的方法前面都被加了一行打印代码。

注意:有的同学发现了,上面那个添加代码怎么得到呢?难道真的要记住那么多api去添加吗?其实不用那么复杂,Eclipse有一个插件Bytecode,可以把Java代码自动生成类似于上面的代码,咋们之后手动拷贝一下就好了!工具后面会说。

第四、为类添加成员方法

下面在来看最后一个操作吧,就是给类中添加一个成员方法,有了上面的操作之后我们应该知道,如果要操作类就要借助ClassVisitor类,要是操作方法就需要借助MethodVisitor类,那么这里为类添加成员方法,借助ClassVistor类来进行操作了,但是在操作之前咋们得先搞好一个工具Bytecode,这个是Eclipse插件,安装很简单:

安装完成之后,可以打开视图栏:

然后选择Java中的bytecode视图就可以了:

下面咋们首先在一个类中编写好我们想要添加的方法代码,然后点击Bytecode视图卡片就可以看到对应的asm代码:

看到了吧,这样操作是不是如此简单,我们可以把这段asm代码直接拷贝到AsmUtils中:

然后在ClassVisitor的构造方法中直接调用这个方法就可以了:

再次运行程序之后,使用JD-GUI查看类信息:

成功的添加了printStackTrace方法了。就是如此简单。借助Eclipse的强大工具Bytecode就可以了,以后都不要在自己去调用asm库的api去手动编写了。这个工具太好了得记住它!

 

四、工具案例实践

上面就介绍完了如何操作一个类和方法,给类添加字段,方法,在每个方法之前添加一行代码。下面就得进入本文的主题了,如何给apk应用中每个类中的每个方法添加一行打印日志信息。在开始的时候我们有了方法,就是借助工具dex2jar源码,他内部也是解析dex格式,然后利用asm将其信息变成一个class文件的,那么我们只要在这个过程中得到ClassVisitor和MethodVisitor这两个对象,就可以尽情的干很多事了。所以第一步你一定要先看懂dex2jar的源码。这里我不会对源码进行详细分析了,用过dex2jar工具的都知道,找入口很简单,直接看他的一个d2j-dex2jar.bat脚本信息:

Dex2jarCmd就是工具的入口类:

然后分析代码,会发现处理的