geek2025re
本文最后更新于44 天前,其中的信息可能已经过时,如有错误请发送邮件到2624241828@qq.com

ez_pyyy

pyc反编译,加密顺序是,异或17,高低位交换,反转字节,循环左移32位

SYC{jtfgdsfda554_a54d8as53}

cipher = [

    48, 55, 57, 50, 53, 55, 53, 50, 52, 50, 48, 55, 101, 52, 53, 50, 52, 50, 52, 50, 48, 55, 53, 55, 55, 55, 50, 54, 53, 55, 54, 55, 55, 55, 53, 54, 98, 55, 97, 54, 50, 53, 56, 52, 50, 52, 99, 54, 50, 50, 52, 50, 50, 54]



def en3(b):

&nbsp; &nbsp; return (b << 4 & 240) | (b >> 4 & 15)



def en33_inv(data, n):

&nbsp; &nbsp; bit_len = len(data) * 8

&nbsp; &nbsp; n = n % bit_len

&nbsp; &nbsp; val = int.from_bytes(data, 'big')

&nbsp; &nbsp; val = (val >> n) | (val << (bit_len - n)) & ((1 << bit_len) - 1)

&nbsp; &nbsp; return val.to_bytes(len(data), 'big')


cipher_hex = ''.join(chr(c) for c in cipher)

data = bytes.fromhex(cipher_hex)

data = en33_inv(data, 32)

data = data[::-1]

data = bytes([en3(b) for b in data])
data = bytes([b ^ 17 for b in data])

flag = data.decode('utf-8')

print(flag)

only flower

ida反编译打开找到jumpout处打开汇编,发现是jmp跳转到错误地址导致错误,jmp对应ef,将ef部分nop掉,直到能看到正确伪代码,查看算法得出(试出来的算法,试了几个不同rol8的实现,标准循环左移,右移,右移成功了)

cipher = [
    0x0A, 0x84, 0xC2, 0x84, 0x51, 0x48, 0x5F, 0xF2,
    0x9E, 0x8D, 0xD0, 0x84, 0x75, 0x67, 0x73, 0x8F,
    0xCA, 0x57, 0xD7, 0xE6, 0x14, 0x6E, 0x77, 0xE2,
    0x29, 0xFE, 0xDF, 0xCC
]
key = "GEEK2025"
result = []

for i, y in enumerate(cipher):
    r = (y - i) & 0xFF
    k = ord(key[i % len(key)])
    shift = k & 7
    x = ((r >> shift) | (r << (8 - shift))) & 0xFF
    result.append(chr(x ^ k))

print(''.join(result))

SYC{asdjjasdhjk12wk12ijkejk}

QYQSの奇妙冒险

die查看文件格式,拖进x86dbg查看,题目提示有按空格,试了下发现叫我nop的,把jmp部分nop结束运行,有多余的int3部分,nop掉进入正确汇编码,继续运行,随机试一个发现退出了,放弃了,拖进ida静态分析发现是xor,直接算了,就是先让input与i异或,再与key[i%4]异或,key为QYQS

def decrypt():

&nbsp; &nbsp; QYQS = [

&nbsp; &nbsp; &nbsp; &nbsp; 2, 1, 16, 43, 28, 3, 23, 57, 6, 1,

&nbsp; &nbsp; &nbsp; &nbsp; 34, 41, 14, 11, 45, 109, 6, 32, 23, 127, 56

&nbsp; &nbsp; ]

&nbsp; &nbsp; key = "QYQS"

&nbsp; &nbsp; result = []

&nbsp; &nbsp; for i in range(21):

&nbsp; &nbsp; &nbsp; &nbsp; decrypted = QYQS[i] ^ ord(key[i % 4])

&nbsp; &nbsp; &nbsp; &nbsp; decrypted ^= i

&nbsp; &nbsp; &nbsp; &nbsp; result.append(chr(decrypted))

&nbsp; &nbsp; return ''.join(result)



flag = decrypt()

print(f"Flag: {flag}")

SYC{I_@m_QyqS_r1GhT?}

encode

拖进ida,有个base64提示,查看顺序表发现是标准base64,外加一个异或,(每个与0x5A异或)把密文解码发现是乱码,不对,翻翻别的算法,发现还有个xtea,加上xtea解码,密钥是geek2025reverse!,得出flag
流程就是先用tea加密,异或,base64加密得到加密后flagvBzX30Koxl3HpDaYaFJKhyB/1ckuVCnc4wZhrwUWeNuZkAxr+Qn5UaYbpvymmCrk

import base64
import struct

def xtea_dec(block, key):
    v0, v1 = struct.unpack('>II', block)
    sum_val, delta = 0xC6EF3720, 0x9E3779B9
    for _ in range(32):
        v1 = (v1 - (((v0 << 4) ^ (v0 >> 5)) + v0 ^ sum_val + key[(sum_val >> 11) & 3])) & 0xFFFFFFFF
        sum_val = (sum_val - delta) & 0xFFFFFFFF
        v0 = (v0 - (((v1 << 4) ^ (v1 >> 5)) + v1 ^ sum_val + key[sum_val & 3])) & 0xFFFFFFFF
    return struct.pack('>II', v0, v1)

