Week 1

easy_RE

打开就是flag

upx -d 解开后每个字符-1就得到flag

Segments

shift + f7

直接看到flag【自己拼接一下】

ELF

首先一个简单的xor 然后是一个base64

在线网站首先解开base64 然后再自己写py解开encode

image-20231011205803896

1
2
3
4
5
6
7
enc = "V\QWkt $_e'^_ggXQ'u|v!c/m"

flag = ""
for i in enc:
flag += chr((ord(i) - 16) ^ 0x20)
print(flag)

Endian

一个简单的异或,然后16进制转字符串的时候发现是小端序。改下顺序就好了

AndroXor

用jadx,找到后,就是一个简单的xor

1
2
3
4
5
6
7
8
enc = [14, b'\r', 17, 23, 2, b'K', b'I', b'7', b' ', 30, 20, b'I', b'\n', 2, b'\f', b'>', b'(', b'@', 11, b'\'', b'K', b'Y', 25, b'A', b'\r']
xor = b'happyx3'
for i in range(len(enc)):
if type(enc[i]) == bytes:
enc[i] = ord(enc[i])
flag = [enc[i]^xor[i%7] for i in range(len(enc))]
print(bytes(flag))
# flag{3z_And0r1d_X0r_x1x1}

EzPE

修改一下DOS头

image-20231011213522860

1
2
3
4
5
6
7
8
enc = [ 0x0A, 0x0C, 0x04, 0x1F, 0x26, 0x6C, 0x43, 0x2D, 0x3C, 0x0C,
0x54, 0x4C, 0x24, 0x25, 0x11, 0x06, 0x05, 0x3A, 0x7C, 0x51,
0x38, 0x1A, 0x03, 0x0D, 0x01, 0x36, 0x1F, 0x12, 0x26, 0x04,
0x68, 0x5D, 0x3F, 0x2D, 0x37, 0x2A, 0x7D]

for i in range(len(enc)-1,0,-1):
enc[i-1] ^= enc[i]^(i-1)
print(bytes(enc))

lazy_activity

