Reverse_0

想写点什么却又不知该写什么, 就写写BUUOJ的逆向题解记录吧

easyre

链接: https://buuoj.cn/challenges#easyre

EXE 64

IDA中 main 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
int __cdecl main(int argc, const char **argv, const char **envp)
{
int b; // [rsp+28h] [rbp-8h]
int a; // [rsp+2Ch] [rbp-4h]

_main();
scanf("%d%d", &a, &b);
if ( a == b )
printf("flag{this_Is_a_EaSyRe}");
else
printf("sorry,you can't get flag");
return 0;
}

输入两个一样的数字即输出flag

flag{this_Is_a_EaSyRe}


reverse1

链接: https://buuoj.cn/challenges#reverse1

EXE 64

IDA中 sub_1400118C0 函数反编译结果如下

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
__int64 sub_1400118C0()
{
char *v0; // rdi
signed __int64 i; // rcx
size_t v2; // rax
size_t v3; // rax
char v5; // [rsp+0h] [rbp-20h]
int j; // [rsp+24h] [rbp+4h]
char Str1; // [rsp+48h] [rbp+28h]
unsigned __int64 v8; // [rsp+128h] [rbp+108h]

v0 = &v5;
for ( i = 82i64; i; --i )
{
*(_DWORD *)v0 = 0xCCCCCCCC;
v0 += 4;
}
for ( j = 0; ; ++j )
{
v8 = j;
v2 = j_strlen(Str2);
if ( v8 > v2 )
break;
if ( Str2[j] == 111 )
Str2[j] = 48;
}
sub_1400111D1((__int64)"input the flag:");
sub_14001128F("%20s", &Str1);
v3 = j_strlen(Str2);
if ( !strncmp(&Str1, Str2, v3) )
sub_1400111D1((__int64)"this is the right flag!\n");
else
sub_1400111D1((__int64)"wrong flag\n");
sub_14001113B(&v5, &unk_140019D00);
return 0i64;
}

其中Str2="{hello_world}", 而函数在遍历Str2时, 会把'o'(111)替换为'0'(49), 最后将用户的输入(Str1)与Str2进行比较

flag{hell0_w0rld}


reverse2

链接: https://buuoj.cn/challenges#reverse2

ELF 64

IDA中 main 函数反编译结果如下

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 __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
int stat_loc; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
__pid_t pid; // [rsp+Ch] [rbp-34h]
char s2; // [rsp+10h] [rbp-30h]
unsigned __int64 v8; // [rsp+28h] [rbp-18h]

v8 = __readfsqword(0x28u);
pid = fork();
if ( pid )
{
argv = (const char **)&stat_loc;
waitpid(pid, &stat_loc, 0);
}
else
{
for ( i = 0; i <= strlen(&flag); ++i )
{
if ( *(&flag + i) == 105 || *(&flag + i) == 114 )
*(&flag + i) = 49;
}
}
printf("input the flag:", argv);
__isoc99_scanf("%20s", &s2);
if ( !strcmp(&flag, &s2) )
result = puts("this is the right flag!");
else
result = puts("wrong flag!");
return result;
}

其中flag="{hacking_for_fun}", 函数在遍历flag时会将'i'(105)'r'(114)替换为'1'(49)

flag{hack1ng_fo1_fun}


内涵的软件

链接: https://buuoj.cn/challenges#内涵的软件

EXE 32

IDA中 main_0 函数反编译结果如下

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
int main_0()
{
int result; // eax
char v1; // [esp+4Ch] [ebp-Ch]
const char *v2; // [esp+50h] [ebp-8h]
int v3; // [esp+54h] [ebp-4h]

v3 = 5;
v2 = "DBAPP{49d3c93df25caad81232130f3d2ebfad}";
while ( v3 >= 0 )
{
printf(aD, v3);
sub_40100A();
--v3;
}
printf(
"\n"
"\n"
"\n"
"这里本来应该是答案的,但是粗心的程序员忘记把变量写进来了,你要不逆向试试看:(Y/N)\n");
v1 = 1;
scanf("%c", &v1);
if ( v1 == 89 )
{
printf(aOdIda);
result = sub_40100A();
}
else
{
if ( v1 == 78 )
printf(asc_425034);
else
printf("输入错误,没有提示.");
result = sub_40100A();
}
return result;
}

flag{49d3c93df25caad81232130f3d2ebfad}


新年快乐

链接: https://buuoj.cn/challenges#新年快乐