data = base64.b64decode("vBzX30Koxl3HpDaYaFJKhyB/1ckuVCnc4wZhrwUWeNuZkAxr+Qn5UaYbpvymmCrk")
data = bytes(b ^ 0x5A for b in data)
key = struct.unpack('>4I', b"geek2025reverse!")

res = b''.join(xtea_dec(data[i:i+8], key) for i in range(0, len(data), 8))
print(res[:-res[-1]].decode())

SYC{St4nd4rd_Funct10n_N0t_4lw4ys_St4nd4rd}

ezSMC

去掉virtualprotcet部分,在miao encrypt点进去之后的前面下断点动调,得到解密后的加密函数内容,u,c得到伪代码,算法是rc4+base58+base64

import base64

BASE58_TABLE = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789"

class RC4:
    def __init__(self, key):
        self.S = list(range(256))
        j = 0
        for i in range(256):
            j = (j + self.S[i] + key[i % len(key)]) & 0xFF
            self.S[i], self.S[j] = self.S[j], self.S[i]
        self.i = 0
        self.j = 0

    def crypt(self, data):
        res = bytearray()
        for b in data:
            self.i = (self.i + 1) & 0xFF
            self.j = (self.j + self.S[self.i]) & 0xFF
            self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
            k = self.S[(self.S[self.i] + self.S[self.j]) & 0xFF]
            res.append(b ^ k)
        return bytes(res)

def base58_decode(data):
    leading_zeros = 0
    for char in data:
        if char == BASE58_TABLE[0]:
            leading_zeros += 1
        else:
            break
    num = 0
    for char in data[leading_zeros:]:
        num = num * 58 + BASE58_TABLE.index(char)
    res = bytearray()
    while num > 0:
        res.append(num & 0xFF)
        num >>= 8
    return (b'\x00' * leading_zeros) + res[::-1]

cipher = "tHMoSoMX71sm62ARQ8aHF6i88nhkH9Ac2J7CrkQsQgXpiy6efoC8YVkzZu1tMyFxCLbbqvgXZHxtwK5TACVhPi1EE5mK6JG56wPNR4d2GmkELGfJHgtcAEH7"

b58_res = base58_decode(cipher)
b64_res = base64.b64decode(b58_res)
hex_res = bytes.fromhex(b64_res.decode())
rc4 = RC4([17])
flag = rc4.crypt(hex_res)

print(flag.decode())

SYC{OHhhhhhhh_y0u_Kn0m_SMCCCC@!}

QYQSの奇妙冒险2

翻汇编中,看到flag了,把flag导出来去空格
SYC{M@y_bE_y0u_F1nd?}

obfuscat3

在init_encode里面看到一个像是密钥流一样的东西,仔细看发现是rc4,v5 = 0x617261736D6153LL,对应Samsara,main里面有

obf_encode(s, n_4, (unsigned __int8 *)&v5);
a1[i] += mysterious_box[(unsigned __int8)((int)(v19
                                                  - ((~(unsigned __int8)mysterious_box[v22] | ~((v13 & 0x7911131C | mysterious_box[v21] & 0xE3) ^ (mysterious_box[v22] & 0x1C | ~(unsigned __int8)mysterious_box[v22] & 0x86EEECE3)))
                                                   + 1))
                                            % 256)];

(能看到类似rc4的操作了)在initencode里·,初始化了s,用密钥置换,obfencode生成密钥流,操作,拿rc4解出错了,重新看,使用了mysteriousbox数组,发现是变种rc4,异或变成加法,

a1[i] += mysterious_box

解密把加法变成减法

def rc4_init(key):

&nbsp; &nbsp; S = list(range(256))

&nbsp; &nbsp; j = 0

&nbsp; &nbsp; for i in range(256):

&nbsp; &nbsp; &nbsp; &nbsp; j = (j + S[i] + key[i % len(key)]) % 256

&nbsp; &nbsp; &nbsp; &nbsp; S[i], S[j] = S[j], S[i]

&nbsp; &nbsp; return S



def rc4_stream(S, length):

&nbsp; &nbsp; i = 0

&nbsp; &nbsp; j = 0

&nbsp; &nbsp; stream = []

&nbsp; &nbsp; for _ in range(length):

&nbsp; &nbsp; &nbsp; &nbsp; i = (i + 1) % 256

&nbsp; &nbsp; &nbsp; &nbsp; j = (j + S[i]) % 256

&nbsp; &nbsp; &nbsp; &nbsp; S[i], S[j] = S[j], S[i]

&nbsp; &nbsp; &nbsp; &nbsp; stream.append(S[(S[i] + S[j]) % 256])

&nbsp; &nbsp; return stream



