2023NewStar-Reverser-Android(all)

Last updated on March 31, 2024 pm

复现一下以前的没做安卓题,顺便加深新学的知识

Week2

AndroGenshin

静态分析手撕即可,RC4+Base64

image-20240330161901204

image-20240330163020822

AndroDbgMe

直接使用MT管理完成更改以及重签名

image-20240330164008451

命令adb shell am start -D -n com.chick.androdbgme/.MainActivity调试模式启动,然后Jadx或者Jeb连上即可

image-20240330170124534

Week3

Andronative

native方法检验,转去so看

image-20240330200359600

很容易找到关键的地方

image-20240330210258135

下断点调试,看汇编会轻松一点

image-20240330210331437

转为对应python代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
box = [1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14,17,16,19,18,21,20,23,22,25,24,27,26,29,28,31,30,33,32,35,34,37,36,39,38,41,40,43,42,45,44,47,46,49,48,51,50,53,52,55,54,57,56,59,58,61,60,63,62,65,64,67,66,69,68,71,70,73,72,75,74,77,76,79,78,81,80,83,82,85,84,87,86,89,88,91,90,93,92,95,94,97,96,99,98,101,100,103,102,105,104,107,106,109,108,111,110,113,112,115,114,117,116,119,118,121,120,123,122,125,124,127,126,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]

def ROL(data,num):
return (data >> (8-num)) | (data << num)

input = [0x61 for i in range(16)]

deadbeef = [0x64,0x65,0x61,0x64,0x62,0x65,0x65,0x66]
for i in range(16):
input[i] = box[input[i]] ^ deadbeef[i % 8]
input[i] = ROL(input[i],3)

print(input)

再走完这个加密后,又走了一个变表的base64,接下来就很容易搓逆脚本了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
box = [1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14,17,16,19,18,21,20,23,22,25,24,27,26,29,28,31,30,33,32,35,34,37,36,39,38,41,40,43,42,45,44,47,46,49,48,51,50,53,52,55,54,57,56,59,58,61,60,63,62,65,64,67,66,69,68,71,70,73,72,75,74,77,76,79,78,81,80,83,82,85,84,87,86,89,88,91,90,93,92,95,94,97,96,99,98,101,100,103,102,105,104,107,106,109,108,111,110,113,112,115,114,117,116,119,118,121,120,123,122,125,124,127,126,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]
enc = [0x18,0x40,0x08,0x10,0xc0,0x69,0xd9,0x78,0x20,0x80,0x28,0xd1,0x78,0x08,0xba,0xa2,0xb2,0x08,0x58,0x70,0xe1,0x28,0xb8,0x18,0xba,0xaa,0x9a,0xb0,0x10,0x00,0x40,0x00,0x20,0x70,0x08,0x60,0x30,0x58,0xb2,0xa0,0x20,0xd9,0xa0,0x68,0x50,0xb8,0xd9,0x70,0xb0,0xd9,0x98,0xaa,0xe2,0xc8]


def ROR(data,num):
return ((data >> num) | (data << (8-num))) & 0xff

deadbeef = [0x64,0x65,0x61,0x64,0x62,0x65,0x65,0x66]

for i in range(len(enc)):
enc[i] = ROR(enc[i],3)
enc[i] = box[enc[i]] ^ deadbeef[i % 8]
print(chr(enc[i]),end='')
print()

#flag{I_hate_le333ekk_asd213sadlgajaieo2sa_this_is_s0?}

2hard2u

一个Java层面的控制流混淆,控制点是str的值。

image-20240330212534442

一般控制流呼混淆基本思路都是恢复控制流,找到真实的控制流是怎么样。这里最笨的思路就是手动提取,因为这里str的值自始至终都是与用户无关,即控制流是基本确定的,可以用python啥的脚本提一提,然后再分析。这里采取ZenTracer来查看控制流。

image-20240330220122373

大致的控制流就是

onClick -> encrypt -> ksarpga

JAVA层

其中encrypt的参数是输入和friedchick,这里先跟入ksa查看,可以发现ksa里面调用了很多次swap函数,而且经过观察swap的第二个参数是从0~255递增的。

image-20240330220659989

不妨简单看一下swap的java代码

image-20240330220843561

大致也能看出来是交换数组numArr的值,参数2、参数3就是要交换的坐标

numArr[i], numArr[i2] = numArr[i2], numArr[i],这里交换了256次。其实有点经验的话,可以知道这就是RC4的准备部分,即打乱S盒。

继续往后看rpga

image-20240330222420401

这里也是一堆的swap操作,不过不同的是这里只执行了9次,结合输入只有9个字符,可以猜测出这里应该是生产密钥流。通过最后的返回值也可以看到,只有九个字符

image-20240330223204512

与CyberChef对比,基本一致

image-20240330223305807

So层

继续往后看就是So里面的encode方法,直接IDA打开看

image-20240330223429356

很容易看出这就是一个TEA加密

简单的搓个逆脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from ctypes import *
enc = [0x65E41905,0x1304AD09,0x37A919C6,0x3B6AF9E9,0xB0E6C374,0x59A15C55,0x823627DE,0xFD68D9AD,0x14F078EA,0xCA16C502,0x6D8E8CA8,0x96E34E5A]

