想必打过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. VC++安装及使用

    1.在浏览器上下载后不能安装 2.黄振古QQ发原文件,依然不能安装 3.考虑后,想通过360压缩安装 4.浏览器上下载的360压缩大多有病毒,无奈下,删掉鲁大师,下载360安全卫士,通过360下载36 ...

  2. centos7 安装mysql5.7.20(yum方式)

    windows下安装mysql请访问:windows下mysql5.7.20安装(zip包方式) 一.安装过程 1.安装wget yum install wget 2.查找yum源名称 在mysql官 ...

  3. Oracle通过SCN做增量备份修复DG

    DG由于网络原因或者bug原因经常不同步,有时隔得时间久了,就会丢失归档日志,或者长时间的归档恢复较慢,有一种可以基于scn的方式来恢复DG库,使用基于scn的增量备份来恢复standby库可以节省大 ...

  4. 上传到HDFS上的文件遇到乱码问题

    1.通过eclipse中的hdfs插件上传文件,上传成功,但是查看是乱码. 查阅文件本身的编码方式,发现是utf-8,同时文件在项目目录下,显示正常,因为我把它的编码格式也设成了utf-8. 2.通过 ...

  5. Java 调用执行其他语言的程序

    以 Java 调用 Python 为例 1. 使用 Runtime 类 该方式简单,但是增加了 Java 对python 的依赖,需要事先安装python,及python程序依赖的第三方库 Runti ...

  6. python3 安装 google-visualization-python(windows10)

    google-visualization-python 的 github 官网:https://github.com/google/google-visualization-python 安装: 打开 ...

  7. Git push 提交代码到远程global user.name错误解决办法

    问题:安装了Git-1.9.4-preview和TortoiseGit等工具后,Git服务器开通了账号和密码并配置了邮箱.克隆了服务器代码到本地,按需求进行代码开发.提交本地代码到服务器时出现错误.具 ...

  8. 如何判断Linux是32位还是64位

    getconf LONG_BIT

  9. 【MySQL】初识数据库及简单操作

    一.数据库概述 1.1 什么是数据(Data) 描述事物的符号记录称为数据,描述事物的符号既可以是数字,也可以是文字.图片,图像.声音.语言等,数据由多种表现形式,它们都可以经过数字化后存入计算机. ...

  10. Vue源码解析---数据的双向绑定

    本文主要抽离Vue源码中数据双向绑定的核心代码,解析Vue是如何实现数据的双向绑定 核心思想是ES5的Object.defineProperty()和发布-订阅模式 整体结构 改造Vue实例中的dat ...