cipher = [

&nbsp; &nbsp; 0xB4, 0xCD, 0x69, 0x54, 0xBD, 0x67, 0x20, 0x9D, 0xF2, 0xC3, 0x24, 0x14, 0xC2, 0x1B, 0xE9, 0x6A,

&nbsp; &nbsp; 0x44, 0x14, 0x4E, 0x39, 0xC5, 0xC8, 0x5B, 0x11, 0x75, 0xAD, 0xDE, 0xBB, 0xFE, 0xE4, 0x6E, 0x65,

&nbsp; &nbsp; 0x06, 0x9A, 0x91, 0xFE, 0xA0, 0x68, 0xA4, 0x86, 0x17, 0x6C, 0x0A, 0xCF, 0x1E, 0x67, 0xE3, 0x0D,

&nbsp; &nbsp; 0x60, 0x47, 0x13, 0x6B, 0xD1, 0x36, 0xF2, 0x77, 0x58, 0x76, 0x1E, 0x98, 0xF5, 0x7F, 0x0A, 0x92,

&nbsp; &nbsp; 0xB7, 0x0A, 0xEA, 0xAE, 0x46, 0x7E, 0x6A, 0x18, 0x4A, 0x59, 0x4E, 0x71, 0xB2, 0xE1, 0x41, 0x7A,

&nbsp; &nbsp; 0x0B, 0x31, 0xBA, 0xC6, 0xAA, 0xCF, 0xCE, 0x09, 0xBF, 0x2E, 0xF8, 0x4D, 0x75, 0xEF, 0x14, 0xED,

&nbsp; &nbsp; 0x5F, 0x66, 0x44, 0x6F, 0xDE, 0xE2, 0x7C, 0x10, 0x8C, 0xB7, 0x4E, 0x6B, 0xB2, 0xD4, 0xF6, 0x91,

&nbsp; &nbsp; 0xD7, 0x84, 0x86, 0x1F, 0xF8, 0x65, 0x94, 0x0B, 0x14, 0x28, 0xFB, 0xDD, 0x47, 0xF4, 0xC1, 0x17,

&nbsp; &nbsp; 0x42, 0x3F, 0x1E, 0x38, 0x07, 0xBB, 0x37, 0x33, 0x12, 0x0C, 0x16, 0x68, 0xE0, 0x23, 0x12, 0x75,

&nbsp; &nbsp; 0x72, 0xD9, 0x71, 0x7A, 0x88, 0xD0, 0x46, 0x28, 0x88, 0xAD, 0x1E, 0x98, 0x8F, 0x92, 0x7E, 0x0E,

&nbsp; &nbsp; 0x69, 0x29, 0x37, 0xB1, 0xFF, 0xC5, 0xAF, 0x6F, 0x41, 0x37, 0x65, 0x0E, 0xD2, 0x62, 0x11, 0x8F,

&nbsp; &nbsp; 0xA6, 0x3E, 0x95, 0xF5, 0x80, 0x9A, 0xDC

]



key = b'Samsara'

S = rc4_init(key)

stream = rc4_stream(S, len(cipher))

plain = bytes((cipher[i] - stream[i]) % 256 for i in range(len(cipher)))

print(plain.decode())

SYC{Alright_I_sti1l_h0pe_th3t_you_solved_the_chall3nge_by_deobfuscating_them_Geek_is_just_the_first_step_of_your_CTF_journey_Im_glad_I_could_be_part_of_your_growth_Good_luck_for_y0u!}

Gensh1n

有个简单输入,对应八个有一个相同,通过is valid char判断,将输入的每个字符与global_nodes[16 * j]比较,有匹配就设置v5=1跳出循环clean up里面,取八个字符作为v7,然后判断

if ( !validate_key((__int64)v7, 8) )
    exit(1);

,在data段找到 arr geek2025,和result28字节数据,在sub44656里面看出rc4,因为有个sbox和ksa和prga和异或加密,普通rc4解密,解一下
validate_key说明globalnodes的八字节key固定

result = [0x52, 0x59, 0xF3, 0x8A, 0x00, 0x0F, 0xE6, 0x56, 0x36, 0xE5, 0xF0, 0x33, 0x40, 0x6E, 0x56, 0x81, 0x5A, 0xE5, 0x6F, 0x87, 0x6F, 0x9F, 0x21, 0xC9, 0xA6, 0xBB, 0x16, 0x51]

key = b"geek2025"



S = list(range(256))

j = 0

for i in range(256):

&nbsp; &nbsp; j = (j + S[i] + key[i % 8]) % 256

&nbsp; &nbsp; S[i], S[j] = S[j], S[i]



i = j = 0

plaintext = []

for byte in result:

&nbsp; &nbsp; i = (i + 1) % 256

&nbsp; &nbsp; j = (j + S[i]) % 256

&nbsp; &nbsp; S[i], S[j] = S[j], S[i]

&nbsp; &nbsp; k = S[(S[i] + S[j]) % 256]

&nbsp; &nbsp; plaintext.append(byte ^ k)



print("Snd input:", bytes(plaintext))

