BUUCTF Reverse 11-32

[toc]

11. Java逆向解密

附件是一个class文件,用jadx打开

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 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<Integer> Resultlist = new ArrayList<>();
for (char c : arr) {
int result = (c + '@') ^ 32;
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<Integer> KEYList = new ArrayList<>();
for (int i : KEY) {
KEYList.add(Integer.valueOf(i));
}
System.out.println("Result:");
if (Resultlist.equals(KEYList)) {
System.out.println("Congratulations!");
} else {
System.err.println("Error!");
}
}
}

exp

1
2
3
4
5
6
7
8
9
key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
flag = ''
for j in key:
for i in range(31,128):
if((i+ord('@'))^32) == j:
print(i)
flag += chr(i)
break
print(flag)

12. [GXYCTF2019]luck_guy

从main函数跟进到patch_me(4)

image-20221123212837666

跟进get_flag()

image-20221123212915244

case 4中对f2进行赋值,在case 5中对f2进行修改,在case 1中拼接f1和f2,然后输出

image-20221123213016497

exp

1
2
3
4
5
6
7
8
9
10
11
flag='GXY{do_not_'
f2=[0x69,0x63,0x75,0x67,0x60,0x6f,0x66,0x7f]
v1=[]
a = ''
for i in range(8):
if i%2==1:
a = f2[i]-2
else:
a = f2[i]-1
flag+=chr(a)
print(flag)

13. [BJDCTF2020]JustRE

32位

image-20221123213516618

32位

shift+f12查看字符串

image-20221124190841484

替换%d

image-20221124190815343

flag{1999902069a45792d233ac}

14. 刮开有奖

32位

image-20221124190945360

shift+f12查看字符串,跟进

image-20221124200229158

在函数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
INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
const char *v4; // esi
const char *v5; // edi
int v7[2]; // [esp+8h] [ebp-20030h] BYREF
int v8; // [esp+10h] [ebp-20028h]
int v9; // [esp+14h] [ebp-20024h]
int v10; // [esp+18h] [ebp-20020h]
int v11; // [esp+1Ch] [ebp-2001Ch]
int v12; // [esp+20h] [ebp-20018h]
int v13; // [esp+24h] [ebp-20014h]
int v14; // [esp+28h] [ebp-20010h]
int v15; // [esp+2Ch] [ebp-2000Ch]
int v16; // [esp+30h] [ebp-20008h]
CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF
char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF

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[0] = 90;
v7[1] = 74;
v8 = 83;
v9 = 69;
v10 = 67;
v11 = 97;
v12 = 78;
v13 = 72;
v14 = 51;
v15 = 110;
v16 = 103;
sub_4010F0((int)v7, 0, 10);
memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = (const char *)sub_401000(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = (const char *)sub_401000(v18, strlen(v18));
if ( String[0] == v7[0] + 34
&& String[1] == v10
&& 4 * String[2] - 141 == 3 * v8
&& String[3] / 4 == 2 * (v13 / 9)
&& !strcmp(v4, "ak1w") // base64编码
&& !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;
}

x查看引用,main函数中调用了该函数

image-20221124200339778

主要逻辑,其中sub_4010F0为

image-20221124200511436

所以根据if判断反推String,exp瞎写的

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
import base64

v7 = [0,1]
v7[0] = 90
v7[1] = 74
v8 = 83
v9 = 69
v10 = 67
v11 = 97
v12 = 78
v13 = 72
v14 = 51
v15 = 110
v16 = 103

flag = [0,1,2,3,4,5,6,7]
flag[0] = chr(51 + 34) # 排序之后,v7[0]是最小值
flag[1] = chr(74) # 第五个

print(flag)

a = base64.b64decode('V1Ax') # WP1
print(a) # jMp
a = 'jMp'
flag[2] = 'W'
flag[3] = 'P'
flag[4] = '1'
flag[5] = 'j'
flag[6] = 'M'
flag[7] = 'p'


print(flag)
x = ''
for i in flag:
x += str(i)
print(x)

15. 简单注册器

apk包丢入jadx,直接看flag生成部分代码

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class test {
public static void main(String[] args) {
char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
x[2] = (char) ((x[2] + x[3]) - 50);
x[4] = (char) ((x[2] + x[5]) - 48);
x[30] = (char) ((x[31] + x[9]) - 48);
x[14] = (char) ((x[27] + x[28]) - 97);
for (int i = 0; i < 16; i++) {
char a = x[31 - i];
x[31 - i] = x[i];
x[i] = a;
}
String bbb = String.valueOf(x);
System.out.println("flag{" + bbb + "}");

}
}

16. [GWCTF 2019]pyre

python反编译

借助于python反编译在线网站:python反编译 - 在线工具 (tool.lu)

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
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7

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 = [
'%1f',
'%12',
'%1d',
'(',
'0',
'4',
'%01',
'%06',
'%14',
'4',
',',
'%1b',
'U',
'?',
'o',
'6',
'*',
':',
'%01',
'D',
';',
'%',
'%13'
]

exp

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
code = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13'
]
for i in range(len(code)-2,-1,-1):
code[i]=chr(ord(code[i])^ord(code[i+1]))
# print(code)
flag = ''
for i in range(len(code)):
print(ord(code[i])-i)
code[i] = chr((ord(code[i])-i)%128)
flag += code[i]
print(code)
print(flag)