EXE 32

1
2
file 新年快乐.exe
新年快乐.exe: PE32 executable (console) Intel 80386, for MS Windows, UPX compressed

存在UPX壳

脱壳

1
2
3
4
5
6
7
8
9
10
upx -d 新年快乐.exe
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020

File size Ratio Format Name
-------------------- ------ ----------- -----------
27807 <- 21151 76.06% win32/pe 新年快乐.exe

Unpacked 1 file.

IDA中 _main 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char v4; // [esp+12h] [ebp-3Ah]
__int16 v5; // [esp+20h] [ebp-2Ch]
__int16 v6; // [esp+22h] [ebp-2Ah]

__main();
strcpy(&v4, "HappyNewYear!");
v5 = 0;
memset(&v6, 0, 0x1Eu);
printf("please input the true flag:");
scanf("%s", &v5);
if ( !strncmp((const char *)&v5, &v4, strlen(&v4)) )
result = puts("this is true flag!");
else
result = puts("wrong!");
return result;
}

flag{HappyNewYear!}


helloword

链接: https://buuoj.cn/challenges#helloword

Android

使用Android Studio打开

java->com.example->helloworld->MainActivity中得到flag

flag{7631a988259a00816deda84afb29430a}


xor

链接: https://buuoj.cn/challenges#xor

EXE 64

IDA中 _main 函数反编译结果如下

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
int result; // eax
signed int i; // [rsp+2Ch] [rbp-124h]
char v6[264]; // [rsp+40h] [rbp-110h]
__int64 v7; // [rsp+148h] [rbp-8h]

memset(v6, 0, 0x100uLL);
v3 = (char *)256;
printf("Input your flag:\n", 0LL);
get_line(v6, 256LL);
if ( strlen(v6) != 33 )
goto LABEL_12;
for ( i = 1; i < 33; ++i )
v6[i] ^= v6[i - 1];
v3 = global;
if ( !strncmp(v6, global, 0x21uLL) )
printf("Success", v3);
else
LABEL_12:
printf("Failed", v3);
result = __stack_chk_guard;
if ( __stack_chk_guard == v7 )
result = 0;
return result;
}
1
2
3
4
5
6
_global = [
0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11,
0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F,
0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F,
0x47, 0x32, 0x4F
]

用户输入经过异或操作后与global相比较, 则global为加密后的flag

解密脚本如下

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
cipher = [
0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11,
0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F,
0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F,
0x47, 0x32, 0x4F]
flag = chr(cipher[0])
for i in range(1, len(cipher)):
flag += chr(cipher[i]^cipher[i-1])
print(flag)

flag{QianQiuWanDai_YiTongJiangHu}


reverse3

链接: https://buuoj.cn/challenges#reverse3

EXE 32

IDA中 _main_0 函数反编译结果如下

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
__int64 main_0()
{
size_t v0; // eax
const char *v1; // eax
size_t v2; // eax
int v3; // edx
__int64 v4; // ST08_8
signed int j; // [esp+DCh] [ebp-ACh]
signed int i; // [esp+E8h] [ebp-A0h]
signed int v8; // [esp+E8h] [ebp-A0h]
char Dest[108]; // [esp+F4h] [ebp-94h]
char Str; // [esp+160h] [ebp-28h]
char v11; // [esp+17Ch] [ebp-Ch]

for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Dest[i] = 0;
}
sub_41132F("please enter the flag:");
sub_411375("%20s", &Str);
v0 = j_strlen(&Str);
v1 = (const char *)sub_4110BE(&Str, v0, &v11);
strncpy(Dest, v1, 0x28u);
v8 = j_strlen(Dest);
for ( j = 0; j < v8; ++j )
Dest[j] += j;
v2 = j_strlen(Dest);
if ( !strncmp(Dest, Str2, v2) )
sub_41132F("rigth flag!\n");
else
sub_41132F("wrong flag!\n");
HIDWORD(v4) = v3;
LODWORD(v4) = 0;
return v4;
}
  • Str2 = "e3nifIH9b_C@n@dH"
1
2
3
4
5
6
#!/usr/bin/env python3
cipher="e3nifIH9b_C@n@dH"
string = ""
for i in range(len(cipher)):
string += chr(ord(cipher[i])-i)
print(string)

解密得到字符串e2lfbDB2ZV95b3V9

在观察函数可以看到用户输入的字符串经过了函数sub_4110BE的处理
跟进函数可以看到一个字符串

