夫天地者,万物之逆旅;光阴者,百代之过客。

0%

攻防世界逆向进阶区题解(持续更新)

0x01 dmd-50

img

输入字符串,md5后若为780438d5b6e29db0898bc4f0225935c0则输出正确

img

https://www.cmd5.com/解密

img

但是输入grape不对。

这是因为grape两次md5后才得到780438d5b6e29db0898bc4f0225935c0,而题目中要md5一次就得到780438d5b6e29db0898bc4f0225935c0。卡在这里了。

看了题解才醒悟,将grape md5一次后的得到的字符串,不就可以md5一次得到780438d5b6e29db0898bc4f0225935c0吗。

img

flag就是b781cbb29054db12f88f08c6e161c199,没有前缀。

比较简单,可惜我脑袋没转过弯来。

0x02 Shuffle

img

直接拿到flag。

这种题太浪费时间了。

(话不要说得太满。——《毛选》)

0x03 re2-cpp-is-awesome

题目描述:他们说c++是复杂的,证明他们说的是错的!

忍不住吐槽:其实他们说的是对的。。。

主函数:

img

看着花里胡巧的是吧。

其实那些很长的语句,大多是c++的STL,逆向的时候看着是长,但是正向编程的时候就是一个简单的函数或方法。

这道题比较基础,我没怎么看懂其中的STL,也能做出来

关键代码

img

char_2是char_1,而char_1

img

初步估计就是输入的字符串

判断输入字符串和off_6020A0[dword_6020C0[i_1]]是否相等。off_6020A0是字符型指针,指向

img

dword_6020C0是int数组。

所以就是从dword_6020C0中获取偏移量,再在字符串中获取字符,与输入字符串逐一比较。

获取dword_6020C0的IDC脚本

1
2
3
4
5
6
7
8
9
10
11
12
static main()
{
auto i,fp;
fp = fopen("d:\\1.txt","wb");
auto start = 0x6020c0;
auto size = 0x60213B - 0x6020c0;
for(i=start;i<start+size;i++)
{
fputc(Byte(i),fp);
}
fp.close();
}

解密脚本

1
2
3
4
5
6
7
8
9
10
11
s = r'''L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t'''
n = []
with open('1.txt', 'rb')as f:
data = f.read()
for i,b in enumerate(data):
if i % 4 == 0:
n.append(b)
flag = ''
for i in n:
flag += s[i]
print(flag)

ALEXCTF{W3_L0v3_C_W1th_CL45535}

是不是逻辑很简单?

0x04 crackme

img

见到了一个新壳,nsPack,网上找了个脱壳工具。

img

傻瓜式脱壳

img

不过好像脱的不是很干净,ida打开时弹出几个报错窗口

img

img

不过还是能正常加载出函数来的。

很简单的异或。

img

img

1
2
3
4
a = [0x74] + [ord(i) for i in 'his_is_not_flag']
b = [0x12,4,8,0x14,0x24,0x5c,0x4a,0x3d,0x56,0x0a,0x10,0x67,0,0x41,0,1,0x46,0x5a,0x44,0x42,0x6e,0x0c,0x44,0x72,0x0c,0x0d,0x40,0x3e,0x4b,0x5f,2,1,0x4c,0x5e,0x5b,0x17,0x6e,0x0c,0x16,0x68,0x5b,0x12]
for i in range(42):
print(chr(a[i % 16] ^ b[i]),end='')

0x05 re-for-50-plz-50

本题考查mips架构下的逆向。

https://blog.csdn.net/yang_hong_/article/details/51016867

img

这种汇编我没接触过,肯定看不懂呀。

看了题解才发现,就是字符串异或0x37。

x86,x86-64都还没学好,这类型的题先放一放吧。

1
2
3
s = 'cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ'
for i in s:
print(chr(ord(i) ^ 0x37),end='')

Reversing-x64Elf-100

1575355115328

加密算法:移位后+1.

很简单的算法。

解密脚本:

1
2
3
4
5
6
v3 = "Dufhbmf"+"pG`imos"+"ewUglpt"
a1 = ''
for i in range(12):
a1 += v3[(i%3)*7 + (2*(i//3))]
for i in a1:
print(chr(ord(i)-1),end='')

最初是用c++写的(就是把IDA中的代码改了改),但是不正确。原因在于v3,v4,v5的地址未必连续。

错误脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
int main(){
signed int i; // [rsp+14h] [rbp-24h]
const char *v3; // [rsp+18h] [rbp-20h]
const char *v4; // [rsp+20h] [rbp-18h]
const char *v5; // [rsp+28h] [rbp-10h]
char a1[16];

v3 = "Dufhbmf";
v4 = "pG`imos";
v5 = "ewUglpt";
for ( i = 0; i <= 11; ++i ){
a1[i] = (&v3)[i % 3][2 * (i / 3)];
}
for ( i = 0; i <= 11; ++i ){
cout<<char(a1[i]-1);
}
return 0;
}

IgniteMe

主函数:

看着花里胡巧的,其实关键代码不多。

1575357537830

sub_4011C0:

1575357574529

没啥可说的,直接放解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
byte_4420B0 = [0x0d,0x13,0x17,0x11,0x2,0x1,0x20,0x1d,0x0c,0x2,0x19,0x2f,0x17,0x2b,0x24,0x1f,0x1e,0x16,0x9,0x0f,0x15,0x27,0x13,0x26,0x0a,0x2f,0x1e,0x1a,0x2d,0x0c,0x22,0x4]
string = list(map(ord, 'GONDPHyGjPEKruv{{pj]X@rF'))
flag = []
for i in range(24):
flag.append((((string[i] ^ byte_4420B0[i]) - 72) ^ 0x55) & 0x7f)
print(flag)
for i in range(len(flag)):
if 65 <= flag[i] <= 90:
flag[i] += 32
elif 97 <= flag[i] <= 122:
flag[i] -= 32
print(''.join(map(chr, flag)))

注意一点,异或的运算优先级低于减号。我被这一点坑了十分钟。

srm-50

1575383190071

简直就是明文存储的flag.

把上图中的字符读出来,就是flag.

Windows_Reverse1

1578758322072

加密后的字符串已知,加密如下:

1578758380059

很简单的替换,只是byte_402ff8无法看到数据。

动态轻松获取:

1578758467193

1
2
3
4
5
6
s =   ' '*32 + '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$#"!'
ss = 'DDCTF{reverseME}'
flag = ''
for i in range(len(ss)):
flag += chr(s.index(ss[i]))
print(flag)

拿到flag{ZZ[JX#,9(9,+9QY!}后,我没敢提交,没见过这么怪的flag(swpuctf2019 mobile2除外)