SYC{50_y0u_pl@y_Gensh1n_too}

GeekBinder

获取硬编码数据,查看算法,有个8字节循环密钥,异或解密就行,两个文件分别打开使用的数据会有不同flag,有细微差别
在sub1119里,有一个xor的过程,每个字节,密钥是geek2025,循环使用,在qword2020,2928到2060,word2078,byte207a那里提数据,在内存中,字节从低地址到高地址,所以最后根据提取出的数据写解密脚本
但是第一个解密脚本得出了一个错误flag,格式是正确的

encrypted = [
    0x34, 0x3C, 0x26, 0x10, 0x73, 0x5E, 0x72, 0x7C,
    0x1E, 0x1F, 0x54, 0x05, 0x55, 0x6F, 0x66, 0x5D,
    0x54, 0x3A, 0x15, 0x19, 0x5D, 0x53, 0x01, 0x46,
    0x14, 0x56, 0x14, 0x34, 0x70, 0x03, 0x66, 0x42,
    0x02, 0x00, 0x0B, 0x34, 0x74, 0x59, 0x5E, 0x50,
    0x54, 0x3A, 0x54, 0x18, 0x6D, 0x53, 0x5D, 0x5B,
    0x13, 0x17, 0x25, 0x19, 0x4B, 0x6F, 0x66, 0x5A,
    0x38, 0x0B, 0x55, 0x19, 0x5F, 0x70, 0x5E, 0x6A,
    0x17, 0x17, 0x25, 0x08, 0x46, 0x59, 0x51, 0x06,
    0x38, 0x54, 0x0B, 0x34, 0x60, 0x55, 0x6D, 0x50,
    0x09, 0x02, 0x54, 0x05, 0x57, 0x55, 0x40, 0x04,
    0x09, 0x02,
    0x18
]

key = "geek2025"
key_bytes = [ord(c) for c in key]

decrypted = []
for i, byte in enumerate(encrypted):
    k = key_bytes[i % len(key_bytes)]
    decrypted.append(byte ^ k)

decrypted_str = ''.join(chr(b) for b in decrypted)
print(decrypted_str)

SYC{An@Iyz1ng_Th3_proc3s3q_B3Tween_File3_1s_contr@ry_To_n0rm@l_pr@ctic3_1n_Re_engineer1ng},查看另一个so文件看到的是

*v3 = 0x7C725E7310263C34LL;
  v3[1] = 0x5D666F5505541F1ELL;
  v3[2] = 0x4601535D19153A54LL;
  v3[3] = 0x4266037034165614LL;
  v3[4] = 0x505E5974340B0002LL;
  v3[5] = 0x5B5D536D18543A54LL;
  v3[6] = 0x5A666F4B19251713LL;
  v3[7] = 0x6A5E705F19550B38LL;
  v3[8] = 0x651594608251717LL;
  v3[9] = 0x506D5560340B5438LL;
  v3[10] = 0x440555705540209LL;

换了个数据提,出正确flag了

encrypted = [

&nbsp; &nbsp; 0x34, 0x3C, 0x26, 0x10, 0x73, 0x5E, 0x72, 0x7C,

&nbsp; &nbsp; 0x1E, 0x1F, 0x54, 0x05, 0x55, 0x6F, 0x66, 0x5D,

&nbsp; &nbsp; 0x54, 0x3A, 0x15, 0x19, 0x5D, 0x53, 0x01, 0x46,

&nbsp; &nbsp; 0x14, 0x56, 0x14, 0x34, 0x70, 0x03, 0x66, 0x42,

&nbsp; &nbsp; 0x02, 0x00, 0x0B, 0x34, 0x74, 0x59, 0x5E, 0x50,

&nbsp; &nbsp; 0x54, 0x3A, 0x54, 0x18, 0x6D, 0x53, 0x5D, 0x5B,

&nbsp; &nbsp; 0x13, 0x17, 0x25, 0x19, 0x4B, 0x6F, 0x66, 0x5A,

&nbsp; &nbsp; 0x38, 0x0B, 0x55, 0x19, 0x5F, 0x70, 0x5E, 0x6A,

&nbsp; &nbsp; 0x17, 0x17, 0x25, 0x08, 0x46, 0x59, 0x51, 0x06,

&nbsp; &nbsp; 0x38, 0x54, 0x0B, 0x34, 0x60, 0x55, 0x6D, 0x50,

&nbsp; &nbsp; 0x09, 0x02, 0x54, 0x05, 0x57, 0x55, 0x40, 0x04,

&nbsp; &nbsp; 0x09, 0x02,

&nbsp; &nbsp; 0x18

]

key = "geek2025"

key_bytes = [ord(c) for c in key]



decrypted = []

for i, byte in enumerate(encrypted):

&nbsp; &nbsp; k = key_bytes[i % len(key_bytes)]

&nbsp; &nbsp; decrypted.append(byte ^ k)



decrypted_str = ''.join(chr(b) for b in decrypted)

print(decrypted_str)