1
aAbcdefghijklmn="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

可以判断内容为Base64字符集, 即函数功能为Base64编码

1
2
echo -n "e2lfbDB2ZV95b3V9" | base64 -d
{i_l0ve_you}

flag{i_l0ve_you}


不一样的flag

链接: https://buuoj.cn/challenges#不一样的flag

EXE 32

IDA中 _main 函数反编译结果如下

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // [esp+17h] [ebp-35h]
int v4; // [esp+30h] [ebp-1Ch]
int v5; // [esp+34h] [ebp-18h]
signed int v6; // [esp+38h] [ebp-14h]
int i; // [esp+3Ch] [ebp-10h]
int v8; // [esp+40h] [ebp-Ch]

__main();
v4 = 0;
v5 = 0;
qmemcpy(&v3, _data_start__, 0x19u);
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v6);
if ( v6 == 2 )
{
++v4;
}
else if ( v6 > 2 )
{
if ( v6 == 3 )
{
--v5;
}
else
{
if ( v6 != 4 )
LABEL_13:
exit(1);
++v5;
}
}
else
{
if ( v6 != 1 )
goto LABEL_13;
--v4;
}
for ( i = 0; i <= 1; ++i )
{
if ( *(&v4 + i) < 0 || *(&v4 + i) > 4 )
exit(1);
}
if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 49 )
exit(1);
if ( *((_BYTE *)&v8 + 5 * v4 + v5 - 41) == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}

输入"1234"分别对应上下左右, v4为Y轴, v5为X轴

这段代码用于检测Y轴与X轴的值是否在[0, 4]这个范围内
(v4, v5使用连续的内存空间, 目测是数组, 所以*(&v4 + i)可以指向v5)

1
2
3
4
5
for ( i = 0; i <= 1; ++i )
{
if ( *(&v4 + i) < 0 || *(&v4 + i) > 4 )
exit(1);
}
  • _data_start__="*11110100001010000101111#"

且该值被赋给v3, v3为字符数组且开始内存为[esp+17h]

当v4 v5为0时, *((_BYTE *)&v8 + 5 * v4 + v5 - 41)指向地址为[esp+17h], 即v3的开始内存

则通过v4与v5的值可以控制内存的指向, 可以画出迷宫地图

1
2
3
4
5
6
7
maze = """
* 1 1 1 1
0 1 0 0 0
0 1 0 1 0
0 0 0 1 0
1 1 1 1 #
"""

*((_BYTE *)&v8 + 5 * v4 + v5 - 41)指向的值为'1'(49)时, 程序退出

*((_BYTE *)&v8 + 5 * v4 + v5 - 41)指向的值为'#'(35)时, 则走出迷宫

则可以得出flag

flag{222441144222}


SimpleRev

链接: https://buuoj.cn/challenges#SimpleRev

ELF 64

IDA中 main 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char v4; // [rsp+Fh] [rbp-1h]

while ( 1 )
{
while ( 1 )
{
printf("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: ", argv, envp);
v4 = getchar();
if ( v4 != 100 && v4 != 68 )
break;
Decry();
}
if ( v4 == 113 || v4 == 81 )
Exit();
puts("Input fault format!");
v3 = getchar();
putchar(v3);
}
}

跟进 Decry 函数

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
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 = 357761762382LL; // "NDCLS"
v7 = 0LL;
v8 = 0;
v9 = 512969957736LL; // "hadow"
v10 = 0LL;
v11 = 0;
text = (char *)join(key3, &v9); // key3="killshadow"
strcpy(key, key1); // key1="ADSFKNDCLS"
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
printf("Please input your flag:", src);
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= 96 || v1 > 122 )
{
if ( v1 > 64 && v1 <= 90 )
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
else
{
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v12;
}
  • str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97

key与str2的值已知, 则可以爆破v1

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
import string
str2 = "killshadow"
key = "adsfkndcls"
flag = ""
for _ in range(len(key)):
for i in range(128):
if ord(str2[_]) == (i-39-ord(key[_])+97)%26+97:
if chr(i) in string.ascii_uppercase:
flag += chr(i)
print(flag)

实际爆破时, 会出现除了大写字母之外的其他结果, 但是本题的flag为大写字母

flag{KLDQCUDFZO}


Java逆向解密

链接: https://buuoj.cn/challenges#Java逆向解密

Java

jd-gui中反编译结果如下

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
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Scanner;

public class Reverse
{
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
System.out.println("Please input the flag :");
String str = s.next();
System.out.println("Your input is :");
System.out.println(str);
char[] stringArr = str.toCharArray();
Encrypt(stringArr);
}

public static void Encrypt(char[] arr) {
ArrayList Resultlist = new ArrayList();

for (int i = 0; i < arr.length; ++i) {
int result = arr[i] + '@' ^ 0x20;
Resultlist.add(Integer.valueOf(result));
}
int[] KEY = { 180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65 };
ArrayList KEYList = new ArrayList();
for (int j = 0; j < KEY.length; ++j) {
KEYList.add(Integer.valueOf(KEY[j]));
}
System.out.println("Result:");
if (Resultlist.equals(KEYList))
System.out.println("Congratulations!");
else
System.err.println("Error!");
}
}
1
2
3
4
5
6
#!/usr/bin/env python3
key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
flag = ""
for i in range(len(key)):
flag += chr((key[i]-ord('@'))^0x20)
print(flag)

