18/09/26-2-BugKu-逆向-easy100(LCTF)

Posted fingerprint

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18/09/26-2-BugKu-逆向-easy100(LCTF)相关的知识,希望对你有一定的参考价值。

0x00
题目链接:https://pan.baidu.com/s/1dIYmMqp73379xRo_6D3fFQ 密码:trg6

0x01
下载压缩包安装apk,打开app。
尝试输入,点击sure按钮,会弹出“oh,no”消息。

0x02
使用jeb2反编译apk,分析Java源码,因为多文件,以及类名和许多变量名、方法都使用a,b,c,d等,导致反编译的源码不容易分析。

0x03
分析算法
1)分析类d
类d实现OnCliListener监听接口,有按钮按下事件的处理方法。if-else语句完成输入flag成功与失败的弹出消息。

分析if语句的判断条件:

技术分享图片
1 MainActivity.a(this.a, MainActivity.a(this.a), this.a.findViewById(2131427414).getText().toString())
View Code

 


调用MainActivity中的a方法,返回真或假,传入三个参数,this.a为类d中成员,MainActivity.a(this.a)为MainActivity中a方法的返回值,this.a.findViewById(2131427414).getText().toString()则为app中输入转化为字符串。

接着分析类MainActivity中的a方法。

2)MainActivity中的a方法分析
a.进入反编译的MainActivity,找到a方法,发现为重载。

技术分享图片
 1 static String a(MainActivity arg1) {
 2 return arg1.v;
 3 
 4 static boolean a(MainActivity arg1, String arg2, String arg3) {
 5 return arg1.a(arg2, arg3);
 6 }
 7 
 8 private boolean a(String arg4, String arg5) {
 9 return new c().a(arg4, arg5).equals(new String(new byte[]{21, -93, -68, -94, 86, 117, -19, -68, -92, 33, 50, 118, 16, 13, 1, -15, -13, 3, 4, 103, -18, 81, 30, 68, 54, -93, 44, -23, 93, 98, 5, 59}));
10 }
View Code

 

可以看到private boolean a(String arg4, String arg5)方法中调用了equals方法进行比较返回布尔值,重点分析此方法和其参数。

b.args4是类d中传入的MainActivity.a(this.a),为MainActivity中static String a(MainActivity arg1)方法的返回值,可以看到返回的是arg1.v,而v是MainActivity的String类型的数据成员以及有相应的方法进行赋值。

技术分享图片
 1 private String v;
 2 
 3 private void p() {
 4 try {
 5 InputStream v0_1 = this.getResources().getAssets().open("url.png");
 6 int v1 = v0_1.available();
 7 byte[] v2 = new byte[v1];
 8 v0_1.read(v2, 0, v1);
 9 byte[] v0_2 = new byte[16];
10 System.arraycopy(v2, 144, v0_2, 0, 16);
11 this.v = new String(v0_2, "utf-8");
12 }
13 catch(Exception v0) {
14 v0.printStackTrace();
15 }
16 }
View Code

 

c.args5是类d中传入this.a.findViewById(2131427414).getText().toString(),即为app中的输入的字符串转化。

d.分析比较,new c().a(args4,args5)和一byte数组转化的String比较,说明ew c().a(args4,args5)返回的为String类型。

e.接着分析new c().a(args4,args5),类c中的a方法。

3) 类c中a方法的分析

技术分享图片
 1 public String a(String arg5, String arg6) {
 2 String v0 = this.a(arg5);
 3 String v1 = "";
 4 a v2 = new a();
 5 v2.a(v0.getBytes());
 6 try {
 7 v0 = new String(v2.b(arg6.getBytes()), "utf-8");
 8 }
 9 catch(Exception v0_1) {
10 v0_1.printStackTrace();
11 v0 = v1;
12 }
13 
14 return v0;
15 }
16 
17 private String a(String arg4) {
18 String v0_2;
19 try {
20 arg4.getBytes("utf-8");
21 StringBuilder v1 = new StringBuilder();
22 int v0_1;
23 for(v0_1 = 0; v0_1 < arg4.length(); v0_1 += 2) {
24 v1.append(arg4.charAt(v0_1 + 1));
25 v1.append(arg4.charAt(v0_1));
26 }
27 
28 v0_2 = v1.toString();
29 }
30 catch(UnsupportedEncodingException v0) {
31 v0.printStackTrace();
32 v0_2 = null;
33 }
34 
35 return v0_2;
36 }
View Code

 

