第三届黄河流域网络安全技能挑战赛WP
京麒杯是打不动的只好来看看小比赛-悲,Re题目整体难度不大,第一个ak了所有逆向
Reverse
qgd
最终flag格式:flag{part1flag/part2flag}
48 89 4C 24 08 55 57 48 81 EC 28 01 00 00 48 8D 6C 24 20 48 8D 0D 34 08 01 00 E8 96 FB FF FF 48 83 BD 20 01 00 00 00 75 05 E9 BF 00 00 00 48 8B 8D 20 01 00 00 E8 7D F9 FF FF 48 89 45 08 48 C7 45 28 00 00 00 00 EB 0B 48 8B 45 28 48 FF C0 48 89 45 28 48 8B 45 08 48 39 45 28 0F 83 8C 00 00 00 48 8B 45 28 48 FF C0 33 D2 B9 02 00 00 00 48 F7 F1 48 8B C2 48 83 F8 01 75 2A 48 8B 45 28 48 8B 8D 20 01 00 00 48 03 C8 48 8B C1 0F BE 00 83 F0 31 48 8B 4D 28 48 8B 95 20 01 00 00 48 03 D1 48 8B CA 88 01 48 8B 45 28 48 FF C0 33 D2 B9 02 00 00 00 48 F7 F1 48 8B C2 48 85 C0 75 2A 48 8B 45 28 48 8B 8D 20 01 00 00 48 03 C8 48 8B C1 0F BE 00 83 F0 58 48 8B 4D 28 48 8B 95 20 01 00 00 48 03 D1 48 8B CA 88 01
encrypted part1 flag:[88 ,47, 80 ,54 ,95 ,57, 90 ,54 ,94, 47]
第一部分很明显需要把上面十六进制字节写入文件然后ida反编译,发现是个奇偶位异或
第二部分在pyinstaller打包的exe中,解包拿到WO0o.pyc和secret.pyc
WO0o是主函数,发现调用了secret里的decrypt获得解密字符串然后做比较,因此直接打印就好
from secret import decrypt
key = bytes.fromhex('EC3700DFCD4F364EC54B19C5E7E26DEF6A25087C4FCDF4F8507A40A9019E3B48BD70129D0141A5B8F089F280F4BE6CCD')
ciphertext = b'\xd4z\'0L\x10\xca\x0b\x0b\xaa\x15\xbeK0"\xbf\xb2\xc6\x05'
cipher = decrypt(ciphertext, key)
a = bytes(input('flag呢'), encoding='utf-8')
if a == cipher:
print('没错没错')
else:
print('不对不对')
解密脚本如下
def key_schedule(key: bytes) -> list:
S = list(range(128))
v6 = 0
for j in range(128):
v6 = (S[j] + key[j % len(key)] + v6) % 128
v6 = (v6 ^ 55) % 128
S[j], S[v6] = (S[v6], S[j])
return S
def next_byte(state: dict) -> int:
S = state['S']
state['i'] = (state['i'] + 1) % 128
state['j'] = (state['j'] + S[state['i']]) % 128
S[state['i']], S[state['j']] = (S[state['j']], S[state['i']])
v2 = S[(S[state['i']] + S[state['j']]) % 128]
return (16 * v2 | v2 >> 4) & 255
def decrypt(ciphertext: bytes, key: bytes) -> bytes:
state = {'S': key_schedule(key), 'i': 0, 'j': 0}
plaintext = bytearray()
for byte in ciphertext:
plaintext.append(byte ^ next_byte(state))
return bytes(plaintext)
key = bytes.fromhex('EC3700DFCD4F364EC54B19C5E7E26DEF6A25087C4FCDF4F8507A40A9019E3B48BD70129D0141A5B8F089F280F4BE6CCD')
ciphertext = b'\xd4z\'0L\x10\xca\x0b\x0b\xaa\x15\xbeK0"\xbf\xb2\xc6\x05'
flag2 = decrypt(ciphertext, key).decode()
b = bytes.fromhex("48 89 4C 24 08 55 57 48 81 EC 28 01 00 00 48 8D 6C 24 20 48 8D 0D 34 08 01 00 E8 96 FB FF FF 48 83 BD 20 01 00 00 00 75 05 E9 BF 00 00 00 48 8B 8D 20 01 00 00 E8 7D F9 FF FF 48 89 45 08 48 C7 45 28 00 00 00 00 EB 0B 48 8B 45 28 48 FF C0 48 89 45 28 48 8B 45 08 48 39 45 28 0F 83 8C 00 00 00 48 8B 45 28 48 FF C0 33 D2 B9 02 00 00 00 48 F7 F1 48 8B C2 48 83 F8 01 75 2A 48 8B 45 28 48 8B 8D 20 01 00 00 48 03 C8 48 8B C1 0F BE 00 83 F0 31 48 8B 4D 28 48 8B 95 20 01 00 00 48 03 D1 48 8B CA 88 01 48 8B 45 28 48 FF C0 33 D2 B9 02 00 00 00 48 F7 F1 48 8B C2 48 85 C0 75 2A 48 8B 45 28 48 8B 8D 20 01 00 00 48 03 C8 48 8B C1 0F BE 00 83 F0 58 48 8B 4D 28 48 8B 95 20 01 00 00 48 03 D1 48 8B CA 88 01".replace(" ", ""))
with open("out", "wb") as f:
f.write(b)
flag1 = ""
encrypted = [88,47,80,54,95,57,90,54,94,47]
for i in range(len(encrypted)):
if i%2:
flag1 += chr(encrypted[i]^0x58)
else:
flag1 += chr(encrypted[i]^0x31)
print(f"flag{{{flag1+flag2}}}")
flag{iwannaknowwhat_DO_you_mean#@!}
Victory Melody
很简单小型虚拟机,可以直接导出opcode查看
int __fastcall sub_140011890(unsigned int *a1, __int64 a2, __int64 a3)
{
j___CheckForDebuggerJustMyCode(&unk_140022014, a2, a3);
while ( 1 )
{
switch ( *((_BYTE *)a1 + a1[2] + 268) )
{
case 0x10:
*a1 = *((char *)a1 + a1[2] + 269);
a1[2] += 2;
break;
case 0x11:
a1[1] = *((char *)a1 + a1[2] + 269);
a1[2] += 2;
break;
case 0x20:
*((_BYTE *)a1 + *((char *)a1 + a1[2] + 269) + 12) = *((_BYTE *)a1 + a1[2] + 270);
a1[2] += 3;
break;
case 0x30:
*((_BYTE *)a1 + *a1 + 12) ^= *((_BYTE *)a1 + 4);
++a1[2];
break;
case 0x40:
sub_14001109B(&unk_14001ACA4, a1 + 3); // %7s
++a1[2];
break;
case 0x50:
return j_memcmp(a1 + 3, (char *)a1 + *((char *)a1 + a1[2] + 269) + 12, *((char *)a1 + a1[2] + 270));
default:
continue;
}
}
}
发现输入7位字符,根据case值对vm做了个划分,然后动调发现7个字符均异或了0x21,直接就能出了
vm = [0x20, 0x10, 0x5B,
0x20, 0x11, 0x58,
0x20, 0x12, 0x56,
0x20, 0x13, 0x6E,
0x20, 0x14, 0x11,
0x20, 0x15, 0x4E,
0x20, 0x16, 0x00,
0x40,
0x11, 0x21,
0x10, 0x00,
0x30,
0x10, 0x01,
0x30,
0x10, 0x02,
0x30,
0x10, 0x03,
0x30,
0x10, 0x04,
0x30,
0x10, 0x05,
0x30,
0x10, 0x06,
0x30,
0x10, 0x07,
0x30,
0x50,
0x10, 0x07]
for i in range(0, 21, 3):
print(chr(vm[i+2]^0x21), end="")
然后md5后包上flag{}
R
rust写的很难分析,上午没看懂加密方式,隐约感觉像是流密码,但是发现输入不同异或的值也不同,下午出题人上了提示说是魔改了rc4有位移,直接一个个函数找就能找到魔改地方
主函数如下,很明显看出v12是比较值即加密完的数据,v25是我们输入加密完的结果,v4是密钥,加密函数是sub_140003C80
// Hidden C++ exception states: #wind=4
__int64 sub_1400040E0()
{//...
v29 = -2LL;
sub_1400017C0(v17, &off_140021CC0);
sub_14000A950(v17);
sub_140002A10(v18);
v20 = sub_140009F60();
v19[0] = sub_140009F90(&v20, v18);
v19[1] = v0;
sub_140001B80(v19);
v1 = sub_1400036A0(v18);
v15 = sub_140002080(v1, v2);
v16 = v3;
v4 = (_BYTE *)sub_140005C00(8LL, 1LL);
*v4 = 108;
v4[1] = 110;
v4[2] = 116;
v4[3] = 102;
v4[4] = 118;
v4[5] = 112;
v4[6] = 117;
v4[7] = 115;
sub_140006450(v21, v4, 8LL);
jumpbuf_sp = _except_get_jumpbuf_sp(v21);
v22[0] = sub_140006470(0LL, jumpbuf_sp);
v22[1] = v5;
while ( 1 )
{
v23 = sub_140005440(v22);
v24 = v6;
if ( !v23 )
break;
v13 = v24;
v10 = (_BYTE *)sub_140006780(v21, v24, &off_140021D10);
*v10 ^= v13;
}
v7 = sub_1400065E0(v21);
sub_140003C80((unsigned int)v25, v15, v16, v7, v8);
v12 = (_BYTE *)sub_140005C00(19LL, 1LL);
*v12 = 41;
v12[1] = 5;
v12[2] = 19;
v12[3] = 12;
v12[4] = -25;
v12[5] = -91;
v12[6] = -46;
v12[7] = -94;
v12[8] = -92;
v12[9] = 58;
v12[10] = 58;
v12[11] = 90;
v12[12] = -69;
v12[13] = 35;
v12[14] = -100;
v12[15] = -28;
v12[16] = -41;
v12[17] = 2;
v12[18] = -65;
sub_140006450(v26, v12, 19LL);
v11 = sub_140005870(v25, v26);
if ( (v11 & 1) != 0 )
{
sub_1400017C0(v27, &off_140021D00);
sub_14000A950(v27);
}
else
{
sub_1400017C0(v28, &off_140021CE0);
sub_14000A950(v28);
}
sub_140001AB0(v26);
sub_140001AB0(v25);
sub_140001AB0(v21);
return sub_140001A70(v18);
}
跟入sub_140003C80,发现while循环存在rc4特征,对输入的密钥做了处理,直接动态调试到while外,v23就是根据密钥生成的S盒(每次都一样)
// Hidden C++ exception states: #wind=4
__int64 *__fastcall sub_140003C80(__int64 *a1, __int64 a2, __int64 a3, __int64 a4, unsigned __int64 a5)
{//...
v38 = -2LL;
v20 = a2;
v21 = a1;
v22 = a1;
LOBYTE(a1) = 0;
LOBYTE(a2) = -1;
v5 = sub_140005120(a1, a2);
v34 = v5;
v35 = BYTE2(v5);
v25 = BYTE2(v5);
v24 = v5;
v37 = BYTE2(v5);
v36 = v5;
sub_140005620(v23, (BYTE2(v5) << 16) | (unsigned int)(unsigned __int16)v5);
v26 = 0;
v27[0] = sub_140006470(0LL, 256LL);
v27[1] = v6;
while ( 1 )
{
v28 = sub_140005440(v27);
v29 = v7;
if ( !v28 )
break;
v17 = v29;
if ( !a5 )
sub_140020930(&off_140021B70);
v15 = *(_BYTE *)(a4 + v29 % a5) ^ 0x66;
v16 = v26;
v11 = *(unsigned __int8 *)sub_1400066C0(v23, v29, &off_140021B88);
v14 = v11 + v16;
if ( __CFADD__(v11, v16) )
sub_1400208B0(&off_140021BA0);
if ( __CFADD__(v15, v14) )
sub_1400208B0(&off_140021BB8);
v26 = (unsigned __int8)(v15 + v14);
v12 = sub_140006680(v23);
sub_1400057D0(v12, v13, v17, v26, (__int64)&off_140021BD0);
}
v30 = 0;
v31 = 0;
v8 = sub_1400057C0(v20, a3);
v33[0] = &v30;
v33[1] = &v31;
v33[2] = v23;
sub_140002200(v32, v8, v9, v33);
sub_140005680(v21, v32);
sub_140001AB0((__int64)v23);
return v22;
}
动调发现sub_140005680的第一个参数就是输出,里面必然有rc4和PRGA操作,直接进去一个个找(动调也可以,一直关注第一个参数a1什么时候变为最终输出)
最终找到如下
char __fastcall sub_140003F40(unsigned __int16 **a1, char *a2)
{//...
v13 = *a2;
v2 = **a1;
if ( __CFADD__(v2, 1) )
sub_1400208B0(&off_140021BE8);
**a1 = (unsigned __int8)(v2 + 1);
v11 = *a1[1];
v3 = *(unsigned __int8 *)sub_1400066C0(a1[2], **a1, &off_140021C00);
if ( __CFADD__(v3, v11) )
sub_1400208B0(&off_140021C18);
*a1[1] = (unsigned __int8)(v3 + v11);
v4 = sub_140006680(a1[2]);
sub_1400057D0(v4, v5, **a1, *a1[1], (__int64)&off_140021C30);
v9 = a1[2];
v10 = *(unsigned __int8 *)sub_1400066C0(v9, **a1, &off_140021C48);
v6 = *(unsigned __int8 *)sub_1400066C0(a1[2], *a1[1], &off_140021C60);
if ( __CFADD__(v6, v10) )
sub_1400208B0(&off_140021C78);
v7 = (_BYTE *)sub_1400066C0(v9, (unsigned __int8)(v6 + v10), &off_140021C90);
return ((((*v7 >> 4) | (16 * *v7)) + 1) ^ v13) + 1;
}
很明显这里v7是PRGA的返回的值,然后做了一定处理在和输入异或再加一,逆向就很简单了
def PRGA(S):
""" Pseudo-Random Generation Algorithm (PRGA) 伪随机数生成算法"""
i, j = 0, 0
while True:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) % 256]
yield K
def RC4(text):
""" RC4 encryption/decryption """
S = [0x0A, 0x14, 0x8C, 0x2C, 0x1E, 0x9A, 0x43, 0xB9, 0x6F, 0x38, 0x39, 0x68, 0x3F, 0x12, 0x36, 0x56, 0x70, 0x31, 0xE4, 0x3C, 0xCB, 0x60, 0x19, 0x4E, 0x10, 0x85, 0xE3, 0xCC, 0xC4, 0x5A, 0x6D, 0x9E, 0x66, 0x7B, 0xE8, 0xF5, 0x74, 0xA9, 0xAA, 0xF1, 0x2B, 0x5D, 0x78, 0xEC, 0x5F, 0x50, 0x05, 0x9D, 0xE7, 0x8A, 0x53, 0x89, 0x4D, 0x21, 0x3D, 0x8F, 0xB0, 0x1C, 0x52, 0xF3, 0x04, 0x35, 0x57, 0xB2, 0xFC, 0x46, 0x33, 0xDE, 0xF6, 0x0E, 0x5B, 0xFD, 0x29, 0x54, 0x51, 0x24, 0x82, 0xA8, 0xC5, 0xCD, 0x93, 0x7F, 0xAC, 0x1F, 0xA1, 0xB1, 0xD5, 0x61, 0xA0, 0x26, 0x6C, 0x67, 0xF2, 0xDC, 0xBB, 0xD6, 0xFF, 0xDD, 0x8B, 0x4C, 0x92, 0x71, 0xC8, 0x99, 0xD2, 0xB7, 0xBF, 0xA5, 0x16, 0x76, 0x87, 0xA2, 0x97, 0x41, 0xD0, 0x9C, 0x63, 0xC0, 0x03, 0x5E, 0x2A, 0x2D, 0xA3, 0x0C, 0xA6, 0x22, 0xAF, 0xD4, 0x64, 0x84, 0xB5, 0xE9, 0x90, 0x79, 0x6B, 0xE5, 0xFA, 0xB3, 0x23, 0x96, 0x59, 0x08, 0x17, 0xE6, 0xFB, 0x91, 0xAD, 0x6E, 0xF8, 0x58, 0x06, 0x9F, 0xCF, 0xCA, 0x5C, 0x0D, 0x9B, 0xD3, 0x95, 0x73, 0xB6, 0x1B, 0x98, 0xE0, 0x37, 0x94, 0x55, 0x7A, 0xE2, 0x2F, 0x72, 0x11, 0x86, 0x15, 0x83, 0x34, 0xC3, 0xAE, 0x49, 0x8D, 0xD9, 0x0F, 0xE1, 0xCE, 0xC2, 0xED, 0x25, 0x88, 0xC1, 0xD1, 0x81, 0xD8, 0x01, 0x2E, 0xEA, 0x20, 0x00, 0xBD, 0xEE, 0xC7, 0xB4, 0xDB, 0xA4, 0x0B, 0xF4, 0xAB, 0x7D, 0xEB, 0x3B, 0x02, 0xC6, 0xEF, 0xFE, 0x27, 0x09, 0x32, 0xF7, 0x47, 0x30, 0x44, 0x4F, 0x13, 0x77, 0x07, 0x18, 0x65, 0x7C, 0xBC, 0x40, 0xF0, 0x28, 0xD7, 0x4B, 0x3E, 0x1D, 0xB8, 0x42, 0xDF, 0x48, 0x3A, 0x69, 0xF9, 0x8E, 0x75, 0xDA, 0x4A, 0x45, 0xBE, 0x1A, 0x80, 0xBA, 0x6A, 0xA7, 0xC9, 0x62, 0x7E]
keystream = PRGA(S)
res = []
for char in text:
tmp = next(keystream)
tmp = (tmp << 4) | (tmp >> 4)
tmp += 1
tmp &= 0xff
res.append(((char-1) ^ tmp))
return bytes(res)
text = [0x29, 0x05, 0x13, 0x0C, 0xE7, 0xA5, 0xD2, 0xA2, 0xA4, 0x3A, 0x3A, 0x5A, 0xBB, 0x23, 0x9C, 0xE4, 0xD7, 0x02, 0xBF]
print(f"flag{{{RC4(text).decode()}}}")
flag{Y0uKn0wRu5tV@ryW@1l}
go for it
算法相比Rust好分析多了
// main.main
void __fastcall main_main()
{//...
p_string = (string *)runtime_newobject(&RTYPE_string);
v75 = p_string;
p_string->ptr = 0LL;
v78[0] = &RTYPE__ptr_string;
v78[1] = p_string;
v2 = qword_567068;
fmt_Fscanf(
(unsigned int)go_itab__ptr_os_File_comma__ptr_io_Reader,
qword_567068,
(unsigned int)"%s",
2,
(unsigned int)v78,
1,
1,
v3,
v4);
if ( v2 || v75->len != 32 )
goto LABEL_4;
v70 = v0;
v71 = v0;
ptr = (unsigned __int64)v75->ptr;
v10 = runtime_stringtoslicebyte(
(unsigned int)&v69,
v75->ptr,
v75->len,
(unsigned int)&v71,
(unsigned int)&v70,
v5,
v6,
v7,
v8);
v73 = v10;
v66 = ptr;
v67 = v11;
v16 = 0LL;
while ( (__int64)ptr > v16 )
{
v17 = v16;
while ( v16 < (__int64)(v17 + 4) )
{
if ( ptr <= v16 )
runtime_panicIndex(v16, ptr, ptr);
v43 = *(unsigned __int8 *)(v16 + v10);
if ( ptr <= v16 + 2 )
runtime_panicIndex(v16 + 2, ptr, ptr);
v44 = v43 ^ *(unsigned __int8 *)(v16 + v10 + 2);
*(_BYTE *)(v10 + v16) = v43 ^ *(_BYTE *)(v16 + v10 + 2);
if ( ptr <= v16 + 1 )
runtime_panicIndex(v16 + 1, ptr, ptr);
LODWORD(cap) = v44 ^ *(unsigned __int8 *)(v16 + v10 + 2);
v42 = cap ^ *(unsigned __int8 *)(v16 + v10 + 1);
*(_BYTE *)(v16 + v10 + 1) ^= (unsigned __int8)v44 ^ *(_BYTE *)(v16 + v10 + 2);
v12 = v42 ^ *(unsigned __int8 *)(v16 + v10 + 2);
*(_BYTE *)(v16 + v10 + 2) ^= v42;
v16 += 3LL;
}
v79 = 0;
v80 = 0LL;
v81 = v0;
v18 = 0LL;
v19 = (_QWORD *)math_big__ptr_Int_SetInt64(
(unsigned int)&v79,
0,
v11,
(int)v17 + 4,
v17,
v12,
cap,
v14,
v15,
v51,
v55);
v20 = v17;
v21 = v17 + 8;
if ( v67 < v17 + 8 )
runtime_panicSliceAcap(v19, 0LL, v17 + 8);
if ( v17 > v21 )
goto LABEL_47;
v72 = v19;
v22 = (v17 & ((__int64)(v17 - v67) >> 63)) + v73;
v23 = v19[2];
v24 = math_big_nat_setBytes(
v19[1],
v23,
v19[3],
v22,
8,
(int)v67 - (int)v17,
(int)v67 - (int)v17,
v73,
v19[1],
v52,
v56,
v58,
v60,
v62,
v64);
v25 = v72;
v72[2] = v23;
v25[3] = v26;
if ( dword_5BBB30 )
{
LODWORD(v22) = (_DWORD)v25 + 8;
runtime_gcWriteBarrier(v25 + 1);
}
else
{
v25[1] = v24;
}
*(_BYTE *)v25 = 0;
if ( v25[2] )
v27 = *(_QWORD *)v25[1];
else
v27 = 0LL;
for ( i = 0LL; i < 64; ++i )
{
if ( v27 < 0 )
v27 = (2 * v27) ^ 0x2EF20D07161E85F7LL;
else
v27 *= 2LL;
}
v65 = v27;
p_bytes_Buffer = (bytes_Buffer *)runtime_newobject(&RTYPE_bytes_Buffer);
v34 = runtime_convT64(v65, v23, v29, v22, 8, v30, v31, v32, v33, v53);
v18 = p_bytes_Buffer;
v38 = encoding_binary_Write(
(unsigned int)go_itab__ptr_bytes_Buffer_comma__ptr_io_Writer,
(_DWORD)p_bytes_Buffer,
(unsigned int)go_itab__ptr_binary_littleEndian_comma__ptr_binary_ByteOrder,
(unsigned int)&unk_5BBAD8,
(unsigned int)&RTYPE_int64,
v34,
v35,
v36,
v37,
v54,
v57,
v59,
v61,
v63,
v64);
if ( v38 )
{
runtime_gopanic(
*(_QWORD *)(v38 + 8),
(_DWORD)v18,
v39,
(unsigned int)&unk_5BBAD8,
(unsigned int)&RTYPE_int64,
v12,
cap,
v14,
v15,
v51,
v55);
LABEL_47:
runtime_panicSliceB(v20, v18, v21);
}
v40 = p_bytes_Buffer;
for ( j = 0LL; j < 8; ++j )
{
for ( k = 0LL; k < 8; ++k )
{
len = v40->buf.len;
cap = v40->buf.cap;
off = v40->off;
if ( off > len )
runtime_panicSliceB(v40->off, v18, v40->buf.len);
v48 = len - off;
v14 = (__int64)(off - cap) >> 63;
v15 = v14 & v40->off;
if ( k >= v48 )
runtime_panicIndex(k, v18, v48);
v18 = (bytes_Buffer *)k;
v12 = -128;
LOBYTE(v12) = 0x80u >> j;
if ( ((0x80u >> j) & __ROL1__(v40->buf.ptr[v15 + k], 5)) != 0 )
{
v49 = j + v17;
if ( j + v17 >= 0x20 )
runtime_panicIndex(j + v17, k, 32LL);
v12 = *((unsigned __int8 *)&v70 + v49);
v50 = -128;
LOBYTE(v50) = 0x80u >> k;
LODWORD(cap) = v12 | v50;
*((_BYTE *)&v70 + v49) = cap;
}
}
}
v10 = v73;
ptr = v66;
v16 = v17 + 8;
LODWORD(v11) = v67;
}
v68[0] = 0x8ADD5C04E5934C8LL;
v68[1] = 0x199AC0E6DA4C2BC9LL;
v68[2] = 0xFF83F5E87D5510B5LL;
v68[3] = 0x58447D6AD4E38B74LL;
if ( (unsigned __int8)runtime_memequal(&v70, v68, 32LL) )
{
v77[0] = &RTYPE_string;
v77[1] = &off_4DE248;
fmt_Fprintln(
(unsigned int)go_itab__ptr_os_File_comma__ptr_io_Writer,
qword_567070,
(unsigned int)v77,
1,
1,
v5,
v6,
v7,
v8,
v51,
v55,
v58,
v60,
v62);
}
else
{
LABEL_4:
v76[0] = &RTYPE_string;
v76[1] = &off_4DE258;
fmt_Fprintln(
(unsigned int)go_itab__ptr_os_File_comma__ptr_io_Writer,
qword_567070,
(unsigned int)v76,
1,
1,
v5,
v6,
v7,
v8,
v51,
v55,
v58,
v60,
v62);
}
}
- 首先输入长度32的字符串
- 然后每8位字符一组(v17+8)前6个字符每3个字符做一轮异或处理,还原比较复杂需要认真分析
- 然后处理完的8字节转为int数做了64轮crc64加密((2 * v27) ^ 0x2EF20D07161E85F7LL)
- 双层8*8循环先把每个字符循环左移5位,然后转置读取比特,读出新的8字节
- runtime_memequal比较4组8字节,即32字节
按步骤逆向即可,注意端序,多调试检查输入输出就好
from Crypto.Util.number import bytes_to_long
def transpose_bytes8x8(block):
# 先把 block 解开成 8×8 位矩阵 bits[row][col]
bits = [[(block[row] >> (7 - col)) & 1 for col in range(8)]
for row in range(8)]
# 转置后按行重组,每行 8 个 bit 合成一个字节
transposed = []
for new_row in range(8):
byte = 0
for new_col in range(8):
byte = (byte << 1) | bits[new_col][new_row]
transposed.append(byte)
return bytes(transposed)
s = ["08ADD5C04E5934C8", "199AC0E6DA4C2BC9", "FF83F5E87D5510B5", "58447D6AD4E38B74"]
for i in range(len(s)):
s[i] = transpose_bytes8x8(bytes.fromhex(s[i])[::-1])
ss = []
for i in s:
ss += list(i)
for i in range(len(ss)):
ss[i] = (ss[i] << 3) | (ss[i] >> 5)
ss[i] &= 0xff
s = [bytes_to_long(bytes(ss[i:i+8][::-1])) for i in range(0, len(ss), 8)]
new_s = []
for v in s:
for i in range(64):
bit = v & 1
if bit:
v ^= 0x2EF20D07161E85F7
v >>= 1
if bit:
v |= 0x8000000000000000
new_s.append(v)
s = []
for i in new_s:
tmp = list(i.to_bytes(8, byteorder='big'))
flag = [0] * 8
for i in range(0, 6, 3):
flag[i+2] = tmp[i+2] ^ tmp[i+1]
flag[i] = tmp[i] ^ flag[i+2]
flag[i+1] = tmp[i+1] ^ flag[i]
flag[6] = tmp[6]
flag[7] = tmp[7]
print("".join(map(chr, flag)), end="")
flag{5e28e27a835c4958b2d6dd186b21727a}
Misc
只做了一道,学点新知识
有一种二维码叫data matrix,https://zxing.org/w/decode.jspx可以解密
解密出来再base85得到UV!W_X_YZ,U,Y∈[0,9], V,W,X,Z∈[A,z]
这个是提示要用掩码来爆破zip