Reverse

logindemo

题目描述:李明的室友初学安卓写了一个登陆的逻辑,请根据har文件的流量中返回正确的请求的签名参数还原出正确的用户名和密码,flag为SCTF{用户名+密码}

Jadx 反编译的 Java 层代码不完整,我们用 Jeb

anything 然后transform然后 getNothing 接着 XOR 最后 generateSignature

一个个看

anything 是对用户名和密码进行打乱顺序,经尝试多次调用能得到原字符串,那我们只需要照着写就行

transform就是乘以 100

Getstr.getNothing在 SO 层

应该是个 RSA,可以看到 P、Q、e

调用 XOR,这个 Jeb 里一直找不到,后面返回去用 Jadx 才找到,你两就不能合一起吗😅

最后是一个 Base64

密文去 sctf.har 中找,搜索 login,可以找到两次登录,可以发现第一次返回200才是成功的,所以密文是第一个

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
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
import base64
from Crypto.Util.number import *

base64_enc = "YgNxAGMDawJjZQR6B2IGYANiYQVxAG8JYQhkawZ3AW8JagluYAN2Am4GbQRmZAR6AWwBbQNlZANxCWsCaAlhZQRxAm4CbgRkZgl1AWIIawhmYAh3B2MBaAJmaghwAWoEbwliYgBwCWkIbQNuawlyAW0FYAhuYgB1Am8CawRuYAJxCG8CbgRgZAF3BWgJYQlhZwFzAGsJbwFlagV0CW0FawhgawNyCGkAbQNjYQh3Bm4FbwNkYAJ6A2IDaANmYwl2A2sEaQRlaglyAm0HaARmYQZ7AWsIbwZhYwB0B2sIYAlvYgN2AWsHYQJiZAByAGgDYANmYQB0BmwJYABhZwl1CGkEaQlmZQJzBm0IYQdjYwh6A20BbwVhZQl3CGoIaABmYAN1AW0IbQFvYAN0B2gFYAVhZAF1BW8HYQZvagZ6A20CaAhjZAl6BWkCYQhvZAN1AGgDaQJhYQZzCW8BYABjZAN0AW8BbQViZwVyA28JagJiagd1CGgDawhvYQJwB28GagNvYwd6AG0BYQFuawVyBGoBaQFkZAV1A24HbgdlYgd1AWwIYQNkagV6BW0DbglvZAl0A2kFaAhjawB3AmwAbwZgZwV3BGMEaQllYAhzAGsEYAFhYAJ6Bm4GaQdkagl6A20DawdkZgd3BW0JbgRgYQZyB2kJbANnZgdwA2gFaQFnYAh7BW4GbAdhYgd7Bm4DawJmawN0CWMDbgJgYwh0AmwGYQRiYQN2BmIGaAVkYwh2BmsDbAFhaglzB2kAbQBjZwJ1BGkCaghiZgByAWkJaAhhagZ3AG0JaghiYQVwAmMIaAFjYgVzBGh0dHA6Ly80Ny4xMDkuMTA2LjYyOjkwOTB7Im5hbWUiOiJTQ1RGIiwicGFzc3dvcmQiOiI4ODg4ODg4OCJ9"
base64_dec = base64.b64decode(base64_enc)
basedecode_enc = bytearray(base64_dec[:base64_dec.index(b"http")])#截断http之后的内容

key = b"S0C0Z0Y0W"
for i in range(len(basedecode_enc)):
basedecode_enc[i] ^= key[i % len(key)]

p = 106697219132480173106064317148705638676529121742557567770857687729397446898790451577487723991083173010242416863238099716044775658681981821407922722052778958942891831033512463262741053961681512908218003840408526915629689432111480588966800949428079015682624591636010678691927285321708935076221951173426894836169
q = 144819424465842307806353672547344125290716753535239658417883828941232509622838692761917211806963011168822281666033695157426515864265527046213326145174398018859056439431422867957079149967592078894410082695714160599647180947207504108618794637872261572262805565517756922288320779308895819726074229154002310375209
e = 65537
n = p * q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
c = int(basedecode_enc)
m = str(pow(c, d, n))
print(m)

