吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17782|回复: 118
收起左侧

[Android CTF] 【2021春节】安卓中级题逆向总结

    [复制链接]
Light紫星 发表于 2021-2-27 08:52
本帖最后由 Light紫星 于 2021-2-27 08:56 编辑

2021春节】解题领红包之三


逆向总结本题所用到的工具:
Jadx1.2.0
FrIDA14.2.13
ida7.5.0
Python3.7.2

首先安装apk,打开后是这个界面:


image.png


随便输入flag,提示flag格式错误,请重试。拖入jadx,找到关键函数,如下:
[Java] 纯文本查看 复制代码
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
package p004cn.pojie52.cm01;
 
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
 
/* renamed from: cn.pojie52.cm01.MainActivity */
public class MainActivity extends AppCompatActivity {
    public native boolean check(String str);
 
    static {
        System.loadLibrary("native-lib");
    }
 
    /* access modifiers changed from: protected */
    @Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(C0266R.layout.activity_main);
        final EditText editText = (EditText) findViewById(C0266R.C0268id.flag);
        findViewById(C0266R.C0268id.check).setOnClickListener(new View.OnClickListener() {
            /* class p004cn.pojie52.cm01.MainActivity.View$OnClickListenerC02651 */
 
            public void onClick(View view) {
                String trim = editText.getText().toString().trim();
                if (trim.length() != 30) {
                    Toast.makeText(MainActivity.this, "flag格式错误,请重试", 0).show();
                } else if (MainActivity.this.check(trim)) {
                    Toast.makeText(MainActivity.this, "恭喜你,验证正确!", 0).show();
                } else {
                    Toast.makeText(MainActivity.this, "flag错误,再接再厉", 0).show();
                }
            }
        });
    }
}


这里判断了输入的长度是否为30位,然后进入了so验证。


下一步,把so拖入ida,直接定位到关键函数:Java_cn_pojie52_cm01_MainActivity_check
该函数内容如下:

[C] 纯文本查看 复制代码
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
__int64 __fastcall Java_cn_pojie52_cm01_MainActivity_check(_JNIEnv *a1, __int64 a2, __int64 a3)
{
  const char *v5; // x21
  size_t v6; // w0
  int v7; // w0
  __int64 v8; // x0
  _BYTE *v9; // x0
  int8x16_t v10; // q0
  int8x16_t v11; // q4
  int8x16_t v12; // q2
  int8x16_t v13; // q5
  int8x16_t v14; // q1
  int8x16_t v15; // q0
  __int64 v16; // x8
  unsigned int v17; // w19
  _BYTE v19[33]; // [xsp+0h] [xbp-A0h]
  int v20; // [xsp+21h] [xbp-7Fh]
  char v21; // [xsp+25h] [xbp-7Bh]
  char v22; // [xsp+26h] [xbp-7Ah]
  char v23; // [xsp+27h] [xbp-79h]
  char v24; // [xsp+28h] [xbp-78h]
  char dest[16]; // [xsp+38h] [xbp-68h] BYREF
  __int128 v26; // [xsp+48h] [xbp-58h]
  __int128 v27; // [xsp+58h] [xbp-48h]
  __int128 v28; // [xsp+68h] [xbp-38h]
  __int64 v29; // [xsp+78h] [xbp-28h]
 
  v29 = *(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  if ( a1->functions->GetStringUTFLength(a1, a3) != 30 )
    return 0;
  v5 = a1->functions->GetStringUTFChars(a1, a3, 0LL);
  v28 = 0u;
  v27 = 0u;
  v26 = 0u;
  *dest = 0u;
  v6 = strlen(v5);
  strncpy(dest, v5, v6);
  a1->functions->ReleaseStringUTFChars(a1, a3, v5);
  v7 = strlen(dest);
  sub_B90(dest, v7, "areyousure??????");
  v8 = strlen(dest);
  v9 = sub_D90(dest, v8);
  *v19 = unk_11A1;
  *&v19[16] = unk_11B1;
  *&v19[25] = unk_11BA;
  v10.n128_u64[0] = 0xB2B2B2B2B2B2B2B2LL;
  v10.n128_u64[1] = 0xB2B2B2B2B2B2B2B2LL;
  v11.n128_u64[0] = 0xFEFEFEFEFEFEFEFELL;
  v11.n128_u64[1] = 0xFEFEFEFEFEFEFEFELL;
  v19[0] = 53;
  v12 = veorq_s8(vaddq_s8(veorq_s8(vaddq_s8(*&v19[1], v10), xmmword_1130), xmmword_1140), v11);
  v13.n128_u64[0] = 0x101010101010101LL;
  v13.n128_u64[1] = 0x101010101010101LL;
  v14.n128_u64[0] = 0x3E3E3E3E3E3E3E3ELL;
  v14.n128_u64[1] = 0x3E3E3E3E3E3E3E3ELL;
  *&v19[1] = vaddq_s8(
               veorq_s8(vsubq_s8(v13, vorrq_s8(vshrq_n_u8(v12, 7uLL), vshlq_n_s8(v12, 1uLL))), xmmword_1150),
               v14);
  v20 = 1782990162;
  v15 = veorq_s8(vaddq_s8(veorq_s8(vaddq_s8(*&v19[17], v10), xmmword_1160), xmmword_1170), v11);
  v21 = ((1
        - ((2 * ((((unk_11C6 - 78) ^ 0xB2) - 117) ^ 0xFE)) | ((((((unk_11C6 - 78) ^ 0xB2) - 117) ^ 0xFE) & 0x80) != 0))) ^ 0x25)
      + 62;
  v16 = 0LL;
  v22 = ((1
        - ((2 * ((((unk_11C7 - 78) ^ 0xB1) - 118) ^ 0xFE)) | ((((((unk_11C7 - 78) ^ 0xB1) - 118) ^ 0xFE) & 0x80) != 0))) ^ 0x26)
      + 62;
  *&v19[17] = vaddq_s8(
                veorq_s8(vsubq_s8(v13, vorrq_s8(vshrq_n_u8(v15, 7uLL), vshlq_n_s8(v15, 1uLL))), xmmword_1180),
                v14);
  v23 = ((1
        - ((2 * ((((unk_11C8 - 78) ^ 0xB0) - 119) ^ 0xFE)) | ((((((unk_11C8 - 78) ^ 0xB0) - 119) ^ 0xFE) & 0x80) != 0))) ^ 0x27)
      + 62;
  v24 = ((1
        - ((2 * ((((unk_11C9 - 78) ^ 0xBF) - 120) ^ 0xFE)) | ((((((unk_11C9 - 78) ^ 0xBF) - 120) ^ 0xFE) & 0x80) != 0))) ^ 0x28)
      + 62;
  while ( v9[v16] == v19[v16] )
  {
    if ( v9[v16] )
    {
      if ( ++v16 != 41 )
        continue;
    }
    v17 = 1;
    goto LABEL_9;
  }
  v17 = 0;
LABEL_9:
  free(v9);
  return v17;
}



大概看一下流程,先判断输入是否30位,然后把输入的数据传入sub_B90进行处理,再传入sub_D90处理一次,处理后的结果为v9,最后v9v19进行比较。所以这里要先看一下sub_b90sub_d90是干什么的,直接使用frida进行hook调用这两个函数,


frida代码如下:

[Python] 纯文本查看 复制代码
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
# -*- coding: UTF-8 -*-
 
import frida, sys
 
jscode = '''
  
function inline_hook() {
    var so_addr = Module.findBaseAddress("libnative-lib.so");
    if (so_addr) {
        console.log("so_addr:", so_addr);
        var addr_b90 = so_addr.add(0xb90);
        var sub_b90 = new NativeFunction(addr_b90 , 'int', ['pointer', 'int','pointer']);
        var arg1 = Memory.allocUtf8String('111111111111111111111111111111');
        var arg2 = 30;
        var arg3 = Memory.allocUtf8String('areyousure??????');
        var ret_b90 = sub_b90(arg1,arg2,arg3);
        console.log(Memory.readByteArray(arg1,64));
         
         
        var addr_d90 = so_addr.add(0xd90);
        var sub_d90 = new NativeFunction(addr_d90 , 'pointer', ['pointer', 'int' ]);
        var arg1 = Memory.allocUtf8String('111111111111111111111111111111');
        var arg2 = 30;
        var ret_d90 = sub_d90(arg1,arg2);
        console.log(Memory.readByteArray(ret_d90,64));
         
         
    }
     
}
setImmediate(inline_hook)
   
'''
def on_message(message, data):
    if message['type'] == 'send':
        print(" {0}".format(message['payload']))
    else:
        print(message)
pass
#print(frida.enumerate_devices())
# 查找USB设备并附加到目标进程
device =  frida.get_remote_device()
#pid = device.spawn(["com.live.xctv"])
  
#session = device.attach(pid)
session =device.attach('cn.pojie52.cm01') #这里是要注入的apk包名
# 在目标进程里创建脚本
script = session.create_script(jscode)
# 注册消息回调
script.on('message', on_message)
print(' Start attach')
# 加载创建好的javascript脚本
script.load()
# 读取系统输入
sys.stdin.read()


结果如下:

image.png


然后我们先进入sub_b90看一下,


sub_b90函数内容如下:

[C] 纯文本查看 复制代码
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
72
73
74
75
76
unsigned __int64 __fastcall sub_B90(_BYTE *a1, unsigned int a2, char *s)
{
  unsigned __int64 result; // x0
  unsigned __int64 v7; // x8
  signed int v8; // w9
  int v9; // w11
  int v10; // w9
  int v11; // w12
  int v12; // w9
  signed int v13; // w11
  __int64 v14; // x8
  int v15; // w12
  int v16; // w9
  int v17; // w13
  int v18; // w11
  int v19; // w14
  __int128 v20[2]; // [xsp+0h] [xbp-140h]
  __int128 v21[14]; // [xsp+20h] [xbp-120h] BYREF
  __int64 v22; // [xsp+108h] [xbp-38h]
 
  v22 = *(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  result = strlen(s);
  v20[0] = xmmword_11D0;
  v20[1] = xmmword_11E0;
  qmemcpy(v21, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmno", 80);
  v21[5] = xmmword_1240;
  v21[6] = xmmword_1250;
  v21[7] = xmmword_1260;
  v21[8] = xmmword_1270;
  v21[9] = xmmword_1280;
  v7 = 0LL;
  v8 = 0;
  v21[10] = xmmword_1290;
  v21[11] = xmmword_12A0;
  v21[12] = xmmword_12B0;
  v21[13] = xmmword_12C0;
  do
  {
    v9 = *(v20 + v7);
    v10 = v8 + v9 + s[v7 - v7 / result * result];
    v11 = v10 + 255;
    if ( v10 >= 0 )
      v11 = v10;
    v8 = v10 - (v11 & 0xFFFFFF00);
    *(v20 + v7++) = *(v20 + v8);
    *(v20 + v8) = v9;
  }
  while ( v7 != 256 );
  if ( a2 )
  {
    v12 = 0;
    v13 = 0;
    v14 = a2;
    do
    {
      v15 = v12 + 1;
      if ( v12 + 1 >= 0 )
        v16 = v12 + 1;
      else
        v16 = v12 + 256;
      v12 = v15 - (v16 & 0xFFFFFF00);
      v17 = *(v20 + v12);
      v18 = v13 + v17;
      v19 = v18 + 255;
      if ( v18 >= 0 )
        v19 = v18;
      v13 = v18 - (v19 & 0xFFFFFF00);
      --v14;
      *(v20 + v12) = *(v20 + v13);
      *(v20 + v13) = v17;
      *a1++ ^= *(v20 + (*(v20 + v12) + v17));
    }
    while ( v14 );
  }
  return result;
}



大概分析一下sub_b90,是根据传入的第三个参数sv20进行了一个初始化,然后再把参数a1v20进行了异或运算,主要看这个异或运算,先设想一下,如果是把a1进行了异或,那么得到的结果和a1之前的数据再异或就可以计算出异或的key,这里我们把它叫做xorkey,那么先看一下我们传入的参数,是301,也就是300x31 ,然后看结果,第一位是0xe00x31^0xe0 = 209,然后把参数改为302,即0x32,得出首位的结果是0xe30xe3^0x32结果也是209,证明我们的思路是正确的,然后依次求出所有的xorkey


最后计算出的结果为:

xorkey = [209, 90, 6, 144, 68, 230, 199, 229, 222, 40, 247, 242, 102, 145, 200, 133, 66, 223, 249, 224, 130, 1, 43, 59, 56, 99, 55, 189, 46, 77]


接下来看sub_d90,咋一看返回值,全是字母,看起来有点像base64,于是用base64编码301进行测试,发现结果吻合,于是可以断定sub_d90base64函数。

接下来,就可以写出通过v9求输入参数的函数:

[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import base64
xorkey = [209, 90, 6, 144, 68, 230, 199, 229, 222, 40, 247, 242, 102, 145, 200, 133, 66, 223, 249, 224, 130, 1, 43, 59, 56, 99, 55, 189, 46, 77]
 
def sub_B90(data,l):
    ret = []
    for i in range(l):
        ret.append(((data[i]))^xorkey[i])
    s=''
    for i in ret:
        s+=chr(i)
    print(s)
    return ret
  
 
def resv(data):
    data =base64.b64decode(data)
    t = sub_B90(data,len(data))
    return(t)


调用resv即可计算出输入的参数。


这个时候我们发现,还有一个v19是我们不知道的,如果找到v19然后代入resv就能求出本题的结果!


根据ida的注释,我们知道v19xsp+0h,而destxsp+38h,而dest又作为参数传入了sub_b90,这里我直接hooksub_b90,得到xsp,然后再在v19初始化结束之后输出xsp的值,即可得到v19


这里的hook代码如下:

[Python] 纯文本查看 复制代码
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
# -*- coding: UTF-8 -*-
 
import frida, sys
 
jscode = '''
 
var destAddr = '';  //定位xsp地址
  
function inline_hook() {
    var so_addr = Module.findBaseAddress("libnative-lib.so");
     
     
    if (so_addr) {
        console.log("so_addr:", so_addr);
         
        var addr_b90 = so_addr.add(0xB90);
        var sub_b90 = new NativeFunction(addr_b90 , 'int', ['pointer', 'int', 'pointer']);
        Interceptor.attach(sub_b90, {
            onEnter: function(args)
            
            destAddr = args[0];
            console.log('onEnter B90');
            },
            //在hook函数之后执行的语句
            onLeave:function(retval)
            {
            console.log('onLeave B90');
            }
        });
 
      
        var addr_b2c = so_addr.add(0xb2c);
        console.log("The addr_b2c:", addr_b2c);
        Java.perform(function() {
            Interceptor.attach(addr_b2c, {
                onEnter: function(args) {
                console.log("addr_b2c OnEnter :",  Memory.readByteArray(destAddr.sub(0x38),64) );
                }
            })
        })
    }
}
setImmediate(inline_hook)
   
   
'''
def on_message(message, data):
    if message['type'] == 'send':
        print(" {0}".format(message['payload']))
    else:
        print(message)
pass
#print(frida.enumerate_devices())
# 查找USB设备并附加到目标进程
device =  frida.get_remote_device()
#pid = device.spawn(["com.live.xctv"])
  
#session = device.attach(pid)
session =device.attach('cn.pojie52.cm01') #这里是要注入的apk包名
# 在目标进程里创建脚本
script = session.create_script(jscode)
# 注册消息回调
script.on('message', on_message)
print(' Start attach')
# 加载创建好的javascript脚本
script.load()
# 读取系统输入
sys.stdin.read()


随便输入一个30位的注册码,得到的结果如下:

image.png


看来这个字符串就是我们要的了。把这个字符串代入函数resv,即可求出本题的flag

image.png


输入52pojieHappyChineseNewYear2021到输入框,点击验证按钮,提示成功!本题分析结束。

【2021春节】安卓中级题逆向总结_pdf.zip (441.04 KB, 下载次数: 257)

免费评分

参与人数 36吾爱币 +34 热心值 +31 收起 理由
ZydmxhZ + 1 我很赞同!
agofor2017 + 1 + 1 用心讨论,共获提升!
tr4pmaker + 1 + 1 我很赞同!
不会逆向 + 1 谢谢@Thanks!
shili180 + 1 + 1 用心讨论,共获提升!
flu鲁少 + 1 + 1 我很赞同!
luochunyan + 1 + 1 谢谢@Thanks!
fatcatfeimao + 1 学习了
Keeper168 + 1 用心讨论,共获提升!
忆无寒 + 1 我很赞同!
wx1945 + 1 + 1 我很赞同!
xhx520 + 1 + 1 我很赞同!
努力加载中 + 1 + 1 谢谢@Thanks!
叶隽 + 1 我很赞同!
louchen1994 + 1 + 1 我很赞同!
QRQ + 1 我很赞同!
jockin + 1 + 1 用心讨论,共获提升!
头铁又刚 + 1 + 1 热心回复!
cpj1203 + 1 + 1 谢谢@Thanks!
mysat + 1 用心讨论,共获提升!
ybkkk2000 + 1 + 1 学习了!
victos + 1 + 1 谢谢@Thanks!
不谙世事的骚年 + 1 + 1 我很赞同!
exluku + 1 + 1 热心回复!
qaz007 + 1 + 1 用心讨论,共获提升!
Bizhi-1024 + 1 谢谢@Thanks!
zhoumeto + 1 用心讨论,共获提升!
gaosld + 1 + 1 热心回复!
fengbolee + 2 + 1 用心讨论,共获提升!
正己 + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
梦游枪手 + 2 + 1 用心讨论,共获提升!
alittlebear + 1 + 1 666
A3uRa + 1 + 1 膜拜大佬
不爱everyone + 1 厉害厉害
求求你们别学了 + 1 + 1 学习到了
gunxsword + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wmsuper 发表于 2021-2-27 11:04
[Python] 纯文本查看 复制代码
1
2
3
4
5
6
from Crypto.Cipher import ARC4
import base64
b64_enc_msg=b'''5Gh2/y6Poq2/WIeLJfmh6yesnK7ndnJeWREFjRx8'''
enc_msg=base64.b64decode(b64_enc_msg)
rc4=ARC4.new(b'areyousure??????')
print(rc4.decrypt(enc_msg).decode('utf8'))

免费评分

参与人数 2吾爱币 +3 热心值 +2 收起 理由
xuqi + 1 + 1 厉害
梦游枪手 + 2 + 1 晴天师傅太强了

查看全部评分

冰.亦 发表于 2021-2-27 09:02
jitui110 发表于 2021-2-27 09:40
转身鬼魅 发表于 2021-2-27 09:54
插眼,学习,不会分析so阻止了我
xx86129058 发表于 2021-2-27 09:59
前排学习
samismy 发表于 2021-2-27 09:59
受教了,研究了到了so不知道怎么调试
刀大喵 发表于 2021-2-27 10:03
定位关键函数后 看不懂流程 放弃了。。。。 学习还要继续呀
然而爆破并没啥用         QQ图片20210227100202.jpg
daymissed 发表于 2021-2-27 10:20
还是看不太懂编码啊,慢慢学习
头像被屏蔽
First丶云心 发表于 2021-2-27 10:33
天哪,脑袋嗡嗡的,好复杂啊!
无敌VS小嘟嘟 发表于 2021-2-27 10:41
感谢分享    就是看不明白
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-6-2 05:07

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表