flag{This_is_the_flag_!}


刮开有奖

链接: https://buuoj.cn/challenges#刮开有奖

EXE 32

IDA中 DialogFunc 函数反编译结果如下

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
73
74
75
76
BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
const char *v4; // esi
const char *v5; // edi
int v7; // [esp+8h] [ebp-20030h]
int v8; // [esp+Ch] [ebp-2002Ch]
int v9; // [esp+10h] [ebp-20028h]
int v10; // [esp+14h] [ebp-20024h]
int v11; // [esp+18h] [ebp-20020h]
int v12; // [esp+1Ch] [ebp-2001Ch]
int v13; // [esp+20h] [ebp-20018h]
int v14; // [esp+24h] [ebp-20014h]
int v15; // [esp+28h] [ebp-20010h]
int v16; // [esp+2Ch] [ebp-2000Ch]
int v17; // [esp+30h] [ebp-20008h]
CHAR String; // [esp+34h] [ebp-20004h]
char v19; // [esp+35h] [ebp-20003h]
char v20; // [esp+36h] [ebp-20002h]
char v21; // [esp+37h] [ebp-20001h]
char v22; // [esp+38h] [ebp-20000h]
char v23; // [esp+39h] [ebp-1FFFFh]
char v24; // [esp+3Ah] [ebp-1FFFEh]
char v25; // [esp+3Bh] [ebp-1FFFDh]
char v26; // [esp+10034h] [ebp-10004h]
char v27; // [esp+10035h] [ebp-10003h]
char v28; // [esp+10036h] [ebp-10002h]

if ( a2 == 272 )
return 1;
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 == 1001 )
{
memset(&String, 0, 0xFFFFu);
GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
if ( strlen(&String) == 8 )
{
v7 = 90;
v8 = 74;
v9 = 83;
v10 = 69;
v11 = 67;
v12 = 97;
v13 = 78;
v14 = 72;
v15 = 51;
v16 = 110;
v17 = 103;
sub_4010F0(&v7, 0, 10);
memset(&v26, 0, 0xFFFFu);
v26 = v23;
v28 = v25;
v27 = v24;
v4 = (const char *)sub_401000(&v26, strlen(&v26));
memset(&v26, 0, 0xFFFFu);
v27 = v21;
v26 = v20;
v28 = v22;
v5 = (const char *)sub_401000(&v26, strlen(&v26));
if ( String == v7 + 34
&& v19 == v11
&& 4 * v20 - 141 == 3 * v9
&& v21 / 4 == 2 * (v14 / 9)
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
{
MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
}
}
return 0;
}
if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
return 0;
EndDialog(hDlg, (unsigned __int16)a3);
return 1;
}

v7-v17为数组, String到v25为数组, v26到v28为数组

1
int arr_1 = {90, 74, 83, 69, 67, 97, 78, 72, 51, 110, 103};

跟进 sub_4010F0 函数

代码逻辑有些复杂, 这里可以反编译代码之后修改成C语言代码再运行, 得出arr_1经过函数处理的结果

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

