【Android SDK程序逆向分析与破解系列】之五:Android APK的静态分析
2015-05-28 17:21
531 查看
作者:郭嘉
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells
【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)
【Android SDK程序逆向分析与破解系列】之三:Android可执行程序DEX分析(二)
【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析
【Android SDK程序逆向分析与破解系列】之五:Android APK的静态分析
android:label:Activity的标题
android:name:Activity的包名+类名
intent-filter:Activity的启动意图
找到主Activity后,查看该类的onCreate()函数的反汇编代码,这就是程序的入口,从这里一直往下看,追踪软件的执行流程。
APK反编译的后代码量一般非常庞大,那么定位关键代码就需要有技巧,有方法,常见的定位关键代码的方法如下所示:
注意:经过混淆的DEX文件,反编译出来的Smail代码可能没有源文件信息,即.source可能为空。
静态字段:field<访问权限>staic[修饰关键字]<字段名>:<字段类型>
实例字段:field<访问权限>[修饰关键字]<字段名>:<字段类型>
直接方法:.method<访问权限>[静态关键字]<方法原型>,起始处会注释# direct methods
虚方法:.method<访问权限>[静态关键字]<方法原型>,起始处会注释#virtual methods
内部类会被反编译成两个文件Outer.smail和Inner.smail
.implements<接口名>,起始处会注释#interfaces。
.end annotation,起始处会注释#annotations。
R类主要描述APK的资源信息,其中包含内部类,R.smail、Rattr.smail、Rattr.smail、Rdimen.smail、Rdrawable.smail、Rdrawable.smail、Rid.smail、Rstyle.smail、Rstyle.smail、Rstring.smail、R$menu.smail等。
BuildConfg类
BuildConfg类中只有一个boolean类型的DEBUG字段,用来标识程序发布的类型,true表示已调试版本发布,false表示以非调试版本发布。
注释类
如果在代码中使用了SuppresLint或TargetApi等注释,程序将会自动生成对应的类,反编译后会在smail\android\annotation目录下生成相应的Smail文件。
for循环对应的Smail代码如下所示:
两种循环生成的Smail代码非常相似,总的说来,迭代器循环有如下特点:
迭代器循环会调用迭代器的hasNext()方法检测循环条件是否满足。
迭代器循环调用迭代器的next()方法获取单个对象。
循环中使用goto指令来控制代码的流程。
for形式的迭代器循环展开后即为while形式的迭代器循环。
对应的Smail代码如下所示:
对应的Smail语句
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells
【Android SDK程序逆向分析与破解系列】章节索引
【Android SDK程序逆向分析与破解系列】之一:Android安装程序APK分析【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)
【Android SDK程序逆向分析与破解系列】之三:Android可执行程序DEX分析(二)
【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析
【Android SDK程序逆向分析与破解系列】之五:Android APK的静态分析
什么是静态分析?
静态分析(Static Analysis)是指在不运行代码的情况下,采用词法分析、语法分析等技术手段对程序文件进行扫描而生成程序的反汇编代码,然会阅读反汇编代码来掌握程序功能的一种技术。一 如何快速定位Android程序的关键代码
APK程序反编译后生成的文件中包含一个AndroidManifest.xml文件,该文件包含了软件的包名,运行系统的版本,使用的组件是破解的关键点。关注MainActivity
每个APK只有一个主Activity,它的定义如下图所示:android:label:Activity的标题
android:name:Activity的包名+类名
intent-filter:Activity的启动意图
找到主Activity后,查看该类的onCreate()函数的反汇编代码,这就是程序的入口,从这里一直往下看,追踪软件的执行流程。
关注Application
Application类主要负责在程序的组件之间传递全局变量,或者在Activity启动之前做一些初始化工作,比如商业软件的授权等等Application类在application标签中用包名+类名来注册。APK反编译的后代码量一般非常庞大,那么定位关键代码就需要有技巧,有方法,常见的定位关键代码的方法如下所示:
1.1 信息反馈法
信息反馈法是先运行目标程序,然后根据程序运行的反馈信息定位关键代码。比如商业软件需要注册,在输入错误的饿注册码时,程序会反馈“无效的注册码”等信息,类似这样的字符串一般会存储在string.xml文件中或硬编码到程序代码中,对于前者会以id的形式访问,直接在反汇编的代码中搜索字符串的id即可,对于后者,在反汇编代码中直接搜索字符串即可。1.2 特征函数法
特征函数法与信息反馈法类似,消息的提示一般最终都是由Android的API来完成,比如Toast、AlertDialog等。1.3 顺序查看法
顺序查看法是从软件的启动代码开始,逐行的向下分析,掌握软件的执行流程。这种方法在病毒分析经常用到,1.4 代码注入法
代码注入法属于动态调试方法,它的原理是手动修改APK的反汇编代码,加入Log输出,配合LogCat查看程序执行到定点的状态数据,这种方法在解密程序时经常使用。1.5 栈跟踪法
栈跟踪法属于动态调试法,然后查看栈上函数调用序列来理解方法的执行流程。1.6 方法剖析
方法剖析(Method Profiling)属于动态调试方法,它主要用于热点分析和性能优化,该功能可以记录每个函数占用的CPU时间,还能追踪所有的函数调用关系,并提供比栈跟踪法更详细的函数调用序列报告。二 Smail语法
2.1 类信息
Smail文件的头三行描述了当前类的信息.class <访问权限>[修饰关键字]<类名> .super <父类名> .source <源文件名>
注意:经过混淆的DEX文件,反编译出来的Smail代码可能没有源文件信息,即.source可能为空。
2.2 主体部分
一个类由多个字段或方法组成。2.2.1 字段
字段的声明使用.field指令。静态字段:field<访问权限>staic[修饰关键字]<字段名>:<字段类型>
实例字段:field<访问权限>[修饰关键字]<字段名>:<字段类型>
2.2.2 方法
方法的声明使用.method指令。直接方法:.method<访问权限>[静态关键字]<方法原型>,起始处会注释# direct methods
虚方法:.method<访问权限>[静态关键字]<方法原型>,起始处会注释#virtual methods
2.2.3 类
内部类
Android的内部类分为成员内部类、静态嵌套类、方法内部类和匿名内部类。class Outer { class Inner() { } }
内部类会被反编译成两个文件Outer.smail和Inner.smail
监听器
监听器的本质是接口btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { } });
.implements<接口名>,起始处会注释#interfaces。
注释类
.annotation[注释属性]<注释类名> [注释字段 = 值].end annotation,起始处会注释#annotations。
自动生成的类
R类R类主要描述APK的资源信息,其中包含内部类,R.smail、Rattr.smail、Rattr.smail、Rdimen.smail、Rdrawable.smail、Rdrawable.smail、Rid.smail、Rstyle.smail、Rstyle.smail、Rstring.smail、R$menu.smail等。
BuildConfg类
BuildConfg类中只有一个boolean类型的DEBUG字段,用来标识程序发布的类型,true表示已调试版本发布,false表示以非调试版本发布。
注释类
如果在代码中使用了SuppresLint或TargetApi等注释,程序将会自动生成对应的类,反编译后会在smail\android\annotation目录下生成相应的Smail文件。
2.2.4 循环语句
循环语句主要有两种:for循环
for(<对象><对象名>; <对象名范围>; <对象递增/递减步长>) { [处理单个对象的代码体] }
for循环对应的Smail代码如下所示:
.local v1, i:I #初始化v1为0 :goto_0 #迭代循环开始 if-1t v1, v5 :cond_0 #如果v1<v5,则跳转到cond_0标号处。 ... ... ... :cond_0 invoke-interface {v0, v1}, Ljava/util/List;->get(I)Ljava/lang/Object; #单个循环项 ... ... ... add-int/lit8 v1, v1, 0x1 #下一个索引 goto :goto_0 #跳转到循环开始处
while循环
while(<迭代器>hasNext()) { <对象><对象名> = <迭代器>.next() [处理单个对象的代码体] }
:goto_0 #迭代循环开始 invoke-interface {v4}, Ljava/util/Iterator;->hasNext()Z #开始迭代 ... ... ... invoke-interface {v4}, Ljava/util/Iterator;->next()Ljava/lang/Object #循环获取每一项 ... ... ... goto :goto_0 #跳转到循环开始处
两种循环生成的Smail代码非常相似,总的说来,迭代器循环有如下特点:
迭代器循环会调用迭代器的hasNext()方法检测循环条件是否满足。
迭代器循环调用迭代器的next()方法获取单个对象。
循环中使用goto指令来控制代码的流程。
for形式的迭代器循环展开后即为while形式的迭代器循环。
2.2.5 分支语句
switch分支语句switch(判断项) { case 判断项值1: break; case 判断项值1: break; case 判断项值1: break; default: break; }
对应的Smail代码如下所示:
packed_switch p1, :pswitch_data_0 #packed_switch分支,pswitch_data_0指定case区域 ... ... ... :pswitch_data_0 #case区域,从0开始
2.2.6 异常捕捉语句
try/catch语句try { } catch(Exception e) { }
对应的Smail语句
:try_start_0 #第一个try开始 ... ... ... :try_end_0 #第一个try结束 ... ... ... :try_start_1 #第二个try开始 ... ... ... :try_end_1 #第二个try结束 ... ... ... :goto_0 ... ... ... :catch_0 ... ... ... :try_start_2 #第三个try开始 ... ... ... :try_end_2 #第三个try结束 ... ... ... :catch_1
相关文章推荐
- 【Android SDK程序逆向分析与破解系列】之一:Android安装程序APK分析
- 【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)
- 【Android SDK程序逆向分析与破解系列】之三:Android可执行程序DEX分析(二)
- 【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析
- Android逆向之旅—静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- Android逆向之旅---静态分析技术来破解Apk
- android逆向学习,笔记(三)静态分析android程序
- Android逆向分析基础-静态分析Android程序
- 【Android安全】APK静态分析-源码反编译逆向分析
- 自用Android程序破解,逆向分析工具集
- 静态分析Android程序——smali文件解析
- Android逆向之旅---动态方式破解apk前奏篇(Eclipse动态调试smail源码)