March 17, 2022

D^3CTF2022-D3arm

上次做这个架构的题还在上次,ZJ省赛的unicorn记忆尤新

0x00 日常查壳

虽然是.bin后缀但其实就是arm文件,binwalk跑不出来啥

可以学习下这篇文章如何应对arm文件逆向

https://bbs.pediy.com/thread-249844.htm

image-20220317085707687

0x01 准备分析ARM

首先要选好架构,这个v7-M还是看了wp才知道,不过我有点好奇怎么才能分辨是v几,因为不选的话进去没法分析

image-20220317085836383

再进去可以看到让填基地址,不过先进去才能知道填什么,直接确定

image-20220317090144413

由这里可以知道RAM和ROM的基地址,详情见放文头的那篇文章

1
2
ROM:00000000                 DCD 0x20010000		//RAM 0x20000000
ROM:00000004 DCD 0x80004C9 //ROM 0x8000000

image-20220317090220065

第一个是RAM填入,第二个ROM填入,第三个应该是文件加载地址

image-20220317090601502

进去直接按C再P就全部恢复了,通过查找main字符串到这

image-20220317090703871

发现有段还没定义,于是手动创建这个段

image-20220317090737074

关于地址的开始和结束可以自己去文件里逛逛,命名随意

image-20220317090822445

创完再去赋个权限,ctrl + s调出

image-20220317090914653

alt + s全部拉满

image-20220317090932639

0x02 MAIN函数

再回到main函数,按u按c再p,全部恢复

由于历史遗留还什么问题,8009621的其实是8009620,这里放到了800A578来调用

手动去8009620

image-20220317090450672

继续往里找

image-20220317091241297

F5有点没法恢复,直接看汇编即可,分别去分析每个调用

image-20220317091312462

init

这里主要是index和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
char *init()
{
_DWORD *v0; // r4
_DWORD *v1; // r0

index = 0;
key = 68;
qword_20002304 = 0x500000005i64;
v0 = (_DWORD *)sub_8007850(12);
*v0 = 5;
v0[1] = 6;
v1 = (_DWORD *)sub_8007850(12);
*v1 = 5;
v1[1] = 7;
v1[2] = 0;
dword_2000230C = (int)v0;
v0[2] = v1;
qmemcpy(&unk_20002358, " points:0 ", 21);
sub_800111C(&unk_2000236D, 21, 45);
sub_800111C(&unk_20002382, 126, 32);
LOBYTE(dword_20002400) = 0;
byte_200023F0 = 115;
byte_200023DB = 115;
byte_200023C6 = 115;
return sub_800616C();
}

check

看encfunc前可以先看check,这边是可以猜出通过交叉引用找到那个encfunc,不管是从Index还是flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int check()
{
sub_80075C2(&unk_20002414);
sub_800765E(&unk_20002414, &unk_200001E0, 6);
puts(&unk_20002414, "\n\n\n");
puts(&unk_20002414, " You get %2d points ", index);
puts(&unk_20002414, " Good! Try it again. ");
puts(&unk_20002414, " ");
sub_8007610(&unk_20002414);
if ( index == 42 && dword_200028E4 == 0x6DDD0 )
{
sub_80075C2(&unk_20002414);
sub_800765E(&unk_20002414, &unk_200001E0, 6);
puts(&unk_20002414, "\n\n");
puts(&unk_20002414, " flag is shown below ");
puts(&unk_20002414, flag);
sub_8007610(&unk_20002414);
}
return sub_8007F48(1000000);
}

encfunc

这边的主要还是xorflag和changekey,其他对index和key或是flag都没有变化就不需要关注

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
int encfunc()
{
int result; // r0

while ( 1 )
{
if ( xorflag() )
{
changekey();
sub_800616C();
}
sub_8005AF0();
result = dword_2000230C;
if ( dword_2000230C )
break;
LABEL_6:
result = sub_8005E78();
if ( result )
return result;
sub_80060CC();
sub_8007F48(dword_20000870);
}
while ( *(_QWORD *)result != qword_20002304 )
{
result = *(_DWORD *)(result + 8);
if ( !result )
goto LABEL_6;
}
return result;
}

xorkey

从这里可以拿到密文

1
2
3
4
5
6
7
8
int xorflag()
{
if ( qword_20002304 != qword_200022F4 )
return 0;
if ( index <= 41 )
flag[index] = c[4 * index] ^ key;
return 1;
}

changekey

注意一下v1 v2和key三行语句即可,每次这里调用完又回到xorkey

PS:先执行了一遍xorflag再来到了这changeflag,然后再回去xorkey

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
_DWORD *changekey()
{
_DWORD *result; // r0
int v1; // r1
bool v2; // cc
__int64 *v3; // r1
__int64 *v4; // r2

result = (_DWORD *)sub_8007850(12);
v1 = ++index % 3;
v2 = (unsigned int)(index % 3) > 2;
*result = 0;
result[1] = 0;
result[2] = 0;
if ( !v2 )
key = 0x335E44u >> (8 * v1);
v3 = &qword_20002304;
do
{
v4 = v3;
v3 = (__int64 *)*((_DWORD *)v3 + 2);
}
while ( v3 );
*((_DWORD *)v4 + 2) = result;
return result;
}

0x03 GetFlag!

于是分析完执行流程,再去写脚本就比较容易了

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
enflag = [
0x20, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x50, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x6E, 0x00,
0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x7D, 0x00,
0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x56, 0x00,
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3C, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00,
0x69, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x27, 0x00,
0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x76, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x57, 0x00,
0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,
0x6C, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00
]
flag = ''
index = 0
key = 68
flag += chr(enflag[0] ^ key)

for i in range(4, len(enflag), 4):
index += 1
v1 = index % 3
if not((index % 3) > 2):
key = (0x335E44 >> (8 * v1)) & 0xFF
flag += chr(enflag[i] ^ key)
print(flag)

GetFlag!

image-20220317091941985

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.