2023SharkCTF-week3-Reverse-wp

2023SharkCTF-week3-Reverse-wp

2023.9.16 by Shen_Fan


第三周的题大多是烂活,还请各位佬轻喷

Encrypted_Code

运行后是个平平无奇的flag检查程序,扔ida里看一眼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[80]; // [rsp+20h] [rbp-50h] BYREF

sub_401A20(argc, argv, envp);
printf("flag: ");
scanf("%60s", v4);
((void (__fastcall *)(char *))loc_401550)(v4);
if ( unk_408970 )
puts("Correct!");
else
puts("Wrong!");
system("pause");
return 0;
}

可以看到程序读入一个字符串到v4,然后将v4作为loc_401550的参数进行函数调用,再根据unk_408970的值进行判断。

对unk_408970进行交叉引用查询发现无其他引用,且loc_401550处是依托乱码,代码可能被加密。使用ida进行动态调试得到loc_401550解密后的代码

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
_DWORD *__fastcall sub_401550(__int64 a1)
{
__int64 v1; // r11
_DWORD *result; // rax
char v3[48]; // [rsp-68h] [rbp-78h] BYREF
_BYTE v4[23]; // [rsp-38h] [rbp-48h] BYREF
int j; // [rsp-14h] [rbp-24h]
int i; // [rsp-10h] [rbp-20h]
int v7; // [rsp-Ch] [rbp-1Ch]
__int64 v8; // [rsp+0h] [rbp-10h]

v8 = v1;
v7 = -559038737;
for ( i = 0; i <= 12; ++i )
{
*(_DWORD *)(4i64 * i + a1) ^= v7;
v7 = *(_DWORD *)(4i64 * i + a1);
if ( v7 != dword_404020[i] )
{
result = dword_408970;
dword_408970[0] = 0;
return result;
}
}
if ( *(_DWORD *)(a1 + 52) )
{
result = dword_408970;
dword_408970[0] = 0;
}
else
{
dword_408970[0] = 1;
qmemcpy(v3, ")/873..?>z<6;=z<5(7;.`z!#5/(z34*/.'", 35);
v3[35] = 5;
v3[36] = 33;
v3[37] = 60;
v3[38] = 51;
v3[39] = 40;
v3[40] = 41;
v3[41] = 46;
v3[42] = 122;
v3[43] = 110;
v3[44] = 24;
v3[45] = 3;
v3[46] = 14;
v3[47] = 31;
qmemcpy(v4, "z\"5(z2?\"z4/78?('zqzx'xP", sizeof(v4));
for ( j = 0; ; ++j )
{
result = (_DWORD *)strlen(v3);
if ( j >= (unsigned __int64)result )
break;
putchar(v3[j] ^ 0x5A);
}
}
return result;
}

简单的异或,编写脚本如下:

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
#include <bits/stdc++.h>

using namespace std;

int dword_404020[16] =
{
-1395861860,
-893864457,
-1879193972,
-693979679,
-1644306258,
-1031098400,
-1646403416,
-108875873,
-1091069990,
-1883249787,
-571491167,
-375522354,
-927162717,
0,
0,
0
};

int main() {
for(int i = 12; i > 0; i--) {
dword_404020[i] ^= dword_404020[i - 1];
}
dword_404020[0] ^= -559038737;
puts((char *)dword_404020);

char v3[200];
memcpy(v3, ")/873..?>z<6;=z<5(7;.`z!#5/(z34*/.'", 35);
v3[35] = 5;
v3[36] = 33;
v3[37] = 60;
v3[38] = 51;
v3[39] = 40;
v3[40] = 41;
v3[41] = 46;
v3[42] = 122;
v3[43] = 110;
v3[44] = 24;
v3[45] = 3;
v3[46] = 14;
v3[47] = 31;
memcpy(v3+48, "z\"5(z2?\"z4/78?('zqzx'xP", 25*sizeof(char));
for(int i = 0; i < 73; i++) {
v3[i] ^= 0x5A;
}
v3[73] = 0;
puts(v3);
}

得到结果

1
2
sharkctf{sEEms_YOU_KNOw_HOW_7O_dE8uG_tH1$_PRoGr4me!!
submitted flag format: {your input}_{first 4BYTE xor hex number} + "}"

拼接得到最终flag:

1
sharkctf{sEEms_YOU_KNOw_HOW_7O_dE8uG_tH1$_PRoGr4me!!_0xdeadbeaf}

Find_Bomb_Plus

解法1:

直接扫雷得到flag(有一定概率可以不猜直接扫出)

解法2:

通过动态调试直接找到雷的位置然后解出

解法3:

通过ida进行patch更改地图大小为1*21,一发入魂

flag就交给你们自己去找了

shell

扔到die里一看,upx,还被modified了,手动脱一手壳

这里使用的工具是x64dbg

F9越过库函数后来到这里

shell_1

根据esp定理,在这里某一次push后在内存对应位置下硬件断点

shell_2

shell_3

然后F9开始运行直到断点被触发

shell_4

待pop完成后使用插件Scylla进行dump

shell_5

将dump后的程序丢入ida后根据字符串”flag:”找到main函数

对逻辑分析后鉴定为rc4,编写脚本解密

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

char key[] ={"I_am_the_key_of_flag"};
unsigned char s[256]={0};
unsigned char ida_chars[] =
{
0xB0, 0xD2, 0x49, 0x3F, 0x5C, 0xEE, 0x55, 0xB2, 0x5B, 0x3C,
0xA5, 0xEA, 0x41, 0x11, 0x86, 0xD9, 0x5C, 0x12, 0xE9, 0xCF,
0x28, 0x79, 0x46, 0x65, 0x55, 0xE1, 0x0E, 0x49, 0x00, 0x00,
0x00, 0x00, 0x60, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00
};

void rc4_init()
{
int Len=strlen(key);
int i =0, j = 0;
char k[256] = {0};
unsigned char tmp = 0;
for (i=0;i<256;i++) {
s[i] = i;
k[i] = key[i%Len];
}
for (i=0; i<256; i++) {
j=(j+s[i]+k[i])%256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

void rc4_crypt(unsigned char *Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for(k=0;k<Len;k++) {
i=(i+1)%256;
j=(j+s[i])%256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t=(s[i]+s[j])%256;
Data[k] ^= s[t];
}
}

int main() {
rc4_init();
rc4_crypt(ida_chars, 28);
for (int i = 0; i < 28; i++) {
printf("%c", ida_chars[i]);
}
}

得到flag:

1
sharkctf{upX_@Nd_RC4_15_fuN}

Star_Rail

如果说扫雷还能扫出来,那么这个是真抽不出来了(悲

使用ida64打开,虽然能找到输出flag的函数,但函数被加花了ida无法直接分析。

根据平时的经验,对随机数判断部分进行patch来逆天改命

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
for ( i = 0; i <= 9; ++i )
{
v4 = rand();
if ( v4 % 100 > 1 )
{
if ( v4 % 100 > 17 )
{
printf(&byte_405153);
++v11;
}
else
{
printf(&byte_40514D);
++v12;
}
}
else
{
printf(&Format);
++dword_408030;
}
if ( i == 4 || i == 9 )
putchar(10);
}

可以看到若v4为0或1,即可输出金光,直接根据汇编将此判断改为100

以下是详细过程:

st_1

st_2

st_3

st_4

st_5

st_6

然后在ida中Edit->Patch programe->Apply patched to…将patch覆盖到原程序文件

运行一键得到flag