17. [ACTF新生赛2020]easyre(不是很懂)

32位,UPX加壳

image-20221125092109279

upx脱壳,kali里执行

1
upx -d easyre.exe

脱壳后的主函数

image-20221203084930991

其中data_start为

image-20221203084955028

flag是v5,上面的程序将v5的ascii值-1作为data_start的下标,和v4进行对比

所以逆向写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v4 = "*F'\"N,\"(I?+@"
print(len(v4))
# print(hex(ord('~')))

data_str = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(' + "'" + '&%$# !"'
print(len(data_str))
flag = ''
for i in range(12):
print(i)
x = data_str.find(v4[i])+1
print(chr(x))
flag += chr(x)
print(flag)

18. findit

apk包

分析出flag的生成代码

image-20221203111841303

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class test {
public static void main(String[] args) {
final char[] a = {'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'};
final char[] b = {'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'};
char[] y = new char[38];
for (int i2 = 0; i2 < 38; i2++) {
if ((b[i2] >= 'A' && b[i2] <= 'Z') || (b[i2] >= 'a' && b[i2] <= 'z')) {
y[i2] = (char) (b[i2] + 16);
if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
y[i2] = (char) (y[i2] - 26);
}
} else {
y[i2] = b[i2];
}
}
String n = String.valueOf(y);
System.out.println(n);

}
}

19. rsa

公钥n = p * q,其中p和q是两个大素数

e是随机选择的数,作为公钥

d是跟e有关的一个数,满足条件式:ed=1(mod phi(n))

phi(n)是欧拉函数,phi(n)=(p-1)(q-1)

将pub.key拖入RSA公私钥分解 Exponent、Modulus,Rsa公私钥指数、系数(模数)分解–查错网 (chacuo.net)

image-20221203112425701

得到

e = 65537

模数转换为十进制

n = 86934482296048119190666062003494800588905656017203025617216654058378322103517

从n中提取p,q,factordb.com

image-20221203113908435

p=285960468890451637935629440372639283459

q=304008741604601924494328155975272418463

解密脚本

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import gmpy2
import rsa
# 注意文件名字不能和模块名rsa一致
e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phin = (q-1)*(p-1)
d = gmpy2.invert(e, phin)

key = rsa.PrivateKey(n, e, int(d), p, q)

with open("C:\\Users\\xxxxx\\Desktop\\flag.enc", "rb+") as f:
f = f.read()
print(rsa.decrypt(f, key))

报错解决:AttributeError: partially initialized module ‘rsa’ has no attribute ‘PrivateKey’ (most likely due to a circular import)

原因:文件名和rsa重名,修改即可

20. [ACTF新生赛2020]rome

32位

image-20221203145038158