SYC{An@Iyz1ng_Th3_proc3ss3q_B3Tween_File3_1s_contr@ry_To_n0rm@l_pr@ctic3_1n_Re_eng1neer1ng}

ez_vm

sub_1a2b3c里,key为3,运行string_process_program,处理加密数据

 sub_1a2b3c(global_vm, &sub_5c6d7e, 3LL, 0x1DuLL);

传入3了,后面数据变化了,
在sub_9e8f7a里,会读输入,将输入存到vm内存偏移512的地方,再将一段长度为29的数据从偏移256出复制到768处,在汇编码里面有一个mov r3, 0x5A,把z放入寄存器了,然后在vmrun里面执行了,判断异或在于10h,xor的操作码
提取数据,每个字节+3,与0x5A进行异或,得到flag

def solve_final():

&nbsp; &nbsp; encrypted_data = [

&nbsp; &nbsp; &nbsp; &nbsp; 0x06, 0x00, 0x16, 0x1E, 0x0A,

&nbsp; &nbsp; &nbsp; &nbsp; 0x66, 0x68, 0x36, 0x67, 0x34, 0x66,

&nbsp; &nbsp; &nbsp; &nbsp; 0x02, 0x2B, 0x67, 0x02, 0x25, 0x66,

&nbsp; &nbsp; &nbsp; &nbsp; 0x17, 0x68, 0x02, 0x25, 0x66, 0x29,

&nbsp; &nbsp; &nbsp; &nbsp; 0x3C, 0x25, 0x26, 0x3C, 0x78, 0x24

&nbsp; &nbsp; ]



&nbsp; &nbsp; flag = ""

&nbsp; &nbsp; for b in encrypted_data:

&nbsp; &nbsp; &nbsp; &nbsp; val = ((b + 3) & 0xFF) ^ 0x5A

&nbsp; &nbsp; &nbsp; &nbsp; flag += chr(val)



&nbsp; &nbsp; print(f"Flag: {flag}")



if __name__ == "__main__":

&nbsp; &nbsp; solve_final()

SYC{W31c0m3_t0_r3@1_r3verse!}

reReverse

打开main发现很简短,查看其他function发现了一个没见过的writtenflags,在csdn里面搜索发现应该是tf,查看其它部分,直接动调试验一个flag,发现符合tf直接被退出了,设置断点也会退出,搜索教程nop掉tf部分发现程序会崩溃,改去汇编里面找,在汇编里面发现有个tea系列的Δ常数0x9E3779B9,TEA算法的主要特征表现在sum和delta变量,有位运算和循环,尝试了tea和xtea都是乱码,没招了问了学长,对比tea,xtea,xxtea特征,发现mx,确定是xxtea。找到key,密钥,密文等部分,别的值解密是乱码没有数字,但是汇编解密有一段0000000000403080从这里开始,可能是比较的明文,从汇编码提出值,然后根据地址的顺序排列这些值0xDEAD, 0xBEEF, 0x5A7D, 0xC0FF运用密钥,最后解密成字符串

import struct

def xxtea_decrypt(v, k):
    n = len(v)
    rounds = 6 + 52 // n
    sum_val = (rounds * 0x9E3779B9) & 0xFFFFFFFF
    y = v[0]
    for _ in range(rounds):
        e = (sum_val >> 2) & 3
        for p in range(n - 1, 0, -1):
            z = v[p - 1]
            y = v[p] = (v[p] - ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z)))) & 0xFFFFFFFF
        p = 0
        z = v[n - 1]
        y = v[0] = (v[0] - ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z)))) & 0xFFFFFFFF
        sum_val = (sum_val - 0x9E3779B9) & 0xFFFFFFFF
    return v

data = [
    0x2973BD37, 0x1BA99AA3, 0xB3C20088, 0xBFC393AB, 0x352ADCCF,
    0x3B98E6E6, 0xAE421991, 0xD7B702CF, 0x0EEF6889, 0x08662435
]
key = [0xDEAD, 0xBEEF, 0x5A7D, 0xC0FF]

res = xxtea_decrypt(data, key)
flag_bytes = b''.join(struct.pack('<I', x) for x in res)

print(f"Hex: {flag_bytes.hex()}")
print(f"结果: {flag_bytes.decode().rstrip(chr(0))}")

在.text段可以看到比较指令

.text:00000000004008BA                 cmp     r9d, 2973BD37h
.text:00000000004008E1                 cmp     r10d, 8662435h
.text:00000000004008ED                 cmp     r11d, 0EEF6889h
.text:00000000004008F9                 cmp     ebx, 0AE421991h
.text:0000000000400902                 cmp     ebp, 0D7B702CFh
.text:000000000040090A                 cmp     r8d, 3B98E6E6h
.text:0000000000400926                 cmp     edx, 352ADCCFh
.text:000000000040092F                 cmp     ecx, 0BFC393ABh
.text:0000000000400938                 cmp     esi, 0B3C20088h
.text:0000000000400942                 cmp     edi, 1BA99AA3h

