想必打过CTF的小伙伴多多少少都触过Android逆向,所以斗哥将给大家整一期关于Android逆向的静态分析与动态分析。本期先带来Android逆向的静态分析,包括逆向工具使用、文件说明、例题解析等。

Android逆向就是反编译的过程,因为看不懂Android正向编译后的结果所以CTF中静态分析的前提是将出现文件反编译到我们看得懂一层源码,进行静态分析。

0X01 基础说明

Android应用的逻辑代码是由Java进行开发,所以是第一层就是java代码
Java虚拟机JVM运行的是java文件编译过后的class文件
Android虚拟机Dalvik并不是执行Java虚拟机JVM编译后生成的class文件,而是执行再重新整合打包后生成的dex文件编译之后的smali文件
APK:是编译完成后的Android应用程序安装包
dex文件:是class文件的打包文件
smali文件:是Dalvik字节码文件
class文件:是JVM字节码文件

0X02 工具使用

在CTF中Android题目不一定给你完整编译完成后的APK,可能是编译过程中任意文件类型,下面斗哥分以下文件类型利用工具来得到斗哥看得懂的java源码

类型一:class文件

这种情况比较简单,推荐工具jd-gui
直接将class文件拉进去就可以看到java源码。

类型二:APK程序

Android工程编译完成会得到我们想要的APK安装包,APK文件其实是一个压缩包。
修改后缀名为zip后解压,解压后的文件如下图所示:

META-INF文件夹:
存放apk签名信息,用来保证apk包的完整性和系统的安全。

res文件夹:
存放资源文件,包括icon,xml文件。

AndroidManifest.xml文件:
应用程序配置文件,每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等信息。

classes.dex文件:
可以直接在Dalvik虚拟机上加载运行的文件,由java文件经过IDE编译生成。

resources.arsc文件>
二进制资源文件,包括字符串等。

反编译APK推荐工具ApkIDE、JEB
1. JEB使用:
JEB直接导入APK,反编译完成看到smali文件。

很多Android逆向工具就反编译到smali文件这步。
JEB选中smali文件中按Q,就可以看到java文件。

优点:从smali文件反编译成的java文件代码结构清晰。
缺点:无法修改。
2. ApkIDE使用:
项目->打开Apk
等待反编译完成。

看到smali文件。

选择要java源码的smali文件,点击下图按钮,打开Java源码。

ApkIDE关联了jd-gui,点击后将跳转到jd-gui。

ApkIDE是将APK反编译到class再用jd-gui拿到Java源码。
在ApkIDE的ApkIDE_v3.3\ApkIDE\Worksrc的项目目录下可以看到反编译后的class文件。

优点:功能强大,可以修改反编译出来的smali文件,重新编译生成APK。
缺点:编译成后的java代码不够清晰。

3.反编译区别
Smali文件是由Smali语法编写,Smali语法宽松式的语法
所以反编译过程不同,工具不同,java源码肯定不同
下面是同一个APK用上面两个工具逆向的结果:

斗哥作为一名Java开发的爱好者喜欢JEB的逆向结果,看着比较舒服。

类型三:dex文件

推荐工具dex2.jar
classes.dex文件,这个是Android源码编译过的字节码包
尝试使用dex2.jar工具拿到java源码命令如下
.\d2j-dex2jar.bat C:\Users\lin\Desktop\classes.dex

jar文件可以理解为classes文件的压缩包,java虚拟机可以直接运行
用Jd-gui打开classes-dex2jar.jar就可以看到java源码

类型四:smali文件

当只有一个单独的smali文件时就无法用上述的工具直接进行反编译
斗哥想到ApkIDE可以对一个APK进行反编译到smali文件,对smali文件进行增删改查的操作
于是用ApkIDE打开任意一个完整的APK然后添加smali文件(APK可以用自己开发的)

将smali文件添加ApkIDE项目中。

重新编译生成APK。

编译成功后将在原APK目录生成一个APK。

再用JEB等工具打开就能看到Ezreal.smali文件。

其他工具:

编辑器:notepad++、Sublime等
Android模拟器:夜神模拟器等

0X04 例题分析

将应用安装到模拟器查看界面是否有提示。
在文本框输入字符点击按钮提示错误,猜想是否用来判断正确的flag。

使用JEB工具编译成java文件,Android文件下是sdk文件,我们要分析是com包下的源码文件。

代码量不多就三个类,先从程序入口MainActivity分析,找到关键代码块。
这句if就是判断flag是否正确。