func函数

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
int func()
{
int result; // eax
int v1[4]; // [esp+14h] [ebp-44h]
unsigned __int8 v2; // [esp+24h] [ebp-34h] BYREF
unsigned __int8 v3; // [esp+25h] [ebp-33h]
unsigned __int8 v4; // [esp+26h] [ebp-32h]
unsigned __int8 v5; // [esp+27h] [ebp-31h]
unsigned __int8 v6; // [esp+28h] [ebp-30h]
int v7; // [esp+29h] [ebp-2Fh]
int v8; // [esp+2Dh] [ebp-2Bh]
int v9; // [esp+31h] [ebp-27h]
int v10; // [esp+35h] [ebp-23h]
unsigned __int8 v11; // [esp+39h] [ebp-1Fh]
char v12[29]; // [esp+3Bh] [ebp-1Dh] BYREF

strcpy(v12, "Qsw3sj_lz4_Ujw@l");
printf("Please input:");
scanf("%s", &v2);
result = v2;
if ( v2 == 'A' )
{
result = v3;
if ( v3 == 'C' )
{
result = v4;
if ( v4 == 'T' )
{
result = v5;
if ( v5 == 'F' )
{
result = v6;
if ( v6 == '{' )
{
result = v11;
if ( v11 == '}' )
{
v1[0] = v7;
v1[1] = v8;
v1[2] = v9;
v1[3] = v10;
*(_DWORD *)&v12[17] = 0;
while ( *(int *)&v12[17] <= 15 )
{
if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 64 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 90 )
*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 51) % 26 + 65;
if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 96 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 122 )
*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 79) % 26 + 97;
++*(_DWORD *)&v12[17];
}
*(_DWORD *)&v12[17] = 0;
while ( *(int *)&v12[17] <= 15 )
{
result = (unsigned __int8)v12[*(_DWORD *)&v12[17]];
if ( *((_BYTE *)v1 + *(_DWORD *)&v12[17]) != (_BYTE)result )
return result;
++*(_DWORD *)&v12[17];
}
return printf("You are correct!");
}
}
}
}
}
}
return result;
}

爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v12 = 'Qsw3sj_lz4_Ujw@l'
flag = ''
for i in range(16):
print(i)
for j in range(0,127):
if(j>64 and j<=90):
x = chr((j-51)%26+65)
elif(j>96 and j<=122):
x = chr((j-79)%26+97)
else:
x =chr(j)
if(x == v12[i]):
flag += chr(j)
print(flag)

21. [FlareOn4]login

查看login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE Html />
<html>
<head>
<title>FLARE On 2017</title>
</head>
<body>
<input type="text" name="flag" id="flag" value="Enter the flag" />
<input type="button" id="prompt" value="Click to check the flag" />
<script type="text/javascript">
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}
</script>
</body>
</html>

会对a-zA-Z的字符串进行判断处理

爆破,exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var str1 = 'PyvragFvqrYbtvafNerRnfl@syner-ba.pbz'
var flag = ''
console.log(str1)
for(i=0;i<36;i++){
console.log(i)
for(j=0;j<128;j++){
var a = String.fromCharCode(j)
var rotFlag = a.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if(rotFlag == str1[i]){
flag = flag + a
}
}
}
console.log(flag)

22. CrackRTF

32位

首先输入长度为6的字符串,会在字符串后面拼接@DBApp,将字符串以及对应长度传入sub_40100A函数中

image-20230516202048692

跟进,发现调用了CryptCreateHash函数

image-20230516202245639

查看这个函数

CryptCreateHash 函数启动数据流的哈希。 它创建并返回到调用应用程序,该句柄指向 加密服务提供程序 (CSP) 哈希对象。 此句柄用于后续调用 CryptHashDataCryptHashSessionKey 以哈希会话键和其他数据流。

image-20230516160328912

跟进查看这个ALG_ID,其代表不同的算法,这里代表的是SHA1

image-20230516160352476

因为数字是6位数,且>=100000,所以可以进行爆破

1
2
3
4
5
6
7
8
9
10
11
 # -*- coding:UTF-8 -*-

import hashlib

for i in range(100000,999999):
str1 = str(i) + "@DBApp"
print(i)
a = hashlib.sha1(str1.encode("utf-8")).hexdigest()
if (a == "6E32D0943418C2C33385BC35A1470250DD8923A 9".lower()):
print(str(i)+"DBApp")
break

image-20230516160301908

看第二个password,长度为6,然后拼接,传入sub_401019函数

image-20230516225852970

跟进,发现函数加密函数

image-20230516225940690

根据0x8003u,此处为md5加密,但是没有限制范围,所以没法爆破

image-20230516230032380

继续往下看,将拼接后的字符串传入sub_40100F中,

image-20230516230146963

跟进,发现是从AAA文件取出字符,然后将取出的字符和拼接后的字符串传入sub_401005

image-20230516230356206

跟进,发现是进行了异或处理

image-20230516230513318

利用ResourceHacker工具擦混看AAA文件内容

image-20230516181211636