然后再这段中,有

.text:0000000000400CEA                 mov     r9d, [rsp+40h]
.text:0000000000400CDE                 mov     edi, [rsp+44h]
.text:0000000000400CD0                 mov     esi, [rsp+48h]
.text:0000000000400CC4                 mov     ecx, [rsp+4Ch]
.text:0000000000400CB4                 mov     edx, [rsp+50h]
.text:0000000000400CA7                 mov     r8d, [rsp+54h]
.text:0000000000400CA3                 mov     ebx, [rsp+58h]
.text:0000000000400C9F                 mov     ebp, [rsp+5Ch]
.text:0000000000400C92                 mov     r11d, [rsp+60h]
.text:0000000000400C8D                 mov     r10d, [rsp+64h]

加载值到寄存器的过程,然后在后面的比较里被使用
就是先从栈加载解密后的值到寄存器,再将寄存器值与硬编码比较,比较成功就win

SYC{sakurakouji_runasama_wa_seikai_ichi}

ezRu3t

下了个rust的插件,算法一个base64一个base85,有

!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu
base85
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
base64
<AA;XAM?,_@;T[r@7E779h8;s>'`pt=>3c6ASuHFASOtP<Gkf_A4&gPAl1]S
密文

网站在线解密得SYC{Ohjhhh_y0u_g3t_Ezzzzz3_Ru3t!@}

qyqs2

反调试混淆技巧
浮点数标准(IEEE 754)NAN的特殊性质

.text:000000014001264B                 movss   xmm0, [rbp+2D0h+a]  ; 将变量 a 加载到 xmm0 寄存器
.text:0000000140012653                 ucomiss xmm0, [rbp+2D0h+a]  ; 将 xmm0 与 a 进行比较 (即比较 a 和 a)
.text:000000014001265A                 jp      loc_1400127AA       ; jp (Jump if Parity) 如果 P/PF 标志位为 1 则跳转
.text:0000000140012660                 jnz     loc_1400127AA       ; jnz 如果非零则跳转(这里是辅助判断)
.text:0000000140012666                 mov     [rbp+2D0h+i], 0     ; 假路径:如果没跳转,继续执行这里

指令ucomiss
当两个操作数至少有一个是NAN时,比较结果会被标记为无需,三个标志位zf,pf,cf同时置为一。jp跳转检测pf,整数运算中,pf表示就行,pf设置为一,jp生效,跳转到loc_1400127AA
原理,ida生成伪代码时会进行死代码消除,ucomiss之后的jp或jnz分支被认为不可能执行
解决,将jp改为jmp强制跳转

her

enc1到enc2的连接点就是seh结构化异常处理,将异常处理函数地址压栈,保留旧的异常链表头,将当前栈顶设为新的表头,然后再mov large fs:0, esp后面,接了一个div,首先在xor ecx, ecx这里,将ecx寄存器清零,eax设为1,div 一个为0的寄存器,导致异常,然后将eip指向sub401186,让这几个无法执行

.text:00401F7C                 mov     eax, [esp+0E0h+var_E0]
.text:00401F7F                 mov     large fs:0, eax
.text:00401F85                 add     esp, 8

然后就到enc2了,继续找enc就行,就是把正常加密放进seh里面了,但seh的大体结构是不变的,在反调试的部分里面,因为设置了动态key,(每次触发异常的时候,进入enc2或者enc3,key就变化)所以把反调试改掉会直接出来空的

def solve():
    enc = [
        0x2D, 0x4F, 0x69, 0x3D, 0x5F, 0x01, 0xBD, 0x9F,
        0xA4, 0x6D, 0x89, 0xAE, 0x2A, 0xEA, 0xD1, 0x9C,
        0x71, 0x6D, 0xE1, 0x1E, 0x38, 0x7E, 0x8C, 0x0A, 
        0xCE, 0x6B, 0xE0, 0xF7, 0x36, 0x72, 0x99
    ]

    b = 0
    flag = ""

    for i in range(len(enc)):
        target_byte = enc[i]
        b_start = b
        found = False

        for char_code in range(128):
            curr_b = b_start
            x = char_code

            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF
            x = (curr_b & 0xFF) ^ x ^ 0xAA

            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF
            term = (curr_b & 0xFF) + (i * i)
            x = (x + term) & 0xFF

            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF
            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF
            term = (curr_b & 0xFF) + (i * i)
            x = (x + term) & 0xFF

            out = ((x >> 5) | (x << 3)) & 0xFF

            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF
            curr_b ^= 0x1A373
            curr_b = (curr_b + 1) & 0xFFFFFFFF

            if out == target_byte:
                flag += chr(char_code)
                b = curr_b
                found = True
                break

        if not found:
            flag += "?"

    print(flag)

if __name__ == "__main__":
    solve()

Mission Ghost Signal

翻看data段,找到一个Syclover2025Geek,往回查调用,然后发现

int sub_402DB1()
{
  _BYTE v1[32]; // [esp+1Ch] [ebp-20Ch] BYREF
  char v2[192]; // [esp+3Ch] [ebp-1ECh] BYREF
  char Buffer[256]; // [esp+FCh] [ebp-12Ch] BYREF
  _BYTE v4[16]; // [esp+1FCh] [ebp-2Ch] BYREF
  int v5; // [esp+20Ch] [ebp-1Ch]
  int j; // [esp+210h] [ebp-18h]
  char v7; // [esp+217h] [ebp-11h]
  int i; // [esp+218h] [ebp-10h]
  size_t v9; // [esp+21Ch] [ebp-Ch]

  sub_403500();
  SetConsoleOutputCP(0xFDE9u);
  SetConsoleCP(0xFDE9u);
  qmemcpy(v4, "1145141145144332", sizeof(v4));
  puts(&::Buffer);
  printf(&byte_407090);
  if ( fgets(Buffer, 256, (FILE *)iob[0]._ptr) )
  {
    v9 = strlen(Buffer);
    if ( v9 && Buffer[v9 - 1] == 10 )
      Buffer[--v9] = 0;
    if ( v9 == 25 )
    {
      sub_401C08(v2, aSyclover2025ge, v4);
      memcpy(v1, Buffer, 0x19u);
      v5 = 7;
      for ( i = 25; i <= 31; ++i )
        v1[i] = v5;
      sub_402B57(v2, v1, 32);
      v7 = 1;
      for ( j = 0; j <= 31; ++j )
      {
        if ( byte_406020[j] != v1[j] )
        {
          v7 = 0;
          break;
        }
      }
      if ( v7 )
        puts(&byte_4070F0);
      else
        puts(&byte_40711C);
      return 0;
    }
    else
    {
      puts(&byte_4070BC);
      return 1;
    }
  }
  else
  {
    puts(&::Buffer);
    return 1;
  }
}

其他puts的转字符串是

.rdata:0040707D Buffer          db '密码验证系统',0           ; DATA XREF: sub_402DB1+77↑o
.rdata:00407090 ; const char asc_407090
.rdata:00407090 asc_407090      db '请输入压缩包密码: ',0       ; DATA XREF: sub_402DB1+83↑o
.rdata:004070AB ; const char Buffer
.rdata:004070AB Buffer          db '输入错误!',0,0          ; DATA XREF: sub_402DB1+B7↑o
.rdata:004070BC ; const char asc_4070BC
.rdata:004070BC asc_4070BC      db '特工,你失败了!密码长度不正确。',0,0,0,0
.rdata:004070BC                                         ; DATA XREF: sub_402DB1+10E↑o
.rdata:004070F0 ; const char asc_4070F0
.rdata:004070F0 asc_4070F0      db '恭喜!这是正确的压缩包密码。',0,0,'特工,你失败了!密码不正确。',0,0

就确定了这里是主要加密段了
然后动调patse data
把call 0x402B57(加密)改成call 0x402BE8(解密),然后替换成byte_406020的数据,得出密码

stack_bomb

nop掉了一些push的部分伪c出来了
知道是tea了,然后找出魔改点

from ctypes import c_uint32

def decrypt(v, k):
    v0, v1 = c_uint32(v[0]), c_uint32(v[1])
    delta = 0x9000000
    sum_val = c_uint32(delta * 32)

    for _ in range(32):
        v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum_val.value) ^ ((v0.value >> 5) + k[3])
        v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum_val.value) ^ ((v1.value >> 5) + k[1])
        sum_val.value -= delta
    return v0.value, v1.value

