venom2025_闻花识女人

去花

新手时复现花指令很少见师傅放源码,其实对比观察源码就很清楚了,本质就是去除多余opcode,亲自动手写一遍再逆向感觉是完全不一样的。

源码如下

第三处

类似smc吧,一开始想整活但嫌麻烦,先加密再去加的花,所以不做太大改动,原理就是静态时是E9 jmp指令,运行后xor成5个nop,不影响程序流执行

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
static inline void* page_align(void *addr) {
size_t page_size = getpagesize();
return (void*)((uintptr_t)addr & ~(page_size - 1));
}

void flower_with_addr(void *junk_addr) {
void *page = page_align(junk_addr);
size_t page_size = getpagesize();

if (mprotect(page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
perror("mprotect");
return;
}

uint8_t key[] = {0x79, 0x81, 0xd5, 0x84, 0x89};
for (int i = 0; i < 5; i++) {
((uint8_t*)junk_addr)[i] ^= key[i]; // -> 0x90 each
}

mprotect(page, page_size, PROT_READ | PROT_EXEC);
}

void *junk_addr = &&junk_label;
flower_with_addr(junk_addr);
junk_label:
__asm__ volatile (
".byte 0xe9 \n\t"
".byte 0x11 \n\t"
".byte 0x45 \n\t"
".byte 0x14 \n\t"
".byte 0x19 \n\t"
::: "memory"
);

第一处

标准jz/jnz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__asm__ volatile (
"pushq %%rbx \n\t"
"xorq %%rbx, %%rbx \n\t" //ida 识别$1 $1+1
"testq %%rbx, %%rbx \n\t"
"jnz 1f \n\t"
"jz 2f \n\t"

"1: \n\t"
".byte 0xe9 \n\t"

"2: \n\t"
"popq %%rbx \n\t"
:
:
: "rbx", "memory"
);

第二处

call+retn,rsp具体加的值根据opcode计算其实很明显

1
2
3
4
5
6
7
8
9
10
11
12
__asm__ volatile (
"call 1f \n\t"
".byte 0x83 \n\t"

"1: \n\t"
"addq $8, (%%rsp) \n\t"
"ret \n\t"
".byte 0xf3 \n\t"
:
:
: "memory"
);

解密

salsa20+aes_ecb无魔改

中间加了简单的倒序xor处理去除一些内容特征

eg.cyber_chef

eg.code

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
import binascii
import struct
from Crypto.Cipher import AES,Salsa20

#aes_dec
# enc = [
# 0xc9, 0xcf, 0xce, 0xc9, 0xce, 0xcb, 0x92, 0xcb, 0xc9, 0x99, 0x9f, 0xc9, 0x9f, 0xcb, 0xc9, 0x93,
# 0xcc, 0xc9, 0x9d, 0x9e, 0xce, 0x93, 0x9b, 0x92, 0xc9, 0x99, 0x9a, 0x9d, 0x9d, 0x99, 0x98, 0x9f,
# 0x99, 0x9c, 0x9c, 0xce, 0x9b, 0xcb, 0x93, 0x99, 0xcf, 0xce, 0x9b, 0xcc, 0xcf, 0xcb, 0x99, 0x99,
# 0x98, 0x9f, 0x9c, 0x9f, 0x9f, 0xc8, 0x99, 0x99, 0x98, 0xc8, 0xc8, 0x93, 0x9a, 0xcc, 0x93, 0xcf,
# 0xcf, 0x9b, 0x99, 0x9f, 0x93, 0x9b, 0x93, 0xce, 0x93, 0xcc, 0x9f, 0xcc, 0x92, 0x92, 0x9d, 0xce,
# 0xcb, 0xc9, 0x93, 0x93, 0x9b, 0x9d, 0x93, 0xc8, 0x9d, 0x9b, 0xcf, 0x93, 0xc9, 0xc9, 0x93, 0x9f
# ]
# hoge=bytes(b ^ 0xAA for b in enc[::-1])
# print(hoge)
# b'59cc9e17b97199cad788f5f9d919531ee9f09bb233b5565233aef1de39a1d6635237703c819d47cf9ca5c53ca8adcdec'
hoge=bytes.fromhex('59cc9e17b97199cad788f5f9d919531ee9f09bb233b5565233aef1de39a1d6635237703c819d47cf9ca5c53ca8adcdec')
aes_key=b"venom2025venom25"
cipher_aes=AES.new(aes_key, AES.MODE_ECB)
pad=cipher_aes.decrypt(hoge)
pad_len=pad[-1]
#去除PKS7填充
enc_tmp=pad[:-pad_len]

#salsa20_dec
# nonce=0xD9CBC6D9CBF5C3DC
# salsa=[0x999D939CCF9F9B9F,0x9A93C89CC898CF93,0x93CB9FCE9998989D,0x9ACCCC9D9BCFC999,
# 0x999D939CCF9F9B9F,0x9A93C89CC898CF93,0x93CB9FCE9998989D,0x9ACCCC9D9BCFC999]
# hoge1=[]
# hoge2=[]
# hoge1.extend(nonce.to_bytes(8, 'little'))
# for qword in salsa:
# hoge2.extend(qword.to_bytes(8, 'little'))
# nonce=bytes(b ^ 0xAA for b in hoge1[::-1])
# salsa_key=bytes(b ^ 0xAA for b in hoge2[::-1])
# print(nonce,salsa_key)
# b'salsa_iv'
# b'0ff71ec39a5d322709b6b2e93796e5150ff71ec39a5d322709b6b2e93796e515'
nonce=b'salsa_iv'
salsa_key=bytes.fromhex('0ff71ec39a5d322709b6b2e93796e5150ff71ec39a5d322709b6b2e93796e515')
cipher_salsa=Salsa20.new(key=salsa_key,nonce=nonce)
flag=cipher_salsa.decrypt(enc_tmp)
print(flag.decode())
# vctf{ab92105b_047e_aa38_0b25_a6989b8e5ed5}

venom2025_闻花识女人
https://alenirving.github.io/2025/11/17/venom2025_闻花识女人/
作者
Ma5k
许可协议
CC-BY-NC-SA