int sub_4010F0(int a1[], int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx

result = a3;
for ( i = a2; i <= a3; a2 = i )
{
v5 = i;
v6 = a1[i];
if ( a2 < result && i < result )
{
do
{
if ( v6 > a1[result] )
{
if ( i >= result )
break;
++i;
a1[v5] = a1[result];
if ( i >= result )
break;
while ( a1[i] <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = i;
a1[result] = a1[i];
}
--result;
}
while ( i < result );
}
LABEL_13:
a1[result] = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}

int main()
{
int i;
int arr_1[] = {90, 74, 83, 69, 67, 97, 78, 72, 51, 110, 103};
sub_4010F0(arr_1, 0, 10);
for(i = 0; i < 11; i++)
{
printf("%d ", arr_1[i]);
}
}

得到的结果为

1
51 67 69 72 74 78 83 90 97 103 110

后续的代码中有对于用户输入的校验

  • String == v7 + 34
  • v19 == v11
  • 4 * v20 - 141 == 3 * v9
  • v21 / 4 == 2 * (v14 / 9)
  • !strcmp(v4, "ak1w")
  • !strcmp(v5, "V1Ax")

  • arr_2[0] == arr_1[0]+34, arr_2[0] == 85
  • arr_2[1] == arr_1[4], arr_2[1] == 74
  • arr_2[2] == (3*arr_1[2]+141)/4, arr_2[2] == 87
  • arr_2[3] == arr_1[7]/9*2*4, arr_2[3] == 80

得出flag前四位为"UJWP"

  • sub_401000(arr_2[5:8]) == "ak1w"
  • sub_401000(arr_2[2:5]) == "V1Ax"

目测是Base64

1
2
3
4
5
echo -n "ak1w" | base64 -d
jMp

echo -n "V1Ax" | base64 -d
WP1

flag{UJWP1jMp}


[GXYCTF2019]luck_guy

链接: https://buuoj.cn/challenges#[GXYCTF2019]luck_guy

EXE 64

IDA中 get_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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
unsigned __int64 get_flag()
{
unsigned int v0; // eax
char v1; // al
signed int i; // [rsp+4h] [rbp-3Ch]
signed int j; // [rsp+8h] [rbp-38h]
unsigned __int64 s; // [rsp+10h] [rbp-30h]
char v6; // [rsp+18h] [rbp-28h]
unsigned __int64 v7; // [rsp+38h] [rbp-8h]

v7 = __readfsqword(0x28u);
v0 = time(0LL);
srand(v0);
for ( i = 0; i <= 4; ++i )
{
switch ( rand() % 200 )
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char *)&s, f1);
strcat((char *)&s, &f2);
printf("%s", &s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
v6 = 0;
s = 0x7F666F6067756369LL;
strcat(&f2, (const char *)&s);
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )
v1 = *(&f2 + j) - 2;
else
v1 = *(&f2 + j) - 1;
*(&f2 + j) = v1;
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
return __readfsqword(0x28u) ^ v7;
}

f2为空字符串, f1="GXY{do_not_"

  • 在case 4中对f2进行拼接字符串, 拼接内容为0x7F666F6067756369LL(小端排序)
  • 在case 5中对f2进行处理
  • 在case 1中将f1, f2进行拼接并输出flag
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
flag = "GXY{do_not_"
f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]
for _ in range(len(f2)):
if _ % 2 == 1:
flag += chr(f2[_]-2);
else:
flag += chr(f2[_]-1);
print(flag)

flag{do_not_hate_me}


findit

链接: https://buuoj.cn/challenges#findit

Android

