2020-10-14

逆向练习#6

[BUUCTF-SimpleRev]

1.

放进exeinfo查看信息,是elf文件,丢进IDA64位。

2.

搜索关键字段进入主要函数

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
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h]
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9; // [rsp+40h] [rbp-20h]
__int64 v10; // [rsp+48h] [rbp-18h]
int v11; // [rsp+50h] [rbp-10h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]

v12 = __readfsqword(0x28u);
*(_QWORD *)src = 'SLCDN';
v7 = '\0';
v8 = 0;
v9 = 'wodah';
v10 = 0LL;
v11 = 0;
text = join(key3, (const char *)&v9); //join是自定义函数,简单的把两个字符串拼接
//即在key3后面增添V9,text='killshadow'
strcpy(key, key1);
strcat(key, src); //key="ADSFKNDCLS"
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
//if(key[v3]>64 && key[v3]<=90)
//把key每一位大写变小写
key[i] = key[v3 % v5] + 32;
++v3;
} //这个v3不知道做什么的
printf("Please input your flag:", src);
while ( 1 )
{
v1 = getchar();
if ( v1 == '\n' )
break;
if ( v1 == ' ' ) //遍历字符,是换行符结束,进入下一个判断:空格跳过
{
++v2; //v2表示字符串中字符的位号,这里判断是空格,于是+1
}
else
{
if ( v1 <= '`' || v1 > 'z' )
{
if ( v1 > '@' && v1 <= 'Z' )
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; //v2是会逐增的
//str2[v2] = (v1-key[v3]+58)%26 + 97
}
else
{
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
//以上为加密操作,所以我们根据这些反推。
}
if ( !(v3 % v5) ) //如果循环到key的最后一位
putchar(32); //输出空格
++v2;
}
}
if ( !strcmp(text, str2) ) //与text对比
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v12;
}

key3跟进,是字符串”kills”。key1是”ADSFK”。

由于字符串小端序存储,反过来写,所以注释中text与key是这个结果。

一般来说,x86系列cpu都是小端序存储,大端序一般用于网络协议。

经验:遇到不明数字最好转换成char类型看看,不然可能会找不到解题关键。

3.

写解密脚本

本来想着自己独立写的,但耗时许久没有成功,取余逆运算是知识盲区。

如:A=(B-C)%D
那么B=(A+C)%D

推倒过程:

​ 比如假设都是正整数
​ A=(B-C)%D
​ 则 B - C = D*n + A 其中 A < D

​ 移项 B = A+C + Dn
​ 当B<D时,两边对D取摸,
​ B = B%D = ( A+C + D
n )%D = (A+C)%D

好家伙,正好最近在学信安数学原理。但需要猜测D的存在。

于是python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
text = 'killshadow'
key = 'adsfkndcls'
key_ = ''
v3=0
for i in range(len(key)):
flag = ord(key[v3%len(key)])
if flag > 64 and flag <=90:
key_ += chr(ord(key[v3%len(key)])+32)
v3=v3+1 #这一段for循环是大小写变换,可以不要
ans = ''
for i in range(len(key)):
for j in range(0,15): #算是爆破?
tmp=chr(ord(text[i]) - 97 + 26*j - 97 + ord(key [v3%len(key)]) + 39)
if ord(tmp)>64 and ord(tmp) <91: #试对了的正确结果输出
ans+=tmp
break
v3=v3+1
print (ans)

网上扒来的

疑惑:为什么是key [v3%len(key)],大概是顺应伪代码的原意。

自我缩减版

1
2
3
4
5
6
7
8
9
10
text = 'killshadow'
key = 'adsfkndcls'
ans = ''
for i in range(len(key)):
for j in range(0,15):
tmp=chr(ord(text[i]) - 97 + 26*j - 97 + ord(key[i]) + 39)
if ord(tmp)>64 and ord(tmp) <91:
ans+=tmp
break
print (ans)

不知为什么这个脚本能确定结果必然是大写的,不过要是不确定加上if检查是否小写就行了。

应该是因为有大写变小写的操作。

得出结果:KLDQCUDFZO

搞定!