首页
社区
课程
招聘
[分享]最近给公务员出ctf题目,复习了一遍Android分析的手法,记录一下,还有刚学的markdown格式哈哈,也试一下
2022-7-11 16:39 14028

[分享]最近给公务员出ctf题目,复习了一遍Android分析的手法,记录一下,还有刚学的markdown格式哈哈,也试一下

2022-7-11 16:39
14028

我总结了几种经典的类型,列个目录吧:
1.Strange apk:firda dump正在运行的dex文件
2.app3:怎么打开.ab文件,jeb动态调试
3.ph0en1x_100:jeb动态调试
4.easydex:so层静态分析,idc脚本

先看第一个吧,Strange apk

首先看一下java层
(这里插一句,JEB谁用谁说好,我感觉这个比as好用,动态调试的时候不用操作太多,还可以修改参数类型和名称,比jadx,jdgui好用好分析,还可以保存上次没有分析完的程序)
先看manifest文件,找到程序的入口点:
图片描述
sctf.demo.myapplication.t这个是程序的入口点
图片描述
但是找不到啊,这里我猜测应该就是在app运行过程中动态释放出来的
那就用frida_dump试试吧
图片描述
在指定文件夹里找到dump下的dex文件进行分析就可以了
图片描述
只有第一个dex文件能找到了.t文件
图片描述
在这个。t文件的oncreate又定位到了这里:
图片描述
因为程序一开始分析的是没有sctf.demo.myapplication.t文件了 xml文件里只有sctf.demo.myapplication.t和sctf.demo.myapplication.s文件,所以这个MAIN应该是sctf.demo.myapplication.s文件里面的,所以就要分析sctf.demo.myapplication.s文件了
图片描述
然后修复一下代码,修改一下变量的名称,加一些注释便于分析:

1
2
3
4
5
6
7
8
9
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
protected void onCreate(Bundle arg5) {
        super.onCreate(arg5);
        this.setContentView(0x7F09001D);
        View input_str = this.findViewById(0x7F070022);
 // 输入字符串
        this.findViewById(0x7F07008A);
        ((Button)input_str).setOnClickListener(new View$OnClickListener(this.findViewById(0x7F070037)) {
            public void onClick(View arg9) {
                String str1 = ""; 
// 两个字符串临时存储变量
                String str2 = "";
                int t = 0;
 // 临时变量
                String str = this.val$ed.getText().toString();
                int num_30 = 30;
                if(str.length() == num_30) { 
// 输入的字符串的长度为30
                    while(t < 12) {
                        str1 = str1 + str.charAt(t);
 // 将前12个输入的字符存储到str1里面
                        ++t;
                    }
 
                    str1 = f.sctf(str1); 
// 跟进去发现是将前12个字符进行base64加密
                    while(t < num_30) {
                        str2 = str2 + str.charAt(t); 
// 将后12个字符存储到str2字符串里面
                        ++t;
                    }
 
                    if(str1.equals("c2N0ZntXM2xjMG1l")) { 
// 根据字符串1和该字符串相匹配,直接就能解出来前12个字符sctf{W3lc0me
                        Intent v4_1 = new Intent();
                        v4_1.putExtra("data_return", str2);
//返回.t文件中分析str2字符串的加密操作
                        s.this.setResult(-1, v4_1);
                        s.this.finish();
                    }
                    else {
                        Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
                    }
                }
                else {
                    Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
                }
            }
        });
    }
}

