BUUCTF-re部分题解

看到有些大佬在做BUUCTF的题,看了一下,题目很多,但是感觉良莠不齐,并且开始的一些题目有些太简单了,就当是多做些题目了。

easyre

确实非常easy,直接拖进IDA看到flag

1
flag{this_Is_a_EaSyRe}

reverse1

IDA打开,通过字符串窗口找到主程序,整个程序流程很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for ( j = 0; ; ++j )
{
v8 = j;
v2 = j_strlen(Str2);
if ( v8 > v2 )
break;
if ( Str2[j] == 'o' )
Str2[j] = '0';
}
sub_1400111D1("input the flag:");
sub_14001128F("%20s", &Str1);
v3 = j_strlen(Str2);
if ( !strncmp(&Str1, Str2, v3) )
sub_1400111D1("this is the right flag!\n");
else
sub_1400111D1("wrong flag\n");

只有这一部分有用,str2时内存中的一个字符串,只是将输入的字符串和变换过后的str2进行一个简单的对比,一样则输出正确

str2的变换就是将所有的o变换成0,str2为‘{hello_world}’,所以flag为

1
flag{hell0_w0rld}

reverse2

和上一题完全一样,只不过时ELF64文件,把i和r全部替换成了1

1
flag{hack1ng_fo1_fun}

helloworld

安卓逆向,直接apktool反编译,在MainActivity.smail文件里找到了flag

1
flag{7631a988259a00816deda84afb29430a}

新年快乐

简单加壳软件,在加壳时没做任何的修改,直接upx脱壳,IDA反编译,通过字符串直接找到flag

1
flag{HappyNewYear!}

内涵的软件

IDA反编译可以直接发现flag,把花括号里的放进flag{}里即可

1
flag{49d3c93df25caad81232130f3d2ebfad}

xor

一看题目就是到要逆运算异或,反编译之后发现关键运算

1
2
3
4
5
for ( i = 1; i < 33; ++i )
v6[i] ^= v6[i - 1];
v3 = global;
if ( !strncmp(v6, global, 0x21uLL) )
printf("Success", v3);

所以逆运算就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
using namespace std;
int main() {
unsigned char ida_chars[] =
{
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
};
string flag;
flag+=ida_chars[0];
for(int i=1;i<33;i++)
{
flag+=(ida_chars[i]^ida_chars[i-1]);
}
cout<<flag<<endl;
return 0;
}

直接输出flag

1
flag{QianQiuWanDai_YiTongJiangHu}

reverse3

和bugku的love是同一个题,不再赘述

不一样的flag

比较简单的的迷宫题,上下左右全部都标示的清清楚楚

不一样的flag-1

迷宫如下图

不一样的flag-2

1
2
3
4
5
*1111
01000
01010
00010
1111#

转换成5*5的方阵,*走到#即可

1
flag{222441144222}

刮开有奖

IDA反编译出来,发现需要输入8位,经过sub_4010F0这个函数的变换后,在经过两个base64变换(查看函数内部自己发现),满足条件即正确

刮开有奖-1

sub_4010F0这个函数内容比较多,但是和输入的字符串无关,所以直接直接把函数实现然后求出来正确的取值就可以了(后面的条件略多,这里的变换实际上只需要第一位和第五位)

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
#include <iostream>
#include <string>

using namespace std;

int __cdecl decrypt(char *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[result] <= 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;
decrypt(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}

char v9[20] = {90, 74, 83, 69, 67, 97, 78, 72, 51, 110, 103};

int main() {
cout << v9 << endl;
decrypt(v9, 0, 10);

cout << v9 << endl;
return 0;
}

输出如图所示

刮开有奖-2

接着分析下面的部分

1
2
3
4
5
6
7
8
9
10
if ( String == v9 + 34         // 第一位等于51+34=85-->'U'
&& v21 == v13 //第2位,等于v13,即sub_4010F0函数返回值的第5位值-->'J'
&& 4 * v22 - 141 == 3 * v11
&& v23 / 4 == 2 * (v16 / 9)
&& !strcmp(v6, "ak1w") // 第6,7,8个字符base64之后,等于ak1w
&& !strcmp(v7,"V1Ax") // 第3,4,5个字符,base64之后等于V1Ax
)
{
MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
}

还多了两个条件就检验正确就可以了

得到flag

1
flag{UJWP1jMp}

SimpleRev

这题没什么难度,IDA打开

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 != 'd' && v4 != 'D' )
break;
Decry();
}
if ( v4 == 'q' || v4 == 'Q' )
Exit();
puts("Input fault format!");
v3 = getchar();
putchar(v3);
}
}