[PHP] 纯文本查看 复制代码
1
2
3
if(!"flag{" + v5.toString() + "}".equalsIgnoreCase(arg12)) {
 
  return v7;}

搜索类查看哪里调用了此方法。
分析得到arg12就是界面要输入的参数,这时我们知道了v5的值就是我们要的flag。

onCreate函数调用了checkSN方法并传入两个参数为:
MainActivity.this.edit_userName.trim()
MainActivity.this.edit_sn.getText().toString().trim()

[PHP] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//OnCreate是Android中的一个特别的函数,用来“表示一个窗口正在生成”。
 
//其不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置颜色等。
 
public void onCreate(Bundle arg3) {
 
   super.onCreate(arg3);
 
   this.setContentView(0x7F040019);
 
   this.setTitle(0x7F06001D);
 
   this.edit_userName = "Tenshine";
 
   this.edit_sn = this.findViewById(0x7F0C0051);
 
   this.btn_register = this.findViewById(0x7F0C0052);
 
   this.btn_register.setOnClickListener(new View$OnClickListener() {
 
       public void onClick(View arg5) {
 
           if(!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim())) {
 
               Toast.makeText(MainActivity.this, 0x7F06001E, 0).show();
 
           }
 
           else {
 
               Toast.makeText(MainActivity.this, 0x7F06001B, 0).show();
 
               MainActivity.this.btn_register.setEnabled(false);
 
               MainActivity.this.setTitle(0x7F060019);
 
           }
 
       }
 
   });
 
}

分析v5的值,v5是由v3和v4生成的,v4是一个int并直接赋值为0用于循环就可以直接使用
而v3则是toHexString方法的返回值,并要传入,v1是v1.update(arg11.getBytes());生成
arg11就是传入的参数"Tenshine"

[PHP] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
private boolean checkSN(String arg11, String arg12) {
 
   boolean v7 = false;
 
   if(arg11 != null) {
 
       try {
 
           if(arg11.length() == 0) {
 
               return v7;
 
           }
 
           if(arg12 == null) {
 
               return v7;
 
           }
 
           if(arg12.length() != 22) {
 
               return v7;
 
           }
 
           MessageDigest v1 = MessageDigest.getInstance("MD5");
 
           v1.reset();
 
           v1.update(arg11.getBytes());
 
           String v3 = MainActivity.toHexString(v1.digest(), "");
 
           StringBuilder v5 = new StringBuilder();
 
           int v4;
 
           for(v4 = 0; v4 < v3.length(); v4 += 2) {
 
               v5.append(v3.charAt(v4));
 
           }
 
           if(!"flag{" + v5.toString() + "}".equalsIgnoreCase(arg12)) {
 
               return v7;
 
           }
 
       }
 
       catch(NoSuchAlgorithmException v2) {
 
           goto label_40;
 
       }
 
       v7 = true;
 
   }
 
   return v7;
 
label_40:
 
   v2.printStackTrace();
 
   return v7;
 
}

将上面的分析结果,取出生成v5的关系代码
都是纯java代码,不需要Android的包引入,只需引入java的依赖包。

[PHP] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.security.MessageDigest;
 
import java.security.NoSuchAlgorithmException;
 
public class Code {
 
   static String toHexString(byte[] arg8, String arg9) {
 
       StringBuilder v3 = new StringBuilder();
 
       byte[] v0 = arg8;
 
       int v5 = v0.length;
 
       int v4;
 
       for(v4 = 0; v4 < v5; ++v4) {
 
           String v2 = Integer.toHexString(v0[v4] & 255);
 
           if(v2.length() == 1) {
 
               v3.append('0');
 
           }
 
           v3.append(v2).append(arg9);
 
       }
 
       return v3.toString();
 
   }
 
   public static void main(String[] args)throws NoSuchAlgorithmException{
 
       MessageDigest v1 = MessageDigest.getInstance("MD5");
 
       v1.reset();
 
       v1.update("Tenshine".getBytes());
 
       String v3 = Code.toHexString(v1.digest(), "");
 
       StringBuilder v5 = new StringBuilder();
 
       int v4;
 
       for(v4 = 0; v4 < v3.length(); v4 += 2) {
 
           v5.append(v3.charAt(v4));
 
       }
 
       System.out.println("flag{" + v5.toString() + "}");
 
   }
 
}

用IDEA编辑运行,拿到flag。

0X05 小小总结

下期斗哥将带来Android逆向之动态分析,讲述Android开发入门、smali语法解析、动态调式smali文件。

大家有任何问题可以提问,更多文章可到i春秋论坛阅读哟~