通过这段代码的分析可以得到前半部分的flag:sctf{W3lc0me
总结一下就是通过base64解密得到的(详细分析过程在代码注释)

 

返回.t文件对str2字符串进程分析
图片描述
修复一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class t extends AppCompatActivity {
    public t() {
        super();
    }
 
    protected void onActivityResult(int arg9, int arg10, Intent arg11) {
        View v0 = this.findViewById(0x7F07008B);
        View v1 = this.findViewById(0x7F070023);
        if(arg9 == 1 && arg10 == -1) {
            try {
                MessageDigest str = MessageDigest.getInstance("MD5");
                str.update("syclover".getBytes());
 // 将syclover字符串进行md5加密
                String temp_str = new BigInteger(1, str.digest()).toString(16); 
// 将加密后的字符转化为字符串8bfc8af07bca146c937f283b8ec768d4
            }
            catch(Exception v5) {
                v5.printStackTrace();
            }
 
            if(f.encode(arg11.getStringExtra("data_return"), temp_str).equals("~8t808_8A8n848r808i8d8-8w808r8l8d8}8")) {
                ((TextView)v0).setVisibility(0);
                ((Button)v1).setVisibility(4);
 // 去除所有的8之后剩下~t0_An4r0id-w0rld}
            }
            else {
                Toast.makeText(this.getApplicationContext(), "one more step", 1).show();
            }
        }
    }

这个是中间的encode的函数(代码修复之后的)分析:

1
2
3
4
5
6
7
8
9
10
11
12
public static String encode(String temp_str, String str) {  // 将data_return字符串和加密后的字符串8bfc8af07bca146c937f283b8ec768d4格一位放一个
       int len_temp_str = temp_str.length();
       int len_str = str.length();
       StringBuilder t_str = new StringBuilder();
       int t;
       for(t = 0; t < len_temp_str; ++t) {
           t_str.append(temp_str.charAt(t));
           t_str.append(str.charAt(t / len_str));  // 每次都是只能取到第一个字符8
       }
 
       return t_str.toString();  // 返回字符8
   }

通过分析后半部分代码得到了:~t0_An4r0id-w0rld}
总结一下就是md5解密,然后分析encode函数,得到flag的后半部分
这道题的关键所在就是,找到程序的入口点,dump出正在运行的dex文件,字符串加密简单分析即可得到

app3

打开之后一看是.ab文件(在对安卓手机进行取证时,经常需要备份手机的应用程序数据,备份后得到的数据文件为ab格式,ab文件一般分两种,一种是没有加密,这种文件前面有24字节的文件头,文件头包含none标志,文件头之后就是数据;一种是加密的备份文件,它的文件头就比较复杂了,文件头包含AES-256标志。)
图片描述
一般的话.ab文件是用这个文件进行操作的 图片描述
我总结出来一般的话使用这两条指令中的一条:
java -jar abe-all.jar unpack app3.ab app3.jar
java -jar abe-all.jar unpack app3.ab app3.tar
图片描述
将.ab文件转化为.tar文件 图片描述
解压缩之后发现了apk文件,就可以进行分析了:
先从程序的入口点开始分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void a() {
        SQLiteDatabase.loadLibs(((Context)this));
 // 加载数据库
        this.b = new a(((Context)this), "Demo.db", null, 1);
        ContentValues v0 = new ContentValues();
  // 实例化v0这个对象,用于存储用户名和密码
        v0.put("name", "Stranger");
 // name = Stranger
        v0.put("password", Integer.valueOf(0x1E240));
 // password = 0x1E240 = 123456
        com.example.yaphetshan.tencentwelcome.a.a v1 = new com.example.yaphetshan.tencentwelcome.a.a();
 // 初始化v1对象
        String v2 = v1.a(v0.getAsString("name"), v0.getAsString("password"));
 // 将获取到的用户名和密码的值转化为字符型变量存储到v2中,调用的v1.a方法,然后跟进去分信息v1.a的方法,如果传入两个参数,就是分别取0-4个字符,就是返回Stra1234
        this.a = this.b.getWritableDatabase(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7));
  // 调用了数据库函数,将刚刚的变量作为参数传入,调用了v1.a的方法和v1.b的方法
        this.a.insert("TencentMicrMsg", null, v0);
    }

这个代码是调用了这个方法:

1
String v2 = v1.a(v0.getAsString("name"), v0.getAsString("password"));

图片描述
最后这个代码这里,由于这里是给数据库传参数的函数,所以就是要分析这个,一开始的那个tar文件里面解压之后发现了.db文件,就是数据库文件,所以我猜测,这里传入的参数应该是登录数据库的密码,重点就是要分析这个函数了

1
this.a = this.b.getWritableDatabase(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7));

先是外层调用了v1.a的这个方法:
图片描述
然后又内层调用了这个方法:
图片描述

 

先分析这个函数的返回值

1
v1.b(v2, v0.getAsString("password"))

跟进去分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.yaphetshan.tencentwelcome.a;
 
public class a {
    private String a;
 
    public a() {
        super();
        this.a = "yaphetshan";
    }
 
    public String a(String arg4, String arg5) {
        return arg4.substring(0, 4) + arg5.substring(0, 4);  // 返回值截取0-4位字符
    }
 
    public String a(String arg3) {
        new b();
        return b.b(arg3 + this.a);  // 调用了b方法,跟进去分析一下
    }
 
    public String b(String arg2, String arg3) {
        new b();
        return b.a(arg2);
    }
}

继续跟进去分析b方法:
图片描述
图片描述
其实也没有什么,就是md5加密和SHA-1加密,
这里我就用动态调试的方法吧:
先获得这个函数的返回值: 图片描述
跟进去下个断点:
图片描述
附上进程:
图片描述
把v0的类型改为string类型是这样的:
图片描述
v0 = 44e2e4457d4e252ca5b9fe9d20b3fea5
接下来就要看看这个函数的返回值了
v1.a(v2 + v1.b(v2, v0.getAsString("password")))
继续下断点:
图片描述
v0 = "yaphetshan"
然后分析这个:
(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7))
下断点,再调:
图片描述
v0 = "ae56f99638285eb0743d8bf76d2b0c80e5cbb096"
然后取前七位:ae56f99(这就是登录数据库的密码了,其实直接从最后一步那里下断点就行了,我想一步步的看看加密算法的结果)
用ae56f99登录数据库找到:VGN0ZntIM2xsMF9Eb19ZMHVfTG92M19UZW5jM250IX0=
这一眼就是base64编码,直接解码就行了
Tctf{H3ll0_Do_Y0u_Lov3_Tenc3nt!}