main函数里面没有什么需要注意的东西,解决问题的重点就都放在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
68
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 = 0LL;
v8 = 0;
v9 = 'wodah';
v10 = 0LL;
v11 = 0;
text = join(key3, (const char *)&v9); // text=killshadow
strcpy(key, key1); // key=key1='ADSFK'
strcat(key, src); // key='ADSFKNDCLS'
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > '@' && key[v3 % v5] <= 'Z' )
key[i] = key[v3 % v5] + 32;
++v3;
} // 转换为小写
// key='adsfkndcls'
printf("Please input your flag:", src);
while ( 1 )
{
v1 = getchar();
if ( v1 == '\n' ) // 遇到回车结束
break;
if ( v1 == ' ' ) // 跳过空格
{
++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;
}

需要注意src和v9本身是以long long类型赋值,转换成字符串要记得逆序,接下来的过程就很简单了,程序的过程很清楚,直接逆向运算就可以算出来结果了

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
#include <iostream>
#include <string>

using namespace std;


int main(void) {
int n = 0, v5 = 10, v3 = 10, v2 = 0;
char v1;
char flag[11] = {0};
char key[] = "adsfkndcls";
char text[] = "killshadow";
//通过放缩,j只能取0-3之间
for (int j = 0; j < 4; ++j) {
for (v2 = 0; v2 < 10; ++v2) {
v1 = text[v2] - 97 + 26 * j - 97 + key[v3++ % v5] + 39;
if ((v1 >= 65 && v1 <= 90) || (v1 >= 97 && v1 <= 122)) {
flag[v2] = v1;
if (++n == 10) {
printf("flag{%s}\n", flag);
return 0;
}
}
}
}

return 0;
}

这里的j是用来逆向取余运算时候遍历,放缩之后得到一个范围,然后计算就可以了

1
flag{KLDQCUDFZO}

Java逆向解密

第一次做Java逆向,顺便也熟悉熟悉Java,所以逆向程序也是用Java写的

附件打开是class文件,IDEA直接可以反编译,反编译出来的代码很简单

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

public class Reverse {
public 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<Integer> Resultlist = new ArrayList();

for(int i = 0; i < arr.length; ++i) {
int result = arr[i] + 64 ^ 32;
Resultlist.add(result);
}

int[] KEY = new int[]{180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65};
ArrayList<Integer> KEYList = new ArrayList();

for(int j = 0; j < KEY.length; ++j) {
KEYList.add(KEY[j]);
}

System.out.println("Result:");
if (Resultlist.equals(KEYList)) {
System.out.println("Congratulations!");
} else {
System.err.println("Error!");
}

}
}

把KEY每个值都减去64^32就好了,没什么难度,所以试试用Java写,练练手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.company;

import java.util.ArrayList;

public class Main {

public static void main(String[] args) {
int[] KEY = new int[]{180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65};
ArrayList<Integer> resultList = new ArrayList<>();
for (int value : KEY) {
resultList.add(value - 64 ^ 32);
}
// System.out.println(resultList);
StringBuilder s = new StringBuilder();
for (int value:resultList){
s.append((char)value);
}
System.out.println("flag{"+s+"}");
}
}

直接输出flag

1
flag{This_is_the_flag_!}

findit

不管是apktool反编译还是直接cfr反编译到代码,都可以找到一串很像flag的字符数组

1
pvkq{m164675262033l4m49lnp7p9mnk28k75}

直接凯撒密码解密,a与k之间相差10,所以key=10

1
flag{c164675262033b4c49bdf7f9cda28a75}

rsa

直接解析公钥,然后暴力分解解密就可以了

hgame_wp CGCTF-re部分题解

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×