直接搜索flag{

就找到了

Week 2

PZthon

python打包成的exe。用pyinstxtractor解开是一个pyc文件。然后就是一个简答的xor。

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
enc = [
115,
121,
116,
114,
110,
76,
37,
96,
88,
116,
113,
112,
36,
97,
65,
125,
103,
37,
96,
114,
125,
65,
39,
112,
70,
112,
118,
37,
123,
113,
69,
79,
82,
84,
89,
84,
77,
76,
36,
112,
99,
112,
36,
65,
39,
116,
97,
36,
102,
86,
37,
37,
36,
104]

flag = ""
for i in enc:
flag += chr(i ^ 21)

print(flag)
#flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}

AndroGenshin

用jadx打开找到“MainActivity”很容易的看到是一个rc4后的base64。并且使用的是一个rc4加密的后的base64的表单。

所以解密比较简单。首先得到base64的表单。然后再base64换表,后解密。

image-20231023193438404

1
2
3
4
5
6
7
8
9
10
11
12
import base64
import string

str1 = "YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1=" # 需要换表的字符串

string1 = "BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqtsvuxwzy1032547698/+" #IDA中看到的表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" #IDA中看到的表
c = str.maketrans(string1,string2)
print(str1.translate(c))#只进行换表

print(base64.b64decode(str1.translate(str.maketrans(string1,string2))))#附带解密
#b'flag{0h_RC4_w1th_Base64!!}'

SMC

image-20231023194124553

上来就看到VirtualProtect 。

下面有一个反调试。然后是一个解密的函数。然后再是调用函数。

思路1:动调调试,绕过反调试。然后运行解密函数,后停下来,让IDA重新去分析函数。

image-20231023200442748

这里修改一下zf标志位。【绕过反调试】

image-20231023200541076

当我们运行过解密函数后,就已经得到了正确的函数了。走到403040这个函数的时候F7进去。

按下“P”然后F5:

就得到了正确的函数。

image-20231023200713499

思路2:

用IDApython实现解密函数。

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
import idaapi
import idc

def decrypt_data():
# 定义byte_403068和sub_403040的地址
byte_403068_address = 0x403068
sub_403040_address = 0x403040
data_size = 38 # 数据大小,根据实际情况修改

# 遍历数据进行解密
for i in range(data_size):
# 从byte_403068读取一个字节
result = idc.get_wide_byte(byte_403068_address + (i % 4))

# 从sub_403040读取一个字节
sub_403040_byte = idc.get_wide_byte(sub_403040_address + i)

# 对sub_403040的字节进行异或操作
decrypted_byte = sub_403040_byte ^ result

# 将解密后的字节写回到sub_403040
idaapi.patch_byte(sub_403040_address + i, decrypted_byte)

print("Decryption completed")
print("OK") # 添加这一行以在完成后打印"OK"

# 执行解密函数
if __name__ == "__main__":
decrypt_data()

image-20231023200904131

一样能得到正确的函数。

然后就是有一个简单的解密了

1
2
3
4
s=[0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71]
for i in range(len(s)):
print(chr(s[i]-5^0x11),end="")# ^号运算符优先级低于减号
#flag{SMC_1S_1nt3r3sting!!R1ght?}

Petals

这个是一个jnz和jz组合而成的花指令。

找到位置后,讲jnz和jz下面的call指令的第一个字节改成90。然后就能看加密的函数了。

image-20231023202847897

这里主要就是:*(_BYTE *)(j + a1) = *((_BYTE *)v5 + *(unsigned __int8 *)(j + a1));

我们知道a1 = 0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89,
0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1,
0xD2, 0x82, 0xD3, 0xDE, 0x87

这句话的意思就是说flag = v5[a1[j] % 256];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enc = [0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89,
0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1,
0xD2, 0x82, 0xD3, 0xDE, 0x87]

v5 = [0] * 256
for i in range(256):
v5[i] = (~(i ^ 25)) & 0xff
#print(v5)
flag = ""
for i in range(len(enc)):
temp = (enc[i]) % 256
flag += chr(v5[temp])
print(flag)
#66ccff#luotianyi#b074d58a

然后是一个md5

C?C++?

用dnSpy反编译C#

加密大概就是这样的,然后就是反着写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
array = [68,75,66,72,99,19,19,78,83,74,91,86,
35,39,77,85,44,89,47,92,49,88,48,91,
88,102,105,51,76,115,-124,125,79,122,-103]
text2 = "NEWSTAR"
for i in range(7):
array[i + 28] -= (ord(text2[i]) // 5) + ord('\n')
array[i + 21] -= i ^ 2
array[i + 14] -= 2*i
array[i + 7] -=ord(text2[i]) % 5
array[i] -= i ^ -(ord(text2[i]) % 4)

for i in range(35):
array[i] -= i
array[i] += ord(' ')

flag = ""
for i in array:
flag += chr(i % 256)
print(flag)
#flag{45dg_ng78_d8b5_1a7d_gh47_kd5b}

R4ndom

这个题是一个伪随机【rand】

image-20231024150047832

简单的看,就是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
# 定义数据
s2 = [
0x3513AB8AB2D7E6EE,
0x2EEDBA9CB9C97B02,
0x16E4F8C8EEFA4FBD,
0x383014F4983B6382,
0xEA32360C3D843607,
0xA655
]

# 循环打印数据
for value in s2:
# 将数据转换为小端序
le_value = value.to_bytes(8, byteorder='little')

# 将小端序的字节转换为16进制字符串并切割成两位一组
hex_str = '0x' + ', 0x'.join(['{:02X}'.format(byte) for byte in le_value])

print(hex_str)
#0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35
#0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E
#0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16
#0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38
#0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA
#0x55, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

image-20231024161248087

主要就是这句话:(16 * ((unsigned __int8)(v3 + v4 % 255) >> 4) + 15) & (unsigned __int8)(v3 + v4 % 255)

如何得到v3的值。

最后借用了官方Wp:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__uint8_t Table[256] = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
int main(){
srand(1400333646);
__uint8_t enc[42] = { 0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E, 0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38, 0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6};
for (int i = 0; i < 42; ++i)
{ for (int j = 0; j < 256; ++j)
{ if (Table[j] == enc[i])
{ printf("%c", (j - rand() % 255)); } } }
return 0;}

image-20231024160809018

easy_enc

这个题,简单的爆破就好了。

如下是我看了Wp,然后自己写的一些解释。

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
uint8_t my_uint8_variable;
int main() {
srand(1400333646);
uint8_t enc[100] = { 0xE8, 0x80, 0x84, 0x8, 0x18, 0x3C, 0x78, 0x68, 0x0, 0x70,
0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8, 0xC, 0x1C, 0x90,
0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30 };

char key[] = "NewStarCTF";
for (int i = 0; i < 29; i++)//flag 有29个字符
{
for (uint8_t j = 32; j <= 127; j++)//爆破
{
uint8_t temp = j;
if (j >= 'A' && j <= 'Z')
{
j = (j - 52) % 26 + 65;
}
else if (j >= '0' && j <= '9')
{
j = (j - 45) % 10 + 48;
}
else if (j >= 'a' && j <= 'z')
{
j = (j - 89) % 26 + 97;
}
j += key[i % 10];
j = ~j;
j *= 52;
if (j == enc[i])
{
if (temp >= 'A' && temp <= 'Z' || temp >= 'a' && temp <= 'z')
{
printf("%c", temp);
}
}
j = temp;//让j能正确的遍历从32到127。中间的j进行了变换。


}


}
return 0;
}

//ruteForceIsAGoodwaytoGetFlag

AndroDbgMe

一看题目就知道要dbg它。

我们这里用官方的wp解一次,因为之前没遇到过,所以我就详细的写。

首先将apk和apktools放在一起。

image-20231024210217160

APKtools解包

java -jar apktool_2.9.0.jar d AndroDbgme.apk

image-20231024210513622

得到AndroDbgme 文件夹。

打开里面的xml文件。

添加:android:debuggable="true"

image-20231024210658065

重新打包,并且重新命名

java -jar apktool_2.9.0.jar b AndroDbgme -o AndroDbgme_unsigned.apk

image-20231024210857231

得到:AndroDbgme_unsigned.apk这个apk文件。

对文件进行对齐:

zipalign -p -f -v 4 AndroDbgme.apk AndroDbgme_unsigned.apk

image-20231024211101502

生成keystore

keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore

image-20231024211340159

口令:123456。

得到了abc.keystore

签名:

jarsigner -verbose -keystore abc.keystore -signedjar AndroDbgme_unsigned_1.apk AndroDbgme_unsigned.apk abc.keystore

image-20231024211725816

错误了

尝试一下:

apksigner sign --ks abc.keystore AndroDbgme_unsigned.apk

image-20231024212010293

这样就是可以了的。

动态调试

打开用jeb打开AndroDbgme_unsigned.apk。并且将这个文件安装到雷电模拟器中【要给root权限】,然后

image-20231024223459241

之间debugger是找不到这个文件的。

image-20231024223627032

打开这个文件后就能找到了。然后点击attach

image-20231024223704030

就得到了flag

Week 3

这个就是一个比较简单的永恒跳转的jnz和jz

找到位置把下面的call的第一个字节nop掉。然后‘c’ ‘p’就能F5了

image-20231031165919862

然后就是一个RC4

image-20231031165942393

STL

pyexe

首先用了工具:“Skipping pyz extraction”

image-20231031210733178

我们用相同版本的python来尝试一下:python3.8【用的主机】

image-20231031210917031

报错了如上。

但是也生成了这个文件夹

image-20231031210947924

然后将pycdc放在这个文件夹里面后:

image-20231031211053279

【为什么我上面的路劲不一样,是因为我将它copy到了虚拟机里面】

得到key=‘00000000new1star'

然后用网上的脚本fix:我将他保存到了1.py里面

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

import glob
import zlib
import tinyaes
from pathlib import Path

CRYPT_BLOCK_SIZE = 16

# key obtained from pyimod00_crypto_key
key = bytes('00000000new1star', 'utf-8')

for p in Path("./fakekey.exe_extracted/PYZ-00.pyz_extracted").glob("**/*.pyc.encrypted"):
inf = open(p, 'rb') # encrypted file input
outf = open(p.with_name(p.stem), 'wb') # output file

# Initialization vector
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = tinyaes.AES(key, iv)

# Decrypt and decompress
plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read()))

