狗儿

热爱的话就坚持吧~

0%

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

鸽了好久了。

0x01 smd-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除外)

Guess-the-Number

JAVA逆向,有手就行。

image-20201125081943842

image-20201125082006705

parallel-comparator-200

给出c源码

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
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#define FLAG_LEN 20

void * checking(void *arg) {
char *result = malloc(sizeof(char));
char *argument = (char *)arg;
*result = (argument[0]+argument[1]) ^ argument[2];
return result;
}

int highly_optimized_parallel_comparsion(char *user_string)
{
int initialization_number;
int i;
char generated_string[FLAG_LEN + 1];
generated_string[FLAG_LEN] = '\0';

while ((initialization_number = random()) >= 64);

int first_letter;
first_letter = (initialization_number % 26) + 97;

pthread_t thread[FLAG_LEN];
char differences[FLAG_LEN] = {0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7};
char *arguments[20];
for (i = 0; i < FLAG_LEN; i++) {
arguments[i] = (char *)malloc(3*sizeof(char));
arguments[i][0] = first_letter;
arguments[i][1] = differences[i];
arguments[i][2] = user_string[i];

pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]);
}

void *result;
int just_a_string[FLAG_LEN] = {115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115};
for (i = 0; i < FLAG_LEN; i++) {
pthread_join(*(thread+i), &result);
generated_string[i] = *(char *)result + just_a_string[i];
free(result);
free(arguments[i]);
}

int is_ok = 1;
for (i = 0; i < FLAG_LEN; i++) {
if (generated_string[i] != just_a_string[i])
return 0;
}

return 1;
}

int main()
{
char *user_string = (char *)calloc(FLAG_LEN+1, sizeof(char));
fgets(user_string, FLAG_LEN+1, stdin);
int is_ok = highly_optimized_parallel_comparsion(user_string);
if (is_ok)
printf("You win!\n");
else
printf("Wrong!\n");
return 0;
}

image-20201125083623182

所以线程返回的每个result都是0

image-20201125083649140

所以异或结果为0

即differences[i] + first_letter == flag[i]

1
2
3
4
5
6
7
8
9
10
11
differences = [0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7]
just_a_string = [115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115]
for i in range(26):
first_letter = 97+i
#print(first_letter)
flag = []
for k in range(len(just_a_string)):
#temp = (differences[k] + first_letter) ^ just_a_string[k]
temp = differences[k] + first_letter
flag.append(temp)
print(''.join(map(chr, flag)))

secret-galaxy-300

算是个脑洞题,没有明显的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
31
32
int __libc_csu_gala()
{
int result; // eax

sc[0] = off_409014;
sc[3] = &byte_40DAC0;
sc[1] = 31337;
sc[2] = 1;
byte_40DAC0 = off_409004[0][8];
byte_40DAC1 = off_409010[0][7];
byte_40DAC2 = off_409008[0][4];
byte_40DAC3 = off_409004[0][6];
byte_40DAC4 = off_409004[0][1];
byte_40DAC5 = off_409008[0][2];
byte_40DAC6 = 95;
byte_40DAC7 = off_409004[0][8];
byte_40DAC8 = off_409004[0][3];
byte_40DAC9 = off_40900C[0][5];
byte_40DACA = 95;
byte_40DACB = off_409004[0][8];
byte_40DACC = off_409004[0][3];
byte_40DACD = off_409004[0][4];
byte_40DACE = off_409010[0][6];
byte_40DACF = off_409010[0][4];
byte_40DAD0 = off_409004[0][2];
byte_40DAD1 = 95;
byte_40DAD2 = off_409010[0][6];
result = *((unsigned __int8 *)off_409008[0] + 3);
byte_40DAD3 = off_409008[0][3];
byte_40DAD4 = 0;
return result;
}

程序初始化的时候通过从别的字符串拼出flag。

image-20201125085040748

simple-check-100

给了三个文件,一样的源码,只是平台不同。

经过分析,输入与flag无关,所以但nop掉相关的函数,直接打印flag.

但是windows上的结果是这样的:

image-20201125092941580

我又去分析了一遍,确实应该输入与flag是无关的。

!!!最后nop了linux64的那个程序,拿到flag。

image-20201125093125775

我服了。上题之前不检验下题目的正确性吗?

Mysterious

vs窗口程序。

经过尝试,输入长度为7的字符串的时候会有动作。

x32dbg附加,然后回溯栈,来到40117c

image-20201125100441179

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
int __stdcall sub_401090(HWND hWnd, int a2, int a3, int a4)
{
int v4; // eax
char Source; // [esp+50h] [ebp-310h]
CHAR Text[4]; // [esp+154h] [ebp-20Ch]
char v8; // [esp+159h] [ebp-207h]
__int16 v9; // [esp+255h] [ebp-10Bh]
char v10; // [esp+257h] [ebp-109h]
int Value; // [esp+258h] [ebp-108h]
CHAR input; // [esp+25Ch] [ebp-104h]
char v13; // [esp+25Fh] [ebp-101h]
char v14; // [esp+260h] [ebp-100h]
char v15; // [esp+261h] [ebp-FFh]

memset(&input, 0, 0x104u);
Value = 0;
if ( a2 == 16 )
{
DestroyWindow(hWnd);
PostQuitMessage(0);
}
else if ( a2 == 273 )
{
if ( a3 == 0x3E8 )
{
GetDlgItemTextA(hWnd, 1002, &input, 260);
strlen(&input);
if ( strlen(&input) > 6 )
ExitProcess(0);
v4 = atoi(&input);
Value = v4 + 1;
if ( v4 == 0x7A && v13 == 0x78 && v15 == 0x7A && v14 == 0x79 )
{
strcpy(Text, "flag");
memset(&v8, 0, 0xFCu);
v9 = 0;
v10 = 0;
_itoa(Value, &Source, 10);
strcat(Text, "{");
strcat(Text, &Source);
strcat(Text, "_");
strcat(Text, "Buff3r_0v3rf|0w");
strcat(Text, "}");
MessageBoxA(0, Text, "well done", 0);
}
SetTimer(hWnd, 1u, 0x3E8u, TimerFunc);
}
if ( a3 == 1001 )
KillTimer(hWnd, 1u);
}
return 0;
}