修改后缀名为zip, 提取classes.dex
使用dex2jar转为jar包
在jd-gui中反编译得到java代码

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
73
74
75
76
77
package com.example.findit;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.Editable;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity
{
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130903064);
paramBundle = (Button)findViewById(2131034173);
EditText localEditText = (EditText)findViewById(2131034174);
TextView localTextView = (TextView)findViewById(2131034175);
paramBundle.setOnClickListener(new View.OnClickListener(new char[] { 84, 104, 105, 115, 73, 115, 84, 104, 101, 70, 108, 97, 103, 72, 111, 109, 101 }, localEditText, new char[] { 112, 118, 107, 113, 123, 109, 49, 54, 52, 54, 55, 53, 50, 54, 50, 48, 51, 51, 108, 52, 109, 52, 57, 108, 110, 112, 55, 112, 57, 109, 110, 107, 50, 56, 107, 55, 53, 125 }, localTextView)
{
public void onClick(View paramView)
{
paramView = new char[17];
char[] arrayOfChar = new char[38];
int i = 0;
if (i >= 17)
{
label12: if (!(String.valueOf(paramView).equals(this.val$edit.getText().toString())))
break label308;
i = 0;
if (i >= 38)
{
label42: paramView = String.valueOf(arrayOfChar);
this.val$text.setText(paramView);
return;
}
}
else
{
if (((this.val$a[i] < 'I') && (this.val$a[i] >= 'A')) || ((this.val$a[i] < 'i') && (this.val$a[i] >= 'a')))
paramView[i] = (char)(this.val$a[i] + '\18');
while (true)
{
i += 1;
break label12:
if (((this.val$a[i] >= 'A') && (this.val$a[i] <= 'Z')) || ((this.val$a[i] >= 'a') && (this.val$a[i] <= 'z')))
paramView[i] = (char)(this.val$a[i] - '\b');
paramView[i] = this.val$a[i];
}
}
if (((this.val$b[i] >= 'A') && (this.val$b[i] <= 'Z')) || ((this.val$b[i] >= 'a') && (this.val$b[i] <= 'z')))
{
arrayOfChar[i] = (char)(this.val$b[i] + '\16');
if (((arrayOfChar[i] > 'Z') && (arrayOfChar[i] < 'a')) || (arrayOfChar[i] >= 'z'))
arrayOfChar[i] = (char)(arrayOfChar[i] - '\26');
}
while (true)
{
i += 1;
break label42:
arrayOfChar[i] = this.val$b[i];
}
label308: this.val$text.setText("答案错了肿么办。。。不给你又不好意思。。。哎呀好纠结啊~~~");
}
});
}

public boolean onOptionsItemSelected(MenuItem paramMenuItem)
{
if (paramMenuItem.getItemId() == 2131034176)
return true;
return super.onOptionsItemSelected(paramMenuItem);
}
}

第一个字符串内容为"ThisIsTheFlagHome"

第二个字符串内容为"pvkq{m164675262033l4m49lnp7p9mnk28k75}"

目测是凯撒加密, 爆破即可得到flag

flag{c164675262033b4c49bdf7f9cda28a75}


简单注册器

链接: https://buuoj.cn/challenges#简单注册器

Android

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
public void onClick(View paramView)
{
int j = 1;
paramView = this.val$editview.getText().toString();
if ((paramView.length() != 32) || (paramView.charAt(31) != 'a') || (paramView.charAt(1) != 'b') || (paramView.charAt(0) + paramView.charAt(2) - 48 != 56))
j = 0;
if (j == 1)
{
paramView = "dd2940c04462b4dd7c450528835cca15".toCharArray();
paramView[2] = (char)(paramView[2] + paramView[3] - 50);
paramView[4] = (char)(paramView[2] + paramView[5] - 48);
paramView[30] = (char)(paramView[31] + paramView[9] - 48);
paramView[14] = (char)(paramView[27] + paramView[28] - 97);
j = 0;
while (true)
{
if (j >= 16)
{
paramView = String.valueOf(paramView);
this.val$textview.setText("flag{" + paramView + "}");
return;
}
int i = paramView[(31 - j)];
paramView[(31 - j)] = paramView[j];
paramView[j] = i;
j += 1;
}
}
this.val$textview.setText("输入注册码错误");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
cipher = []
for _ in "dd2940c04462b4dd7c450528835cca15":
cipher.append(_)
cipher[2] = chr(ord(cipher[2])+ord(cipher[3])-50)
cipher[4] = chr(ord(cipher[2])+ord(cipher[5])-48)
cipher[30] = chr(ord(cipher[31])+ord(cipher[9])-48)
cipher[14] = chr(ord(cipher[27])+ord(cipher[28])-97)
for j in range(16):
i = cipher[(31-j)]
cipher[(31-j)] = cipher[j]
cipher[j] = i
flag = "flag{"
for _ in cipher:
flag += _
flag += "}"
print(flag)

flag{59acc538825054c7de4b26440c0999dd}


[GWCTF 2019]pyre

链接: https://buuoj.cn/challenges#[GWCTF 2019]pyre

Python

使用uncompyle6反编译pyc文件得到源代码

1
2
3
4
5
6
7
8
9
10
11
12
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num

for i in range(l - 1):
code[i] = code[i] ^ code[(i + 1)]

print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
cipher = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
l = len(cipher)
for _ in range(l):
cipher[_] = ord(cipher[_])
for _ in range(l-2, -1, -1):
cipher[_] = cipher[_]^cipher[_+1]
for _ in range(l):
cipher[_] = (cipher[_]-_)%128
flag = ""
for _ in cipher:
flag += chr(_)
print(flag)

flag{Just_Re_1s_Ha66y!}

EOF