再理一下逻辑:是把AAA中的字符和拼接后的字符串进行异或,结果为lpBuffer,然后将lpBuffer写入文件dbapp.rtf

image-20230516230736347

随便查看一个rtf文件的内容,前六位是rtf文件的标志位

image-20230516230836866

异或的逆运算也是异或,那么将rtf文件的标志位前六位和AAA文件中的前六位进行异或,得到的结果就是第二个passwd

1
2
3
4
5
6
7
8
9
10
11
str1 = "{\\rtf1"
print(str1)

str2 = [0x05,0x7D,0x41,0x15,0x26,0x01]
print(str2)

flag = ''
for i in range(0,len(str1)):
# print(str1[i])
flag += chr(ord(str1[i])^str2[i])
print(flag)

image-20230516201914273

输入两次passwd之后会生成一个rtf文件,flag就在其中

23. [WUSTCTF2020]level1

给了一个程序以及输出结果,主要逻辑如下

1
2
3
4
5
6
7
8
9
10
11
12
13
  v7 = __readfsqword(0x28u);
flag = fopen("flag", "r");
fread(ptr, 1uLL, 0x14uLL, flag);
fclose(flag);
for ( i = 1; i <= 19; ++i )
{
if ( (i & 1) != 0 )
printf("%ld\n", (unsigned int)(ptr[i] << i));
else
printf("%ld\n", (unsigned int)(i * ptr[i]));
}
return 0;
}

if(i&1) ,在这要说明的是,这个&是二进制位参与运算,末尾开始,奇数二进制末尾是1,偶数是0,也就是说奇数i&1结果为1,偶数则为0。 这个判断语句也可写为if(i&1==1)

<<和>>的意思

<<是左移运算符的意思,左移运算符是用来将一个数的各二进制位全部左移若干位,右补0。高位左移后溢出,舍弃。
例如:
将a的二进制数左移2位,右补0。若a=15,即二进制数00001111,左移2位得00111100,即十进制数60。

语法格式:需要移位的数字 << 移位的次数

例如: 3 << 2,则是将数字3左移2位。即00000011—–>00001100(12);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
arr = []

with open("./re/output.txt","r") as f:
line = f.readline()
while line:
arr.append(int(line))
line = f.readline()
print(arr)

flag = ""
for i in range(1,20):
# print(i)
if(i % 2 != 0):
arr[i-1] = arr[i-1] >> i
else:
arr[i-1] = int(arr[i-1] / i)
print(arr)
for i in range(0,19):
flag += chr(arr[i])
print(flag)

24. [GUET-CTF2019]re

upx加壳,脱壳后

关键函数为if判断里的sub_4009AE

image-20230518084651384

进行字符串判断

image-20230518084739001

写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import re

with open("./re/output.txt","r") as f:
str = f.read()
pattern = re.compile(r'\d+')
nums = pattern.findall(str)

# print(nums)
print(len(nums))
arr = []
for i in range(0,len(nums)):
if(int(nums[i])>10000):
arr.append(int(nums[i]))

flag = ''
for i in range(0,len(arr)):
if(i % 2 != 0):
flag += chr(int(arr[i]/arr[i-1]))
print(flag)

运行结果

image-20230518084533583

但是flag不对,因为程序中没有a1[6],需要进行爆破,最后a1[6]=1

image-20230518084554147

25. [2019红帽杯]easyRE

经过十次base64解码,得到https://bbs.pediy.com/thread-254172.htm

image-20230518153132961

根据string1[i] ^ i) != v15[i],通过爆破,获取string1,

image-20230519003644390

1
2
3
4
5
6
7
8
v15 = "Iodl>Qnb(ocy"+chr(127)+"y.i"+chr(127)+"d`3w}wek9{iy=~yL@EC"
flag = ''
for i in range(len(v15)):
for j in range(31,128):
if(j^i == ord(v15[i])):
flag += chr(j)
print(''.join(flag))
# https://bbs.kanxue.com/thread-254172-4.htm

但是上面得到的网站没啥用

根据这个if判断,查看off_6CC090字符串

image-20230519004030818

接着看到byte_6CC0A0和byte_6CC0A3字符串

image-20230519004102473

跟进sub_400D35函数

v4是一个数组,用HIBYTE取高字节也就是v4的最后一个字节,与byte_6CC0A3异或,判断是否为fg,那么可以猜测这个字符串数组为flag

image-20230519002540835