tmp = "".join(chr(int(i)) for i in m.split("00")[:-1])

def anything(str):
arr_c = list(str.encode())
to = len(arr_c) - 1
perfect(arr_c, 0, to, (to + 1) // 2)
return bytes(arr_c)
def perfect(a, start, to, n):
if start >= to:
return
if start == to - 1:
a[start], a[to] = a[to], a[start]
k = 0
p = n * 2 + 1
k_3 = 1
while(k <= p // 3):
k += 1
p /= 3
k_3 *= 3
m = (k_3 - 1) // 2
rightCircle(a, start + m, start + n + m - 1, m)
i = 0
t = 1
while(i < k):
circle(a, start-1, t, m * 2 + 1)
t *= 3
i += 1
perfect(a, m * 2 + start, to, (to - (m * 2 + start) + 1) // 2)
def circle(a, start, i, n2):
k = i * 2 % n2
while(k != i):
a[start + i], a[start + k] = a[start + k], a[start + i]
k = k * 2 % n2
def rightCircle(a, start, to, n):
m = n %(to - start + 1)
reverse(a, to - m + 1, to)
reverse(a, start, to - m)
reverse(a, start, to)
def reverse(a, start, to):
while(start < to):
a[start], a[to] = a[to], a[start]
start += 1
to -= 1

original = tmp
for i in range(100):
flag = tmp
tmp = anything(tmp).decode()
if tmp == original:
print('SCTF{'+ flag + '}')
break
#12100119001160011500550010400117001090010600530010400540010300
#ywts7humj5h6g
#SCTF{wshm56yt7ujhg}

BBox

b box b b BOO BOO BOO BOO。

最终flag请用SCTF{}包裹

SO 层的 checkflag 和 Java 层的 strange.encode ,Jadx 看不到 strange.encode,应该是有混淆

想着用 firda 试试,结果只要 frida_server 一开,点 check 就会闪退,应该是有检测

经尝试用 hluda ,并且换个端口能绕过

1
2
./hluda-s-x86_64 -l 0.0.0.0:9999
adb forward tcp:9999 tcp:9999(需要另外开一个终端)

然后我们用 r0tracer trace com.example.bbandroid.strange这个类

1
frida -H 127.0.0.1:9999 -f com.example.bbandroid -l r0tracer.js

可以拿到码表和返回值

或者 Jeb 静态分析+调试

静态有控制流平坦化,但勉强能看,大致能猜到可能是 base64 + 异或

码表懒得看直接调试,这里能拿到nopqrstDEFGHIJKLhijklUVQRST/WXYZabABCcdefgmuv6789+wxyz012345MNOP=

然后看到 length 猜测异或了长度

用 算法助手 Hook 一下,验证

这里再额外记录一下 Objection 使用,也能 Hook 到堆栈和函数返回值

同样是启动服务转发端口,然后

1
2
objection -N -h 127.0.0.1 -p 9999 -g com.example.bbandroid explore
android hooking watch class_method com.example.bbandroid.strange.encode --dump-args --dump-backtrace --dump-return

那基本上就确定了,我们再看看 SO

checkflag用到了随机种子,但是种子计算了除法,应该就是固定值 17 了

异或完随机数是一个 CRC32,逆一下

注意实在 Linux 下运行即可

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
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
uint32_t decrypt(uint32_t data, uint32_t key) {
for (int i = 0; i < 32; i++) {
if (data & 1) {
data = (data ^ key) >> 1;
data |= 0x80000000;
} else {
data = data >> 1;
}
}
return data;
}

int main() {
uint32_t key = 0x85B6874F;

uint32_t enc[] = {0xA3C8C033, 0x1A1DBFF3, 0xC6B7413B, 0x52865EF1, 0x1E6BCF52,
0xBFCBF9C5, 0xF1627BED, 0x544843F7, 0xD94C85FB, 0x6EF23035};
unsigned char dec[40];
for (int i = 0; i < 10; i++) {
uint32_t decrypted = decrypt(enc[i], key);
((uint32_t *)dec)[i] = decrypted;
}
for (int i = 0; i < 40; i++) {
printf("%x ", dec[i]);
}
printf("\n");
srand(17);
for (int i = 0; i < 40; i++) {
dec[i] ^= rand() & 0xff;
}
printf("%s\n", dec);
return 0;
}
/*
f1 d8 e 67 d0 68 80 e 34 fc 69 b4 c4 c0 e8 92 f6 50 2a 6e a5 a6 a8 49 6a 9 aa 28 f8 f4 91 17 c7 42 3f 5b 32 4a d3 89
HuqdOgqiMKPiWHFxFmPiW/M}I\rfO.}fO.K|I/]|
*/

最后异或和解 base64

SCTF{Y0u_@re_r1ght_r3ver53_is_easy!}

ez_cython

I love C and Python!!!

用 python3.8 解包

pycdc 反编译 pyc

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
# Source Generated with Decompyle++
# File: ez_cython.pyc (Python 3.8)

import cy

def str_hex(input_str):
return (lambda .0: [ ord(char) for char in .0 ])(input_str)


def main():
print('欢迎来到猜谜游戏!')
print("逐个输入字符进行猜测,直到 'end' 结束。")
guess_chars = []
char = input("请输入一个字符(输入 'end' 结束):")
if char == 'end':
pass
elif len(char) == 1:
guess_chars.append(char)
continue
print('请输入一个单独的字符。')
continue
guess_hex = str_hex(''.join(guess_chars))
if cy.sub14514(guess_hex):
print('真的好厉害!flag非你莫属')

print('不好意思,错了哦。')
retry = input('是否重新输入?(y/n):')
if retry.lower() != 'y':
pass

print('游戏结束')

if __name__ == '__main__':
main()

check 在 cy.sub14514

可以用 python3.8 去加载 cy.cp38-win_amd64.pyd

cy.sub50520是 XXTea ,cy.sub50804是 XXTea 的 MX 位移函数

cy.sub114514 调用 XXTea 并对密文进行 Check

密文在这两函数里对照一下能搞出来

或者学习别人的做法注入一下

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
51
52
53
54
55
56
57
58
59
60
61
62
63
import cy

class Symbol:
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
def __rshift__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} >> {other.name})")
else:
expression = Symbol(f"({self.name} >> {other})")
return expression
def __lshift__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} << {other.name})")
else:
expression = Symbol(f"({self.name} << {other})")
return expression
def __rxor__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} ^ {other.name})")
else:
expression = Symbol(f"({self.name} ^ {other})")
return expression
def __xor__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} ^ {other.name})")
else:
expression = Symbol(f"({self.name} ^ {other})")
return expression
def __add__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} + {other.name})")
else:
expression = Symbol(f"({self.name} + {other})")
return expression
def __and__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} & {other.name})")
else:
expression = Symbol(f"({self.name} & {other})")
return expression