Android逆向之静态分析的更多相关文章

  1. [转]Android逆向之动态调试总结

    一.在SO中关键函数上下断点 刚学逆向调试时.大多都满足于在SO中某关键函数上下断点.然后通过操作应用程序,去触发这个断点,然后进行调试 详细的步骤可以参见非虫大大的<Android软件安全与逆 ...

  2. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)

    Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...

  3. android逆向学习小结--CrackMe_1

    断断续续的总算的把android开发和逆向的这两本书看完了,虽然没有java,和android开发的基础,但总体感觉起来还是比较能接收的,毕竟都是触类旁通的.当然要深入的话还需要对这门语言的细节特性和 ...

  4. Android逆向之so的半自动化逆向

    因为工作需要,转型干android逆向,有几个月了.不过对于so的逆向,任然停留在,难难难的阶段,虽然上次自己还是逆向了一个15k左右的小so文件,但是,那个基本是靠,一步一步跟代码,查看堆栈信息来自 ...

  5. Android逆向破解表单注册程序

    Android逆向破解表单注册程序 Android开发 ADT: android studio(as) 程序界面如下,注册码为6位随机数字,注册成功时弹出通知注册成功,注册失败时弹出通知注册失败. 布 ...

  6. Android逆向破解表单登录程序

    Android逆向破解表单登录程序 Android开发 ADT: android studio(as) 程序界面如下,登录成功时弹出通知登录成功,登录失败时弹出通知登录失败. 布局代码 <?xm ...

  7. Android 逆向实战篇(加密数据包破解)

    1. 实战背景由于工作需要,要爬取某款App的数据,App的具体名称此处不便透露,避免他们发现并修改加密逻辑我就得重新破解了. 爬取这款App时发现,抓包抓到的数据是加密过的,如图1所示(原数据较长, ...

  8. 【转】Android逆向入门流程

    原文:https://www.jianshu.com/p/71fb7ccc05ff 0.写在前面 本文是笔者自学笔记,以破解某目标apk的方式进行学习,中间辅以原理性知识,方便面试需求. 参考文章的原 ...

  9. Android逆向之smali

    Android逆向之smali 头信息 smail文件前三行 .class <访问权限> [关键修饰字] <类名>; .super <父类名>; .source & ...

随机推荐

  1. pythone函数基础(15)接口开发初识

    导入需要的第三方模块 import flaskimport toolsimport json,redisimport random server = flask.Flask(__name__)#新建一 ...

  2. koa中间件

    koa是Express的下一代基于node的web框架  目前有1.x和2.0两个版本 1. Express Express是第一代最流行的web框架  它对node.js的http进行了封装 Exp ...

  3. CSRedisCore 在net core中的使用

    背景:与net core配套的StackExchange.Redis客户端总是间歇性的发生timeout异常. 由complexer单例对象创建的IDatabase对象,在产生Timeout异常后会导 ...

  4. Python内置的服务器的使用

    cd 到某一文件 Python内置的服务器: E:\myObject\office\netObject\new-gcms> python -m SimpleHTTPServer 8888 如果是 ...

  5. JS的作用域链

    JavaScript词法性质作用域 简而言之就是,在JavaScript中,函数的作用域在编译时期就已经确定下来了,而不是取决于他的执行位置 var num = 10; function method ...

  6. 详解slab机制

    转 详解slab机制 2015年01月15日 16:34:47 cosmoslhf 阅读数:12657   http://blog.csdn.net/u010246947/article/detail ...

  7. NumPy学习_02 ndarray基本操作

    1.算术运算符 它们只用于位置相同的元素之间,即为元素级的运算. 所得到的运算结果组成一个新的数组. 不用编写循环即可对数据执行批量运算.(矢量化) import numpy as np # 创建一个 ...

  8. EasyPR源码剖析(2):车牌定位

    上一篇主要介绍了车牌识别的整体框架和流程,车牌识别主要划分为了两个过程:即车牌检测和字符识别,而车牌识别的核心环节就是这一节主要介绍的车牌定位,即 Plate Locate.车牌定位主要是将图片中有可 ...

  9. Eclipse 新建 Maven web 项目

    File --> New --> Maven Project --> 选择存放路径 --> 选择骨架 --> 输入Maven坐标 --> 初步成型,下面还要配置 1 ...

  10. OO第9-11作业总结

    一. 规格化设计   规格化抽象,即将执行的细节抽象为用户所需求的行为(模块做什么). 主要作用在于提高工程设计中的可维护性,可读性,明确功能,使整个编程任务变得清晰有序以减少程序BUG. 说其发展历 ...