a方法重载,先分析两个参数a方法,调用了一个参数的a方法并传入字符串arg5然后将返回值赋值给v0。
一个参数的a方法比较简单,把传入的字符串每两个字符为一组然后交换这两个字符的位置最后返回改变后的字符串。

接着分析两个参数的a方法。

技术分享图片
1 a v2 = new a();
2 v2.a(v0.getBytes());
3 try {
4 v0 = new String(v2.b(arg6.getBytes()), "utf-8");
5 }
View Code

 


发现和类a有关。

4) 类a的分析

技术分享图片
 1 public class a {
 2 private SecretKeySpec a;
 3 private Cipher b;
 4 
 5 public a() {
 6 super();
 7 }
 8 
 9 protected void a(byte[] arg4) {
10 if(arg4 != null) {
11 goto label_15;
12 }
13 
14 try {
15 this.a = new SecretKeySpec(MessageDigest.getInstance("MD5").digest("".getBytes("utf-8")), "AES");
16 this.b = Cipher.getInstance("AES/ECB/PKCS5Padding");
17 return;
18 label_15:
19 this.a = new SecretKeySpec(arg4, "AES");
20 this.b = Cipher.getInstance("AES/ECB/PKCS5Padding");
21 }
22 catch(UnsupportedEncodingException v0) {
23 v0.printStackTrace();
24 }
25 catch(NoSuchAlgorithmException v0_1) {
26 v0_1.printStackTrace();
27 }
28 catch(NoSuchPaddingException v0_2) {
29 v0_2.printStackTrace();
30 }
31 }
32 
33 protected byte[] b(byte[] arg4) {
34 this.b.init(1, this.a);
35 return this.b.doFinal(arg4);
36 }
37 }
View Code

 

可以轻松猜测到这是AES加密,ECB模式,PKCS5Padding填充。

技术分享图片
1 protected byte[] b(byte[] arg4) {
2 this.b.init(1, this.a);
3 return this.b.doFinal(arg4);
4 }
5 
6 v0 = new String(v2.b(arg6.getBytes()), "utf-8");//来自类c
View Code

 

此段代码即是返回AES加密后的结果,再看类c发现要加密的明文是arg6,传入的arg6即是this.a.findViewById(2131427414).getText().toString(),app中输入的内容的字符串转化。

然后找找密钥。

技术分享图片
1 private SecretKeySpec a;
2 
3 this.a = new SecretKeySpec(arg4, "AES");
View Code

 


发现arg4作为了密钥,arg4则是在类c中传入的v0.getBytes(),而v0是经过类c中方法处理的字符串,最初是来自类MainActivity的v成员。也就是说字符串成员v在类c中进行变化,然后作为了AES加密的密钥。关于v成员在上文已分析。

0x04
总结算法
题目主要考察AES加密,ECB模式,PKCS5Padding填充,密钥为MainActivity中成员v的变化,明文为在app中输入的内容。然后AES加密结果和byte数组转化的String比较。若相同则弹出“Congratulation”,说明输入的即为flag。

技术分享图片
1 //AES加密结果要比较的String
2 new String(new byte[]{21, -93, -68, -94, 86, 117, -19, -68, -92, 33, 50, 118, 16, 13, 1, -15, -13, 3, 4, 103, -18, 81, 30, 68, 54, -93, 44, -23, 93, 98, 5, 59})
View Code

 

0x05
获得flag的操作
首先要找到密钥,使用jeb2进行动态调试,在很多地方设下断点都能获得密钥的内容。操作后得到成员v为“this_is_the_key.”,而变换即为密钥"htsii__sht_eek.y"。

现在已经知道加密方式,密钥,和密文了,解密就很简单了,一个比较麻烦的地方就是解密不太好操作,因为加密结果要比较是的String类型,并且为乱码。如果直接搜索和修改网上的AES源码,也可以得到密文,不过比较麻烦。

一个比较简单的操作是将写脚本将比较的String进行Base64加密(因为在线解密要求输入密文的格式为Base64格式),然后网上搜索在线AES解密。然后选择相应AES解密模式(ECB,PKCS5Padding),输入密钥key,即可进行解密得到flag的Base64格式,接着进行Base64解密即可得到flag。

 



















以上是关于18/09/26-2-BugKu-逆向-easy100(LCTF)的主要内容,如果未能解决你的问题,请参考以下文章

leetcode

将 VBA 翻译成 JavaScript 自定义函数,得到不同的答案

NaN 在 scikit-learn 中产生问题

Android逆向系列文章— Android基础逆向

Android逆向-Android基础逆向(2-2)

Android 逆向Android 逆向用途 | Android 逆向原理