ph0en1x_100

既然JEB动态调试这么好用,那就再来一个题(这个题就非常简单了,直接一步到位)嘿嘿
关键代码就是这里,修复一下代码在分析就是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void onCreate(Bundle arg2) {
      super.onCreate(arg2);
      this.setContentView(0x7F040019);
      this.input_flag = this.findViewById(0x7F0C004F);
  }
 
  public void onGoClick(View arg5) {
      if(this.getSecret(this.getFlag()).equals(this.getSecret(this.encrypt(this.input_flag.getText().toString())))) {
          Toast.makeText(((Context)this), "Success", 1).show();
      }
      else {
          Toast.makeText(((Context)this), "Failed", 1).show();
      }
  }
1
if(this.getSecret(this.getFlag()).equals(this.getSecret(this.encrypt(this.input_flag.getText().toString()))))

如果这个if分支返回为真,就能让程序正确运行
然后equals的两个参数在传入之前都调用了getSecret()函数,所以这个函数就不再用分析了
先看一下getflag()函数:
再看一下encrypt()函数:
终于可以用ida分析了:
图片描述
图片描述
上ida导入.h文件在改一下参数:
图片描述
分析一下encrypt函数,发现逻辑很简单,就是将传进来的字符串的每个字符的ASCII码减一
图片描述
对于getFlag函数直接用JEB动态调试该函数得到返回值即可:
下好断点,附加进程:
图片描述
图片描述
string@4175:"ekfz@q2^x/t^fn0mF^6/^rbqanqntfg^E`hq|"
直接上脚本就行了:
图片描述

easydex

apk没有加固:
图片描述
首先看看apk的java层:
图片描述
发现只有一些资源文件,并没有发现dex文件,所以dex文件应该也是动态加载出来的
这里我尝试用frida-dexdump想dump下正在运行的dex文件,但是啥也没有:
图片描述
图片描述
所以就要分析so层了:
我想着先从jnionload或者java开始的来着,但是都没有,然后我就想着从这个函数分析吧:
图片描述
一看这么多逻辑,先动态看看程序是怎么走的吧:
先在这里下个断点,可以找出程序在系统中(经过了异或运算)的释放的dex文件的位置
图片描述
图片描述
然后接着动态分析就能分析出程序的流程:
这个是我修复之后的代码:
图片描述
图片描述
这个31分支这里就是解密dex文件的位置:
图片描述
下面就是对解密出来的dex文件(从byte_7004开始,长度为0x35A0C是加密后的数据)进行的操作:
图片描述
这里有两种方法:
1.在删除dex文件操作之前下个断点,然后将手机中的dex文件pull到电脑上
2.使用idc脚本直接解密出dex文件:
图片描述
然后就可以得到dex文件进行分析了:
但是再dex文件中并没有发现明显的逻辑:
图片描述
然后将字符串解密:
图片描述
然后再源apk文件中发现了two fish算法............(这道题的关键应该是so层的分析,这个twofish算法我还是第一次听说)
图片描述
然后找个在线解密网站就行了:
图片描述


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞6
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/07/26 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (9)
雪    币: 8271
活跃值: (4791)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
v0id_ 2022-7-11 16:55
2
0
ctf到什么水平可以当公务员
雪    币: 22
活跃值: (3614)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
New对象处 2022-7-11 17:19
3
0
宇宙的尽头是体制内
雪    币: 5640
活跃值: (7272)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
以和爲貴 1 2022-7-11 17:22
4
0
v0id_ ctf到什么水平可以当公务员[em_51]

我也不知道哈哈,就是一个比赛吧


最后于 2022-7-11 17:23 被以和爲貴编辑 ,原因:
雪    币: 3654
活跃值: (3828)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2022-7-18 09:05
5
0
 公务员还要做 CTF
雪    币: 3654
活跃值: (3828)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2022-7-18 09:05
6
0
v0id_ ctf到什么水平可以当公务员[em_51]
先是 公务员 才有CTF
雪    币: 26
活跃值: (771)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
beyondcyx 2022-7-18 10:29
7
0
公务员也要考ctf ??
雪    币: 5640
活跃值: (7272)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
以和爲貴 1 2022-7-18 10:51
8
0
beyondcyx 公务员也要考ctf ??
是一个税务局的比赛
雪    币: 2832
活跃值: (1430)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
M00yy 2022-7-19 18:35
9
0
公务员不是直接请别人代打吗
雪    币: 5640
活跃值: (7272)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
以和爲貴 1 2022-7-19 21:15
10
0
M00yy 公务员不是直接请别人代打吗[em_7]

哈哈看破不说破啊大佬

最后于 2022-7-19 21:16 被以和爲貴编辑 ,原因:
游客
登录 | 注册 方可回帖
返回