首先利用flag和v4代表的4个字节异或,获取v4

然后利用v4和byte_6CC0A0的异或,获得flag

1
2
3
4
5
6
7
8
9
10
11
12
13
arr1 = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]

str1 = "flag"
v4 = ''
for i in range(4):
v4 += chr(ord(str1[i])^arr1[i])
print(v4)

str2 = ''
for j in range(25):
str2 += chr(arr1[j] ^ ord(v4[j%4]))

print(str2)

26. [MRCTF2020]Transform

image-20230519193234769

常量那里,注意8 dup(0)代表8个0

image-20230519200837560

1
2
3
4
5
6
7
8
9
10
11
12
index = [0x9, 0x0A, 0x0F, 0x17, 0x7, 0x18, 0x0C, 0x6, 0x1, 0x10, 0x3, 0x11, 0x20, 0x1D, 0x0B, 0x1E, 0x1B, 0x16, 0x4, 0x0D, 0x13, 0x14, 0x15, 0x2, 0x19, 0x5, 0x1F, 0x8, 0x12, 0x1A, 0x1C, 0x0E, 0]

result = [0x67,0x79,0x7B,0x7F,0x75,0x2B,0x3C,0x52,0x53,0x79,0x57,0x5E,0x5D,0x42,0x7B,0x2D,0x2A,0x66,0x42,0x7E,0x4C,0x57,0x79,0x41,0x6B,0x7E,0x65,0x3C,0x5C,0x45,0x6F,0x62,0x4D,0]
arr1 = []
arr2 =[0]*33
for i in range(33):
arr1.append(result[i]^index[i])
arr2[index[i]] = result[i]^index[i]
print(arr2)
for i in arr2:
print(chr(i),end='')
# MRCTF{Tr4nsp0sltiON_Clph3r_1s_3z}

27. [WUSTCTF2020]level2

水题

28. [SUCTF2019]SignIn

主要函数

int mpz_init_set_str (mpz_t rop, char *str, int base)

这三个参数分别是多精度整数变量,字符串,进制

void mpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t mod) [Function]
Set rop to base^exp mod mod.
其实就是计算 base 的 exp 次方,并对 mod 取模,最后将结果写入 rop 中
__gmpz_cmp 比较函数

这里的逻辑是(v6^*v5) mod v4 = v7,而v5,v4,v7已知,求

image-20230519231623838

RSA解密原理:[(12条消息) BUUCTF]REVERSE——rsa_Angel~Yan的博客-CSDN博客

RSA解密脚本:(12条消息) 个人收集的RSA常用脚本_mon0dy的博客-CSDN博客

image-20230519231758106

大整数分解在线网站:factordb.com

image-20230519230022147

解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import gmpy2
import binascii

def Decrypt(c,e,p,q):
L=(p-1)*(q-1)
d=gmpy2.invert(e,L)
n=p*q
m=gmpy2.powmod(c,d,n)
flag=str(m)
print(flag)
if __name__ == '__main__':
# N = p*q
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
e = 65537
# 密文
c = 78510953323073667749065685964447569045476327122134491251061064910992472210485
Decrypt(c,e,p,q)

# 185534734614696481020381637136165435809958101675798337848243069
# binascii进制转换
x = 185534734614696481020381637136165435809958101675798337848243069
print(binascii.unhexlify(hex(x)[2:]).decode(encoding="utf-8"))

29. [ACTF新生赛2020]usualCrypt

32位,输入为v8,sub_401080根据v8生成v5,然后对v5进行判断

image-20230526105150368

跟进sub_401080,该函数主要有三个操作

  1. sub_401000

对base64码表进行字符串交换

  1. base64编码,注意这里的base64码表是修改过的

image-20230526105403493

  1. 最后用sub_401030进行处理

image-20230526105423310

跟进,发现是大小写转换

image-20230526105710689

最后的结果是zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9

所以逆向操作:首先进行大小写转化,而后利用修改后的base64码表进行解码

base64解码参考大佬博客:(22条消息) Base64编码算法(Python实现)_大灬白的博客-CSDN博客

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
result = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'
print(len(result))
str1 = []
for i in range(len(result)):
# print(result[i])
if ord(result[i])>64 and ord(result[i])<91:
str1.append(chr(ord(result[i])+32))
elif ord(result[i])>96 and ord(result[i])<123:
str1.append(chr(ord(result[i])-32))
else:
str1.append(result[i])
print(''.join(str1))
print(ord("a")) # 65 90 97 122


