题目复现

本周做的题

BUU-简单注册器

用jadx打开apk文件

找到MainActivity分析加密方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

using namespace std;

int main() {
char str[] = { 'd','d','2','9','4','0','c','0','4','4','6','2','b','4','d','d','7','c','4','5','0','5','2','8','8','3','5','c','c','a','1','5' };

str[2] = (char)(str[2] + str[3] - 50);
str[4] = (char)(str[2] + str[5] - 48);
str[30] = (char)(str[31] + str[9] - 48);
str[14] = (char)(str[27] + str[28] - 97);

for (int i = 0; i < 16; ++i) {
char temp = str[i];
str[i] = str[31 - i];
str[31 - i] = temp;
}

for (int i=0;i<32;i++) {
cout << str[i];
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
str=['d','d','2','9','4','0','c','0','4','4','6','2','b','4','d','d','7','c','4','5','0','5','2','8','8','3','5','c','c','a','1','5']

str[2]=chr(ord(str[2])+ord(str[3])-50)
str[4]=chr( ord(str[2])+ord(str[5])-48 )
str[30]=chr( ord(str[31])+ord(str[9])-48)
str[14]=chr( ord(str[27])+ord(str[28])-97 )

for i in range(16):
x=str[31-i]
str[31-i]=str[i]
str[i]=x

for i in str:
print (i,end="")

BUU-findit

用jadx打开apk文件

找到MainActivity分析加密方式

需要注意的是,两个if条件,第一个if是说如果b[i2]是AZ或az的字符,y[i2] = b[i2]+16,第二个if条件是说,如果y[i2]符合条件,y[i2]=chr(y[i2]-26),两个if条件后得到的才是flag,else也是flag 。由于str中没有AZ的字符,第一个if条件AZ的可以不写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
str=[ 0x70, 0x76, 0x6b, 0x71, 0x7b, 0x6d, 0x31, 0x36, 0x34, 0x36, 0x37, 0x35, 
0x32, 0x36, 0x32, 0x30, 0x33, 0x33, 0x6c, 0x34, 0x6d, 0x34, 0x39, 0x6c,
0x6e, 0x70, 0x37, 0x70, 0x39, 0x6d, 0x6e, 0x6b, 0x32, 0x38, 0x6b, 0x37,
0x35, 0x7d]
flag=''
for i in str:
if(i >=ord("A") and i<=ord("Z") or i>=ord('a')and i<=ord('z') ):
i+=16
if(i>ord("Z")and i<ord("a")or i>=ord("z")):
flag+=chr(i-26)
else:
flag+=chr(i)
print(flag)

BUU-[GWCTF 2019]pyre

得到的是pyc文件,用在线反编译网站就可以https://www.lddgo.net/string/pyc-compile-decompile

因为:如果 pyc 文件版本 > Python 3.8 ,则只能选择 pycdc 反编译引擎。 pycdc 引擎在某些情况下会反编译失败。
如果 pyc 文件版本 <= Python 3.8 ,推荐使用 uncompyle6 反编译引擎。

简单的加密方式,逆回去就好

num = ((input1[i] + i) % 128 + 128) % 128 可以化为 num ≡ input1[i] + i (mod 128)

因为两次 % 128 的目的是确保结果在 [0, 127] 范围内。

input1[i] ≡ num - i (mod 128)

input1[i] = (num - i) % 128

这里 % 128 确保结果在 [0, 127] 范围内,与字符的 ASCII 码兼容。

  1. num≡input1[i]+i(mod128)

    这意味着:

    num=(input1[i]+i)+128k

    其中 k 是某个整数。这个等式表明 numinput1[i] + i 之间的差值是 128 的倍数。

  2. 变形等式

    为了解出 input1[i],我们需要将等式变形:

    input1[i]≡num−i(mod128)

    这意味着:

    input1[i]=(num−i)+128m

    其中 m 是某个整数。我们希望 input1[i] 在 [0, 127] 的范围内,因此使用模运算来实现这一点。

  3. 模运算

    通过取模 128,我们可以确保结果在 [0, 127] 的范围内:

    input1[i]=(num−i)%128

    这里的 % 运算符表示取余数,确保结果落在 0 到 127 之间。这与字符的 ASCII 码范围兼容,因为标准 ASCII 码的范围就是 0 到 127。

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

BUU-[FlareOn4]login

得到的是html,打开后查看网页源代码

进行分析:这里有一个三元运算符:(c <= “Z” ? 90 : 122) >= (c = c.charCodeAt(0) +13) ? c : c -26。这里的c是字符,首先判断c是否是小于等于Z的,也就是大写字母的话,上限是90(Z的ASCII码),否则是小写字母,上限是122(z的ASCII码)。然后比较这个上限是否大于等于原字符的ASCII码加上13后的值。如果满足,就直接用原字符加13;否则,减去26(字母表长度)。例如,第一个字符P:大写字母,ASCII码80。80-13=67,也就是C。再例如字符是N(ASCII码78),大写字母。加13后是91,超过了90,所以需要减去26,得到65,也就是A。这个是凯撒密码,key为13

BUU-[WUSTCTF2020]level1

用64位IDA打开

文件里的数据为加密后的,应该将加密方式逆过来得到加密前的数据是flag

1
2
3
4
5
6
7
8
9
10
11
str=[198,232,816,200,1536,300,6144,984,51200,570,92160,1200,
565248,756,1474560,800,6291456,1782,65536000]
flag=''
for i in range(len(str)):
if ((i+1)&1!=0):
flag+=chr(str[i]>>(i+1))
else:
flag+=chr(str[i] // (i+1))
print(flag)

#ctf2020{d9-dE6-20c}
1
2
3
4
5
6
7
str = [0, 198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570, 92160, 1200, 565248,
756, 1474560, 800, 6291456, 1782, 65536000]
for i in range(1, 20): # i 是从 1 开始的
if i % 2 == 1:
print(chr(str[i] >> i), end='')
else:
print(chr(str[i] // i), end='')

因为读取了20个字节,但是文本文件里只有19个,for循环是从1到19,没有使用第零位的数据,第零位的数据可以是任意值,这里就习惯写成0,这样的话,解密脚本就不用i-1了

BUU-[WUSTCTF2020]level2

拿到后先查壳,发现了upx壳,脱完壳后用IDA32位打开,这道题开门见山呐

BUU-rsa

这是一道RSA的题

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

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

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

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

得到两个文件,flag.enc打不开,pub.key打开查看后发现是加密后的公钥,根据题目可推断出

pub.key是公钥,flag.enc是rsa加密后的文件,因此我们只要通过公钥文件解析出n,e,p,q,d,再利用脚本解密rsa加密文件。

使用在线网站进行公钥解析:http://tool.chacuo.net/cryptrsakeyparse

可以获取到:

e = 65537

n=86934482296048119190666062003494800588905656017203025617216654058378322103517(模数转换为十进制)

然后使用RSA因数分解工具yafu将n进行分解,输入命令

yafu-x64 factor(86934482296048119190666062003494800588905656017203025617216654058378322103517)

yafu工具的安装与使用教程:https://blog.csdn.net/dchua123/article/details/105444230

p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import gmpy2
import 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(r"E:\re\output\flag.enc", "rb") as f:
encrypted_data = f.read()
print(rsa.decrypt(encrypted_data, key))

flag{decrypt_256}

BUU-CrackRTF

查看加密函数发现是哈希函数,使用在线网站解密 https://www.somd5.com/

蓝色光标部分分别是第一个密码和第二个密码,直接运行输入这两个密码,然后就会自动生成一个文件,里面放着flag

Flag{N0_M0re_Free_Bugs}

BUU-[MRCTF2020]Transform

需要注意的是在逆向解密时,要注意先异或赋值给dword_40F040,再进行下一步时,Str[dword_40F040]里的dword_40F040还是原来的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
data = [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]
list = [0x09, 0x0A, 0x0F, 0x17, 0x07,
0x18, 0x0C, 0x06, 0x01, 0x10,
0x03, 0x11, 0x20, 0x1D, 0x0B,
0x1E, 0x1B, 0x16, 0x04, 0x0D,
0x13, 0x14, 0x15, 0x02, 0x19,
0x05, 0x1F, 0x08, 0x12, 0x1A,
0x1C, 0x0E,0x00]
m = []
c = [0]*33
flag = ''
for i in range(33):
m.append(data[i]^list[i])
for i in range(33):
c[list[i]] = m[i]
for i in range(33):
flag += chr(c[i])
print(flag)

MRCTF{Tr4nsp0sltiON_Clph3r_1s_3z}

NSS-[HNCTF 2022 WEEK3]Double

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
pipe(pipedes);
if ( fork() )
{
puts("i'm parent");
close(pipedes[1]);
for ( i = 0; i <= 29; ++i )
{
read(pipedes[0], &buf, 1uLL);
v9 = i ^ buf;
if ( arr[i ^ buf] != enc[i] )
{
puts("error!");
exit(0);
}
}
puts("you are right!");
close(pipedes[0]);
return 0;
}
else
{
puts("i am child");
close(pipedes[0]);
puts("please input your flag!");
__isoc99_scanf("%s", s);
for ( j = 0; j < strlen(s); ++j )
{
v8 = j;
write(pipedes[1], &s[j], 1uLL);
}
close(pipedes[1]);
return 0;

对这段代码的解释如下:

这段代码是一个使用管道进行父子进程通信的程序,主要用于验证用户输入的字符串(flag)是否正确。

pipe(pipedes) 创建了一个管道,pipedes[0] 是读端,pipedes[1] 是写端。

fork()函数用于创建一个新的进程,新创建的进程被称为子进程,而调用fork()的进程被称为父进程

fork()返回新创建的子进程的PID(进程标识符),这是一个正整数。因此,如果fork()的返回值大于0,那么当前进程是父进程。fork()返回0。因此,如果fork()的返回值等于0,那么当前进程是子进程。

父进程执行 if 分支,子进程执行 else 分支。

父进程逻辑

  • 输出提示信息 i'm parent
  • 关闭管道的写端 pipedes[1](因为父进程只需读取数据)。
  • 循环 30 次(i 从 0 到 29),每次从管道读一个字符到 buf
  • 计算 v9 = i ^ buf(将当前循环索引 i 与读取的字符 buf 异或)。
  • 检查预定义数组 arr[v9] 是否等于另一个数组 enc[i]。若不等,输出错误并退出。
  • 若所有字符都通过验证,输出 you are right!

子进程逻辑

  • 输出提示信息 i am child
  • 关闭管道的读端 pipedes[0](因为子进程只需写入数据)。
  • 通过 scanf 获取用户输入的字符串 s
  • 将字符串 s 的每个字符逐个写入管道的写端 pipedes[1]

验证逻辑

  • 用户输入的每个字符 s[j] 会被父进程按顺序读取。
  • 父进程通过异或操作 i ^ s[i] 生成索引 v9,检查 arr[v9] 是否等于 enc[i]
  • 最终,只有满足所有 arr[i ^ s[i]] == enc[i] 的输入才会被判定为正确。

逆向关键:

简单来看就是i与s[i]异或得到新的下标,arr[v9]=enc[i];只要找到arr[]和enc[],并找到他们都相等时的下标再进行异或,就可以得到输入的flag。

先找到enc[]和arr[]

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
enc = [0x1FAC, 0x4F91, 0x3796, 0xB584, 0xE18, 0xC1E2, 0x7370, 0x1FAC, 0xA880, 0xB8F1, 0x233B, 0x7370, 0x27B8,
0x4F91, 0xEB08, 0x8BAC, 0x5900, 0x3081, 0x4E1A, 0x599D, 0x5BE3, 0x5C49, 0xF53B, 0xFFDA, 0xBA6F, 0x3E5D,
0x27B8, 0x5B51, 0x8A30, 0x2A10]

arr = [0x00003C0E, 0x0000C68C, 0x00004EE7, 0x00007BD6, 0x0000C318, 0x0000CF83, 0x0000EB1D, 0x0000304F, 0x0000FF00,
0x00002C3A, 0x0000666D, 0x00006798, 0x0000D015, 0x00001E56, 0x0000562A, 0x00008A81, 0x00005C95, 0x000078A0,
0x000060ED, 0x00001114, 0x0000ADDB, 0x0000732C, 0x00005190, 0x00001135, 0x0000E353, 0x0000E9C9, 0x00000AAF,
0x00002818, 0x00002636, 0x00009B26, 0x00003D09, 0x000018BF, 0x00002A64, 0x00004F3D, 0x0000AE5F, 0x00004E1A,
0x0000496A, 0x0000DB84, 0x000024C3, 0x0000FFDA, 0x0000378B, 0x00001F5E, 0x0000D071, 0x00008C71, 0x0000062E,
0x0000D6D9, 0x00008F74, 0x0000E856, 0x0000EA45, 0x0000BEC4, 0x00000486, 0x0000F140, 0x0000729A, 0x00007FFD,
0x0000AFED, 0x00005F38, 0x000006FC, 0x00004BBD, 0x00003322, 0x000064DE, 0x0000458F, 0x00008A30, 0x00007514,
0x00008BAC, 0x0000B584, 0x0000B8F1, 0x000072BC, 0x0000C1E2, 0x0000B0B0, 0x00005C49, 0x0000ABBF, 0x0000539B,
0x0000DBD0, 0x00000DAC, 0x0000EB08, 0x00005BE3, 0x00003B32, 0x0000D535, 0x00001FAC, 0x0000FB63, 0x00000E18,
0x00003796, 0x00004F91, 0x00006644, 0x000097A8, 0x00000E06, 0x0000FB99, 0x0000A880, 0x0000C982, 0x0000889B,
0x00004F89, 0x00003FE4, 0x0000EE7E, 0x00000BE7, 0x00008ACD, 0x00003208, 0x00002A10, 0x00006332, 0x00002AD6,
0x000003D0, 0x0000F53B, 0x00005900, 0x0000016E, 0x0000F928, 0x00005B51, 0x000027B8, 0x0000BEEF, 0x0000233B,
0x0000017E, 0x000063F0, 0x0000C025, 0x0000E51D, 0x00003D44, 0x00006F36, 0x000016F9, 0x00003081, 0x0000705F,
0x0000B776, 0x0000599D, 0x00004EDC, 0x00006557, 0x0000BE16, 0x00008F0E, 0x0000BA6F, 0x00003E5D, 0x00007370,
0x00001746, 0x00006C0C, 0x0000712B, 0x00005CBB, 0x00006359, 0x00008CAF, 0x00004ED7, 0x0000AEC8, 0x0000FBA7,
0x000074BD, 0x0000E3B1, 0x00005D37, 0x00004D4E, 0x00008104, 0x0000B410, 0x00008656, 0x00002176, 0x000023BB,
0x0000245E, 0x0000A92E, 0x0000AD1A, 0x0000E530, 0x0000D77C, 0x0000E043, 0x00009116, 0x0000EDDC, 0x0000AB12,
0x00000D67, 0x00007685, 0x00003CB9, 0x0000BFCE, 0x00005A2B, 0x000039F9, 0x0000908B, 0x0000FE3E, 0x0000BD18,
0x0000DB54, 0x00000CAB, 0x00003C56, 0x0000FE73, 0x0000D974, 0x00000F08, 0x00005B88, 0x0000A0F2, 0x00003D88,
0x00009DE4, 0x00000935, 0x000052B4, 0x0000A340, 0x0000EA88, 0x0000BE72, 0x00006DCE, 0x00006A2B, 0x00003146,
0x00000358, 0x00000F4F, 0x0000FA60, 0x000025EB, 0x0000DAC7, 0x0000076A, 0x00003D67, 0x000043F0, 0x00009F9C,
0x00005B66, 0x00007163, 0x00008F3B, 0x00007EBB, 0x000005D1, 0x000062C4, 0x00009F95, 0x00001E06, 0x00005D58,
0x0000E984, 0x000075B3, 0x00000D5F, 0x0000EE58, 0x00002390, 0x0000FB91, 0x000028AA, 0x000087DD, 0x0000F5EA,
0x0000443C, 0x00006742, 0x00001999, 0x000088E9, 0x0000FD0E, 0x0000C8BD, 0x000055F8, 0x0000BB09, 0x00006C10,
0x00008068, 0x0000CDD4, 0x000029A6, 0x0000DD9F, 0x0000CEC3, 0x00006217, 0x0000BE28, 0x00003E7A, 0x0000E71E,
0x0000C573, 0x0000042B, 0x0000DE06, 0x0000C934, 0x000035D1, 0x0000EF49, 0x000063A3, 0x0000F08F, 0x000026E1,
0x0000E61E, 0x00002710, 0x0000B6B3, 0x000010E0, 0x0000BD36, 0x0000499C, 0x00008446, 0x0000B614, 0x0000E921,
0x0000DB2D, 0x00004AB8, 0x00004C8B, 0x0000D1A8, 0x00006A9B, 0x0000D817, 0x0000F349, 0x0000CE92, 0x00007F8D,
0x00004C66, 0x0000CF40, 0x00009169, 0x00000000]
for i in range(len(enc)):
for j in range(len(arr)):
if arr[j]==enc[i]:
print(chr(j^i),end="")

NSSCTF{I_Have_D0ub1e_Pr0cess!}