enc = [
    [0x9A8C0C4B, 0xC412FF1C], [0xBFC3A488, 0xB16C8FD0],
    [0x4136E319, 0x8835E4FF], [0x118263A7, 0x7C85D629]
]
key = [1, 2, 3, 4]
flag = b''

for g in enc:
    d = decrypt(g, key)
    flag += d[0].to_bytes(4, 'little') + d[1].to_bytes(4, 'little')

print(flag.decode())

ez_android

打开软件,对应搜索,进入function1
解密

from Crypto.Cipher import DES
import binascii

cipher_text = "43464244374534323530413841423536"
key = "12345678"

def solve_part1():
    try:
        first_layer = binascii.unhexlify(cipher_text).decode('utf-8')
        cipher_bytes = binascii.unhexlify(first_layer)
        des = DES.new(key.encode('utf-8'), DES.MODE_ECB)
        decrypted = des.decrypt(cipher_bytes)
        print(f"Part 1 Flag: {decrypted.decode('utf-8', errors='ignore').strip()}")
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    solve_part1()

function2,进入libwrapper.so层查看,有提示realso,用frida脚本提出来,或者找encrypted_so,所有字节异或0xAA(因为可以出elf文件头),然后发现是rc4,key是mysecret,解出第二部分,第三部分,有一个libfunction3.so,能看到算法,但不知道s盒,要dump出来,最后解密

import struct

IP = [
    58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
]

FP = [
    40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
    36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
    34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
]

E = [
    32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13,
    14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
    24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
]