aAbcdefghijklmn = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
# print(len(aAbcdefghijklmn))
for j in range(6,15):
v1 = aAbcdefghijklmn[j+10]
aAbcdefghijklmn[j+10] = aAbcdefghijklmn[j]
aAbcdefghijklmn[j] = v1
# print(''.join(str1))
letters = aAbcdefghijklmn

def decryption(inputString):
# 对前面不是“=”的字节取索引,然后转换为2进制
asciiList = ['{:0>6}'.format(str(bin(letters.index(i))).replace('0b', ''))
for i in inputString if i != '=']
outputString = ''
#补齐“=”的个数
equalNumber = inputString.count('=')
while asciiList:
tempList = asciiList[:4]
#转换成2进制字符串
tempString = ''.join(tempList)
# 对没有8位2进制的字符串补够8位2进制
if len(tempString) % 8 != 0:
tempString = tempString[0:-1*equalNumber*2]
# 4个6字节的二进制 转换 为三个8字节的二进制
tempStringList = [tempString[x:x+8] for x in [0, 8, 16]]
# 二进制转为10进制
tempStringList = [int(x, 2) for x in tempStringList if x]
#连接成字符串
outputString += ''.join([chr(x) for x in tempStringList])
asciiList = asciiList[4:]
#print(output_str)
return outputString
print(decryption(''.join(str1)))

30. [HDCTF2019]Maze

upx脱壳

F5没反应,jnz指令跳转到下一行代码,这里为花指令

image-20230526221044749

将jnz指令给nop掉

方法1:

edit –> Patch program –> change byte修改byte,然后edit –> Patch program –> Apply patches to input file保存修改的文件

方法2:

edit –> Patch program –> Assemble直接输入nop,然后edit –> Patch program –> Apply patches to input file保存修改的文件

重启程序,得主要逻辑

image-20230526230849046

写脚本画出迷宫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
str = '*******+********* ******    ****   ******* **F******    **************'
print(len(str))
for i in range(len(str)):
if (i+1)%10 != 0:
print(str[i],end='')
else:
print(str[i])

# 输出
# 70
# *******+**
# ******* **
# **** **
# ** *****
# ** **F****
# ** ****
# **********
# ssaaasaassddw

参考链接:[【CTF】花指令问题——HDCTF2019]Maze - 掘金 (juejin.cn)

31. [MRCTF2020]Xor

32位

反汇编出错

image-20230527204857814

首先看到将byte_4212C0和%s压入栈中,所以flag其实存储在byte_4212C0中

image-20230527204924244

然后在loc_4010B6中edx自增,并且与1Bh进行比较,大于1Bh就提示Wrong!

image-20230527205856774

如果不大于1Bh,就先和eax异或,然后和byte_41EA80比较,后者为字符串

1
MSAWB~FXZ:J:`tQJ"N@ bpdd}8g

image-20230527205819335

1
2
3
4
5
6
7
# 将字符串与下标异或

str1 = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g'
flag = ''
for i in range(len(str1)):
flag += chr(ord(str1[i])^i)
print(flag)

参考链接:(23条消息) BUUCTF-RE-MRCTF2020Xor_Persistent_s的博客-CSDN博客

32. Youngter-drive

多线程

image-20230527223338486

首先看StartAddress,dword_418008为29,递减。调用了sub_41112C

image-20230527211555531

判断大小写,对于大写字母,Ascii值减38作为off_418000的下标;对于小写字母,Ascii值减96作为off_418000的下标

image-20230527212222668

另一个进程,对dword_418008-1

image-20230527223648595

这两个进程交替运行,最后调用sub_411190()函数,将source和off_418004对比

image-20230527223804673

字符串对比

image-20230527211820798

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
result = 'TOiZiZtOrYaToUwPnToBsOaOapsyS'

off_418000 = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'

flag = ''
for i in range(len(result)):
if(i%2 == 0):
flag += result[i]
else:
if off_418000.index(result[i])+38 < 65:
flag += chr(off_418000.index(result[i])+96)
else:
flag += chr(off_418000.index(result[i])+38)

print(flag)
# ThisisthreadofwindowshahaIsES

但是程序运行结果不能直接作为flag,要再加上一个E,不知道为啥,看了很多大佬的博客也不懂

flag{ThisisthreadofwindowshahaIsESE