# Write pyc header
# The header below is for Python 3.8
outf.write(b'\x55\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0')

# Write decrypted data
outf.write(plaintext)

inf.close()
outf.close()

# Delete .pyc.encrypted file
p.unlink()
"""
Python 2.7: \x03\xf3\x0d\x0a\0\0\0\0
Python 3.0: \x3b\x0c\x0d\x0a\0\0\0\0
Python 3.1: \x4f\x0c\x0d\x0a\0\0\0\0
Python 3.2: \x6c\x0c\x0d\x0a\0\0\0\0
Python 3.3: \x9e\x0c\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.4: \xee\x0c\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.5: \x17\x0d\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.6: \x33\x0d\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.7: \x42\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.8: \x55\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.9: \x61\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.10: \x6f\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
"""

image-20231031211642122

这里兜兜转转了好久好久,全是因为python版本的问题。【感觉是电脑有缓存,就很莫名其妙。重启一下虚拟机就好了】,我上面贴的图是在主机里面实现的,我在虚拟机里面安装好了python的版本,重启机子后也成功了。

现在来看代码来逆向:

image-20231031223437088

这里就知道了base64

还有一个from setting import key

image-20231031223634493

key == b'new_star'

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
#最后抄了一个wp:我大致都理解了,但是不知道为什么有个md5 ==

import base64
import hashlib
def rc4(plaintext):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# 生成密钥流
i = j = 0
keystream = []
for _ in range(len(plaintext)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
keystream.append(k)
ciphertext = []
for i in range(len(plaintext)):
ciphertext.append(ord(plaintext[i]) ^ keystream[i] ^ 5)
return ciphertext
def decode2(encoded_str):
decoded_str = base64.b64decode(encoded_str).decode()
return [ord(t) for t in decoded_str]
def decode(data):
for a in range(256):
for b in range(256):
tmp_list = data[:5]+ [a] +data[5:-2]+ [ b,data[-2],data[-1]] #拼接还原
string_tmp = "".join([chr(t) for t in tmp_list])
flag = "".join([chr(t) for t in rc4(string_tmp)])
if hashlib.md5(flag.encode()).hexdigest()[:6] == "cbd746":
print(flag)
a = b'IMKJw4jCkgQxw6A1w5QRw7A5SG14wobDs8KF'
key = b'new_star'
decode(decode2(a))
# flag{no_ke1_no_fuN!}