前面几个字符动调分析拿到。0x401152和0x40118a下个断点,慢慢分析。

经过分析,前几个字符是122xyz

image-20201125095709331

answer_to_everything

脑洞题

image-20201125101544002

flag{#kdudpeh}flag{kdudpeh}都不对

网上查了下,题目描述image-20201125101636675

暗示交sha1…

flag{sha1(kdudpeh)}

即flag{80ee2a3fe31da904c596d993f7f1de4827c1450a}

RE-100

多线程。

image-20201125103116802

首尾是{}

然后分四段

第一段是53fc275d81,第四段是4938ae4efd,但是下一个判断确是整个输入是{daf29f59034938ae4efd53fc275d81053ed5be8c}

不过前面有个!confuseKey(bufParentRead, 42),进去看看。

image-20201125103255625

所以顺序重新调整为3,4,1,2

53fc275d81 053ed5be8c daf29f5903 4938ae4efd

提交flag是{53fc275d81053ed5be8cdaf29f59034938ae4efd},去掉{}

tt3441810

给出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
00400080  68 66 6C 00 00 48 BF 01  00 00 00 00 00 00 00 48
00400090 8D 34 24 48 BA 02 00 00 00 00 00 00 00 48 B8 01
004000A0 00 00 00 00 00 00 00 0F 05 68 61 67 00 00 48 BF
004000B0 01 00 00 00 00 00 00 00 48 8D 34 24 48 BA 02 00
004000C0 00 00 00 00 00 00 48 B8 01 00 00 00 00 00 00 00
004000D0 0F 05 68 7B 70 00 00 48 BF 01 00 00 00 00 00 00
004000E0 00 48 8D 34 24 48 BA 02 00 00 00 00 00 00 00 48
004000F0 B8 01 00 00 00 00 00 00 00 0F 05 68 6F 70 00 00
00400100 48 BF 01 00 00 00 00 00 00 00 48 8D 34 24 48 BA
00400110 02 00 00 00 00 00 00 00 48 B8 01 00 00 00 00 00
00400120 00 00 0F 05 68 70 6F 00 00 48 BF 01 00 00 00 00
00400130 00 00 00 48 8D 34 24 48 BA 02 00 00 00 00 00 00
00400140 00 48 B8 01 00 00 00 00 00 00 00 0F 05 68 70 72
00400150 00 00 48 BF 01 00 00 00 00 00 00 00 48 8D 34 24
00400160 48 BA 02 00 00 00 00 00 00 00 48 B8 01 00 00 00
00400170 00 00 00 00 0F 05 68 65 74 00 00 48 BF 01 00 00
00400180 00 00 00 00 00 48 8D 34 24 48 BA 02 00 00 00 00
00400190 00 00 00 48 B8 01 00 00 00 00 00 00 00 0F 05 68
004001A0 7D 0A 00 00 48 BF 01 00 00 00 00 00 00 00 48 8D
004001B0 34 24 48 BA 02 00 00 00 00 00 00 00 48 B8 01 00
004001C0 00 00 00 00 00 00 0F 05 48 31 FF 48 B8 3C 00 00
004001D0 00 00 00 00 00 0F 05

一看就是某种小众的汇编,但是题目没有任何描述。

所以只能当成misc来做了

image-20201125105112278

0x68这个字节码的作用应该是存储一个word.

1
2
3
4
5
6
7
8
9
10
11
12
13
import struct
with open(r'rev100', 'r')as f:
b = f.read()
data = b''
for line in b.split('\n'):
temp = line[len('00400080 '):].split(' ')
for i in temp:
if i:
data += struct.pack('B', int(i, 16))

for i in range(len(data)):
if data[i] == ord('h'):
print('{}{}'.format(chr(data[i+1]), chr(data[i+2])), end='')

提交去掉flag{}

流浪者

看雪ctf2019的一道题,估计是签到题。

看图标,好像是pascal写的。

image-20201126200057268

打表0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

image-20201126200121340

验证。

所以就是一个简单的置换密码。

1
2
3
4
5
6
7
8
a = 'KanXueCTF2019JustForhappy'
b = 'abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ'
c = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
flag = ''
for i in a:
temp = b.index(i)
flag += c[temp]
print(flag)

666

image-20201126201101386

水题

1
2
3
4
5
6
7
8
9
cipher = list(map(ord, 'izwhroz""w"v.K".Ni'))
key = 0x12
flag = []
for i in range(0, len(cipher), 3):
print(i)
flag.append((key ^ cipher[i]) - 6)
flag.append((key ^ cipher[i+1]) + 6)
flag.append(key ^ cipher[i+2] ^ 6)
print(''.join(map(chr, flag)))

SignIn

image-20201126203257913

逆向里考察rsa

用到了GMP(The GNU Multiple Precision Arithmetic Library)又叫GNU多精度算术库。

n才256bit,直接yafu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
e = 65537

'''
分解自yafu
P39 = 366669102002966856876605669837014229419
P39 = 282164587459512124844245113950593348271
'''

from Crypto.Util.number import *

p = 366669102002966856876605669837014229419
q = 282164587459512124844245113950593348271

phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))