go_go_go!
下载附件,似乎得到一个linux二进制可执行文件
直接丢进IDA

找到main

已经能看到 Go 的启动入口 rt0_amd64_linux → runtime_rt0_go。C 语言或汇编仅仅在做引导工作,真正的业务逻辑在 Go 运行时初始化之后。

这才是真正的入口
// main.main
void __fastcall main_main()
{
string *p_string; // rax
int v1; // r8d
int v2; // r9d
int v3; // r10d
int v4; // r11d
char *ptr; // rbx
int v6; // r8d
int v7; // r9d
int v8; // r10d
int v9; // r11d
__int64 v10; // rax
int v11; // r8d
int v12; // r9d
int v13; // r10d
int v14; // r11d
__int64 i; // rcx
unsigned __int64 j; // rcx
__int64 v17; // [rsp-2Ch] [rbp-A8h]
__int64 v18; // [rsp-24h] [rbp-A0h]
__int64 v19; // [rsp-1Ch] [rbp-98h]
__int64 v20; // [rsp+1h] [rbp-7Bh]
_BYTE v21[11]; // [rsp+9h] [rbp-73h]
__int64 v22; // [rsp+14h] [rbp-68h]
char v23; // [rsp+1Ch] [rbp-60h] BYREF
string *v24; // [rsp+3Ch] [rbp-40h]
_QWORD v25[2]; // [rsp+44h] [rbp-38h] BYREF
_QWORD v26[2]; // [rsp+54h] [rbp-28h] BYREF
_QWORD v27[2]; // [rsp+64h] [rbp-18h] BYREF
p_string = (string *)runtime_newobject(&RTYPE_string); //初始化
v24 = p_string;
p_string->ptr = 0LL;
v27[0] = &RTYPE__ptr_string;
v27[1] = p_string;
fmt_Fscan((unsigned int)off_4C2008, qword_5371C8, (unsigned int)v27, 1, 1, v1, v2, v3, v4); //获取输入
ptr = v24->ptr;
v10 = runtime_stringtoslicebyte((unsigned int)&v23, v24->ptr, v24->len, 1, 1, v6, v7, v8, v9); //逐字符切片
for ( i = 0LL; (__int64)ptr > i; ++i )
*(_BYTE *)(v10 + i) = (*(_BYTE *)(i + v10) + 2) ^ 0x23; //每个字符ascii+2 并且与0x23抑或计算
v20 = 0x114A5E776065687BLL;
*(_DWORD *)v21 = 1108429378;
*(_QWORD *)&v21[3] = 0x4245534042114A42LL;
v22 = 0x5C445657165B4457LL; //这里 v20, v21, v22 拼起来就是一个长度为 0x1B (27) 的固定字节序列 targetBytes
for ( j = 0LL; (__int64)ptr > (__int64)j; ++j )
{
if ( j >= 0x1B )
runtime_panicIndex(j, ptr, 27LL);
v11 = (unsigned __int8)v21[j - 8];
if ( (_BYTE)v11 != *(_BYTE *)(j + v10) )
{
v26[0] = &RTYPE_string;
v26[1] = &off_4C1B68;
fmt_Fprintln((unsigned int)off_4C2028, qword_5371D0, (unsigned int)v26, 1, 1, v11, v12, v13, v14, v17, v18, v19);
return;
}
}
v25[0] = &RTYPE_string;
v25[1] = &off_4C1B78;
fmt_Fprintln((unsigned int)off_4C2028, qword_5371D0, (unsigned int)v25, 1, 1, v11, v12, v13, v14, v17, v18, v19);
}
这里要对v21处理一下


payload
"""
根据 Go 程序 main.main 里的校验逻辑:
(input[i] + 2) ^ 0x23 == target[i]
得出反推公式:
input[i] = (target[i] ^ 0x23) - 2
"""
# v20 (8 bytes)
v20 = [0x11, 0x4A, 0x5E, 0x77, 0x60, 0x65, 0x68, 0x7B]
# v21 (11 bytes) —— 根据分析已经推复原为:
v21 = [0x42, 0x4A, 0x11, 0x42, 0x4A, 0x11, 0x42, 0x40, 0x53, 0x45, 0x42]
# v22 (8 bytes)
v22 = [0x5C, 0x44, 0x56, 0x57, 0x16, 0x5B, 0x44, 0x57]
target = v20 + v21 + v22
assert len(target) == 27
decoded_bytes = [ (b ^ 0x23) - 2 for b in target ]
decoded_str = ''.join(chr(x & 0xFF) for x in decoded_bytes)
print(f"[+] Target bytes : {target}")
print(f"[+] Decoded flag : {decoded_str}")
得到0g{RADIV_g0_g0_and_}esr3ver
变形一下
VIDAR{g0_g0_g0_and_rev3rse}
正文完