class AList:
def __init__(self, nums):
self.nums = [Symbol(str(num)) for num in nums]
def __getitem__(self, key):
return self.nums[key]
def copy(self):
return AList(self.nums)
def __len__(self):
return len(self.nums)
def __setitem__(self, key, value):
print(f"new_{self.nums[key]} = {value}")
self.nums[key] = Symbol(f"new_{self.nums[key].name}")
def __eq__(self, other):
print(f"{self.nums} == {other}")
return self.nums == other

enc = AList([f"a[{i}]" for i in range(32)])
res = cy.sub14514(enc)
print(res)

最后就是解 XXTea,注意几处魔改的地方就好了

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
51
52
53
54
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define DELTA 0x9E3779B9
#define MX (z >> 3 ^ y << 3) + (y >> 4 ^ z << 2) ^ (sum ^ y) + (k[(p & 2) ^ e] ^ z)

void xxtea_encrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len - 1;
uint32_t y, z, sum = 0, e, p, q;
q = 4 + 60 / len;
while (q-- > 0) {
sum += DELTA;
e = sum >> 3 & 3;
for (p = 0; p < n; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n] += MX;
}
}

void xxtea_decrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len;
uint32_t y = v[0], z, sum, e, p, q;
q = 4 + 60 / len;
sum = q * DELTA;
while (sum != 0) {
e = sum >> 3 & 3;
for (p = n-1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
}
}