P = [
    16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
    2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
]

PC1 = [
    57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,
    59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39,
    31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37,
    29, 21, 13, 5, 28, 20, 12, 4
]

PC2 = [
    14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4,
    26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40,
    51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
]

SHIFTS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

S_BOX = [
    [
        [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7], [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8], [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0], [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]
    ],
    [
        [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10], [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5], [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15], [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]
    ],
    [
        [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8], [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1], [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7], [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]
    ],
    [
        [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15], [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9], [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4], [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]
    ],
    [
        [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9], [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6], [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14], [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]
    ],
    [
        [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11], [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8], [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6], [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]
    ],
    [
        [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1], [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6], [1, 4, 11, 13, 12, 3, 7, 10, 15, 6, 8, 0, 5, 9, 14, 2], [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]
    ],
    [[0] * 16, [0] * 16, [0] * 16, [0] * 16]
]

def c_permute(in_bytes, table, out_bits):
    out_len = (out_bits + 7) // 8
    out = bytearray(out_len)
    for i in range(out_bits):
        pos = table[i] - 1
        byte_idx = pos // 8
        bit_idx = 7 - (pos % 8)
        if byte_idx < len(in_bytes):
            bit = (in_bytes[byte_idx] >> bit_idx) & 0x01
            out[i // 8] |= (bit << (7 - (i % 8)))
    return out

def rotl32(val, shift):
    shift = shift % 32
    return ((val << shift) & 0xFFFFFFFF) | (val >> (32 - shift))

def generate_subkeys(key_bytes):
    permuted_key = c_permute(key_bytes, PC1, 56)
    c_bytes = permuted_key[0:4]
    d_bytes = permuted_key[3:7]
    c_int = struct.unpack('>I', c_bytes)[0]
    d_int = struct.unpack('>I', d_bytes)[0]
    subkeys = []
    for s in SHIFTS:
        c_int = rotl32(c_int, s)
        d_int = rotl32(d_int, s)
        c_new = struct.pack('>I', c_int)
        d_new = struct.pack('>I', d_int)
        combined = bytearray(7)
        combined[0:4] = c_new
        combined[3:7] = d_new
        subkey = c_permute(combined, PC2, 48)
        subkeys.append(subkey)
    return subkeys

def feistel(R, subkey):
    expanded = c_permute(R, E, 48)
    for i in range(6):
        expanded[i] ^= subkey[i]
    output_val = 0
    for i in range(8):
        idx = i * 6
        byte_idx = idx // 8
        bit_idx = 7 - (idx % 8)
        b0 = (expanded[byte_idx] >> bit_idx) & 0x01
        idx5 = idx + 5
        byte_idx5 = idx5 // 8
        bit_idx5 = 7 - (idx5 % 8)
        b5 = (expanded[byte_idx5] >> bit_idx5) & 0x01
        row = (b0 << 1) | b5
        col = 0
        for j in range(1, 5):
            idxj = idx + j
            byte_idxj = idxj // 8
            bit_idxj = 7 - (idxj % 8)
            bit = (expanded[byte_idxj] >> bit_idxj) & 0x01
            col = (col << 1) | bit
        val = S_BOX[i][row][col]
        pos_in_int = 28 - (i * 4)
        output_val |= (val << pos_in_int)
    output_bytes = struct.pack('>I', output_val)
    temp = c_permute(output_bytes, P, 32)
    R[:] = temp

def des_crypt(key, data, mode='decrypt'):
    subkeys = generate_subkeys(key)
    if mode == 'decrypt':
        subkeys = subkeys[::-1]
    block = c_permute(data, IP, 64)
    L = block[0:4]
    R = block[4:8]
    for i in range(16):
        temp = bytearray(R)
        feistel(R, subkeys[i])
        for j in range(4):
            R[j] ^= L[j]
        L = temp
    preoutput = R + L
    output = c_permute(preoutput, FP, 64)
    return output

def main():
    DES_KEY = bytes([0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1])
    hex_ciphertext = "AEBCDE9B24029CA7"
    ciphertext = bytes.fromhex(hex_ciphertext)
    decrypted = des_crypt(DES_KEY, ciphertext, mode='decrypt')
    print(f"解密: {decrypted.decode('utf-8').rstrip(chr(0))}")

if __name__ == "__main__":
    main()

Th1s_1s_Th3_R3@lly_F1ag!得出

文末附加内容

评论

  1. Converter258
    Windows Edge
    2 月前
    2025-12-14 19:26:57

    吓哭了

  2. Byte
    Windows Edge
    2 月前
    2025-12-14 19:27:27

    给无机盐大手子orz了

  3. linye
    Windows Edge
    2 月前
    2025-12-14 19:28:32

    给无机盐神跪了

  4. sweet
    Windows Edge
    1 月前
    2026-1-10 22:52:18

    给无机盐🈸跪了😭

    • 博主
      sweet
      Windows Chrome
      1 月前
      2026-1-10 22:52:36

      爱你主播

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