for i in range(0,len(enc),2):
v9 = c_uint32(enc[i])
v10 = c_uint32(enc[i+1])
delta = c_uint32(0x9E3779B9 - 0x61C88647 * 31)
for k in range(32):
v10.value -= ((16 * v9.value) | 7) ^ (delta.value + v9.value) ^ ((v9.value >> 5) + 5)
v9.value -= ((v10.value >> 5) + 2) ^ ((16 * v10.value ) | 5) ^ (v10.value + delta.value)
delta.value += 0x61C88647
enc[i],enc[i+1] = v9.value,v10.value

for i in enc:
for k in range(4):
print(hex((i >> (8 * k)) & 0xff)[2:].zfill(2),end='')
# print(hex(i)[2:].zfill(2),end='')

print()
#0601c388c3acc2bdc2b8c2aec2a213c3a2c3bcc3ab0728c38f43c287c294c39d546cc295c385c3a153c2865d78c3bcc2

然后还需要转换一下,从C的char*转回utf-8

image-20240330231842329

flag因为出题人脚本有问题,故不全。

Week4

iwannarest

没什么特别的,跟一跟就可以了,一个TEA类型的算法

image-20240331215601053

对应加密

1
2
3
4
5
6
7
8
9
10
11
12
13
def encrypt(v1:c_uint32,v2:c_uint32):
sum_ = c_uint32(0x9E3779B9)

for i in range(32):
# v13 = (sum_.value >> 2) & 3
v1.value += (((v2.value << 2) ^ (v2.value >> 5)) + ((v2.value >> 3) ^ (v2.value << 4))) ^ ((key[(sum_.value >> 2) & 3] ^ v2.value) + (v2.value ^ sum_.value))
# print(hex(v1.value))
v2.value += (((v1.value << 2) ^ (v1.value >> 5)) + ((v1.value >> 3) ^ (v1.value << 4))) ^ ((key[((sum_.value >> 2) & 3) ^ 1] ^ v1.value) + (v1.value ^ sum_.value))
sum_.value += 0x9E3779B9
# print(hex(v2.value))
# print(hex(sum_.value))
return v1.value,v2.value

对应解密

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
from ctypes import *

key= [1,1,4,5]
def decrypt(v1:c_uint32,v2:c_uint32):
sum_ = c_uint32(0x9E3779B9 + 0x9E3779B9 * 32)

for i in range(32):
sum_.value -= 0x9E3779B9
v2.value -= (((v1.value << 2) ^ (v1.value >> 5)) + ((v1.value >> 3) ^ (v1.value << 4))) ^ ((key[((sum_.value >> 2) & 3) ^ 1] ^ v1.value) + (v1.value ^ sum_.value))
v1.value -= (((v2.value << 2) ^ (v2.value >> 5)) + ((v2.value >> 3) ^ (v2.value << 4))) ^ ((key[(sum_.value >> 2) & 3] ^ v2.value) + (v2.value ^ sum_.value))

# print(hex(sum_.value))
return v1.value,v2.value

# v1,v2 = encrypt(c_uint32(0x61616161),c_uint32(0x62626262))
# print(hex(v1),hex(v2))

enc= [0xEC339492,0xBB7D6A5F,0x5BD9F28A,0x412C450B,0xC5982391,0x3355F5FD,0x1503E350,0x3945171]
for i in range(0,len(enc),2):

v1 = c_uint32(enc[i])
v2 = c_uint32(enc[i+1])
v1,v2 = decrypt(v1,v2)

for k in range(4):
print(chr((v1 >> (k*8))&0xff),end='')
for k in range(4):
print(chr((v2 >> (k*8))&0xff),end='')

# flag{GDu7Il0v3uP1zl3tm3Gr@duate}

简单的跨栏

Java层RC4,Native层变表64,直接静态手撕

Week5

Java层有两个反调试,patch一下即可。

然后主要逻辑都是在Native层,函数是动态注册的,所以名字找不到。不过关键地方也很容易看到,这里用了一个indirectJump混淆,即通过跳转寄存器来混淆。动态调试一下,比较容易看到关键地方。

显然这里将前8字节拆分为两个4字节分别存入w10 w9寄存器,还有魔数0x9E3779B9,大体可以猜测出是TEA类的算法加密,然后继续跟一下就能看到完整的加密流程

image-20240330210331437

Key、密文什么的也很容易拿到,直接搓逆脚本

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
from ctypes import *

key= [52,20,22,11]
def decrypt(v1:c_uint32,v2:c_uint32):
sum_ = c_uint32(0x9E3779B9 * 32)
for i in range(32):
v2.value -= (((v1.value << 4) ^ (v1.value >> 5)) + v1.value) ^ (sum_.value + key[(sum_.value >> 11) & 3])
sum_.value -= 0x9E3779B9
v1.value -= (((v2.value << 4) ^ (v2.value >> 5)) + v2.value) ^ (sum_.value + key[sum_.value & 3])
return v1.value,v2.value


enc = [4040038566,2148388880,4143339962,1106011462,1625757206,2404338960,2235309951,2545489960,249417902,3999178384,2860580105,1697496044]
for i in range(0,len(enc),2):

v1 = c_uint32(enc[i])
v2 = c_uint32(enc[i+1])
v1,v2 = decrypt(v1,v2)

for k in range(4):
print(chr((v1 >> (k*8))&0xff),end='')
for k in range(4):
print(chr((v2 >> (k*8))&0xff),end='')



2023NewStar-Reverser-Android(all)
http://example.com/2024/03/30/2023NewStartAndroid/
Author
yring
Posted on
March 30, 2024
Licensed under