int main() {
uint32_t v[32] = { 4108944556, 3404732701, 1466956825, 788072761, 1482427973, 782926647, 1635740553, 4115935911, 2820454423, 3206473923, 1700989382, 2460803532, 2399057278, 968884411, 1298467094, 1786305447, 3953508515, 2466099443, 4105559714, 779131097, 288224004, 3322844775, 4122289132, 2089726849, 656452727, 3096682206, 2217255962, 680183044, 3394288893, 697481839, 1109578150, 2272036063};
uint32_t const k[4] = { 0x53, 0x79, 0x43, 0x31 };
xxtea_decrypt(v, 32, k);
printf("Decrypted data:\n");
for (int i = 0; i < 32; i++) {
printf("%c", v[i]);
}
return 0;
}
/*
Decrypted data:
SCTF{w0w_y0U_wE1_kNOw_of_cYtH0N}
*/

uds

能告诉我汽车的VIN码吗?

Can you tell me the VIN number of the car?

ida 加载的时候选择 ARM 小端架构

根据字符串 UDS 跟踪到函数 sub_80043E8

sub_8104D10是个端序转换然后调用sub_8104CA8加密,并且传入的参数为{0x0123,0x4567,0x89AB,0xCDEF}

sub_8104CA8是个 Tea

然后 sub_81045D0是个 RC4 ,key 是 Tea 的加密结果

密文是生成的在 sub_810004C

sub_810004C的参数是dword_8004EC8

直接扒代码模拟一下生成密文,并且计算出 Tea 加密的结果作为 RC4 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
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
#include <stdio.h>
#include <stdint.h>
int __fastcall sub_810004C(char *a1)
{
char v4 = 0; // r2
char v5 = 0; // t1
char v6 = 0; // r3
char v7 = 0; // t1
char v8 = 0; // r2
char v9 = 0; // t1
char v10 = 0; // t1
int i = 0,j = 0;
uint8_t a2[0x195] = {0};
do
{
v5 = a1[i++];
v4 = v5;
v6 = v5 & 0xF;
if ( (v5 & 0xF) == 0 )
{
v7 = a1[i++];
v6 = v7;
}
v8 = v4 >> 4;
if ( !v8 )
{
v9 = a1[i++];
v8 = v9;
}
while ( --v6 )
{
v10 = a1[i++];
a2[j++] = v10;
}
while ( --v8 )
a2[j++] = 0;
}
while ( j < 0x194 );
for (int i = 0; i < 0x195; i++) {
printf("%x ", a2[i]);
}
return 0;
}

void tea_encrypt (uint32_t* v, uint32_t* k) {
uint32_t sum = 0;
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}

v[0]=v0;
v[1]=v1;
}

int main(){
char a1[40] ={0x01, 0x13, 0x02, 0x96, 0x88, 0x00, 0x12, 0xB0, 0x14, 0xA6, 0x91, 0xFE, 0xB9, 0xD7, 0x41, 0xAF, 0x82, 0xCC, 0x4E, 0xE9, 0x47, 0x47, 0x28, 0x4F, 0xD1, 0x42, 0x10, 0x52, 0x01, 0x58, 0x90, 0xD0, 0x03, 0x00, 0x90, 0xD0, 0x03, 0x02, 0x18, 0x01};
sub_810004C(a1);
uint32_t enc[2] = {0x11223344, 0x55667788};
uint32_t key[4] = {0x0123, 0x4567, 0x89AB, 0xCDEF};
tea_encrypt(enc, key);
printf("\n");
printf("Encrypted data:\n");
printf("%x %x\n", enc[0], enc[1]);
}
/*
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 a6 91 fe b9 d7 41 af 82 cc 4e e9 47 47 28 4f d1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 1 0 0 0 0 90 d0 3 0 90 d0 3 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Encrypted data:
604a8a6e 9dacb167
*/