这道逆向题我已经解出flag了,根据我的动态调试,程序并不检查1-5以及最后一字节内容,只检查6-2...
Criado em: 24 de março de 2026
Respondido usando GPT-5.4 Thinking por Chat01
Criado em: 24 de março de 2026
Respondido usando GPT-5.4 Thinking por Chat01
这道逆向题我已经解出flag了,根据我的动态调试,程序并不检查1-5以及最后一字节内容,只检查6-27字节
v13 = (_QWORD *)(sub_7FF7699815EB((__int64)flag) + 5);这一行就是把flag的第六字节指针赋值给v13
我输入flag{oh_you_found_our_x3nny1是可以通过检查的,这很奇怪,我看代码,对第28字节是有检查的呀:
debug034:000001D23D75A980 sub_1D23D75A980 proc near
debug034:000001D23D75A980
debug034:000001D23D75A980 var_20 = qword ptr -20h
debug034:000001D23D75A980
debug034:000001D23D75A980 sub rsp, 20h
debug034:000001D23D75A984 mov [rsp+20h+var_20], rcx
debug034:000001D23D75A988 mov r10d, 7C072E27h
debug034:000001D23D75A98E xor r10d, 12345678h
debug034:000001D23D75A995 mov edi, dword ptr [rsp+20h+var_20]
debug034:000001D23D75A998 cmp edi, r10d
debug034:000001D23D75A99B jnz short loc_1D23D75A9BB
debug034:000001D23D75A99D mov edi, dword ptr [rsp+20h+var_20+4]
debug034:000001D23D75A9A1 mov r10d, 87653A4Fh
debug034:000001D23D75A9A7 xor r10d, 87654321h
debug034:000001D23D75A9AE cmp edi, r10d
debug034:000001D23D75A9B1 jnz short loc_1D23D75A9BB
debug034:000001D23D75A9B3 xor rax, rax
debug034:000001D23D75A9B6 add rsp, 20h
debug034:000001D23D75A9BA retn
debug034:000001D23D75A9BB ; ---------------------------------------------------------------------------
debug034:000001D23D75A9BB
debug034:000001D23D75A9BB loc_1D23D75A9BB: ; CODE XREF: sub_1D23D75A980+1B↑j
debug034:000001D23D75A9BB ; sub_1D23D75A980+31↑j
debug034:000001D23D75A9BB add rsp, 20h
debug034:000001D23D75A9BF xor rax, rax
debug034:000001D23D75A9C2 sub rax, 1
debug034:000001D23D75A9C6 retn
debug034:000001D23D75A9C6 sub_1D23D75A980 endp
解释一下
pythonprint(hex(0x7C072E27 ^ 0x12345678)) print(hex(0x87653A4F ^ 0x87654321))
pythons='flag{oh_you_found_our_x3nny1' print(len(s)) for i,ch in enumerate(s,1): print(i,ch)
你这段代码的关键误区有两个:
v13 当成了字节指针在看其实按你贴的汇编,这个函数本身更像是在比较传入参数 rcx 这个 64 位值本身,而不是比较 rcx 指向的 flag 内容。
asmsub rsp, 20h mov [rsp+20h+var_20], rcx mov r10d, 7C072E27h xor r10d, 12345678h mov edi, dword ptr [rsp+20h+var_20] cmp edi, r10d jnz short loc_1D23D75A9BB mov edi, dword ptr [rsp+20h+var_20+4] mov r10d, 87653A4Fh xor r10d, 87654321h cmp edi, r10d jnz short loc_1D23D75A9BB xor rax, rax ...
先把常量算出来:
0x7C072E27 ^ 0x12345678 = 0x6E33785F0x87653A4F ^ 0x87654321 = 0x0000796E所以实际比较的是:
clow32 == 0x6E33785F high32 == 0x0000796E
*rcx这两句非常关键:
asmmov [rsp+20h+var_20], rcx mov edi, dword ptr [rsp+20h+var_20]
[rsp+20h+var_20] 这个位置,是局部变量 var_20,里面存的是 rcx 本身。
也就是说它等价于:
ctmp = rcx; if ( *(DWORD*)&tmp != 0x6E33785F ) fail; if ( *((DWORD*)&tmp + 1) != 0x0000796E ) fail;
而不是:
cif ( *(DWORD*)rcx != ... ) if ( *(DWORD*)(rcx+4) != ... )
这俩差别非常大。
它比较的是 传入参数 rcx 这个 64 位数值 的低 4 字节和高 4 字节。
如果把这 8 个字节按小端看:
0x6E33785F -> 5F 78 33 6E -> "_x3n"0x0000796E -> 6E 79 00 00 -> "ny\0\0"拼起来是:
text"_x3nny\0\0"
但注意,这里只是说:
如果把 rcx 当成 8 字节数据来看,它长得像
_x3nny\0\0
这不等于“程序在检查 flag 的后 8 个字符”。
因为很可能最后这段并没有真的在检查 flag 内容。
你现在的动态结果其实很有说服力:
flag{oh_you_found_our_x3nny11 没被有效校验这和你贴的这段汇编并不矛盾,反而说明:
这段函数检查的根本不是“第 28 字节是不是某个值”,而是调用时传进去的 rcx 值。
v13 是 _QWORD *你前面说:
cv13 = (_QWORD *)(sub_xxx((__int64)flag) + 5);
这句确实是把 flag + 5 赋给了 v13,也就是指向第 6 个字节。
但因为它的类型是 _QWORD *,所以后面如果出现:
cv13 + 1
它不是往后走 1 个字节,而是往后走 8 个字节。
也就是:
c(char*)v13 == flag + 5 (char*)(v13 + 1) == flag + 13 (char*)(v13 + 2) == flag + 21
所以反编译伪代码里一旦混了 _QWORD *、_DWORD *,偏移很容易被你“脑补成字符下标”,最后就会误以为它在查第 28 字节。
结合你的动态结果,我觉得大概率是下面两种之一:
也就是传进去的是某个指针,函数只是在比这个指针的数值,和 flag 字符内容无关。
这种情况下,你看到的 _x3nny 只是地址低字节碰巧被构造成这样,或者是出题人故意混淆。
也许你以为传进去的是“flag 后面 8 字节”,但实际上 caller 传的是:
这就会导致你静态看着像“检查第 28 字节”,动态却发现“最后一字节不参与”。
你去看这段函数的调用点,只要看 rcx 是怎么来的就行:
asmlea rcx, [something] call sub_1D23D75A980
那传进去的是地址,函数比较的是地址值,不是内容。
asmmov rcx, [something] call sub_1D23D75A980
那传进去的是8 字节数据本身,这时才是在比内容。
这个判断一锤定音。
你这段汇编里:
v13 被反编译成了 _QWORD *rcx所以你的动态结果“只检查 6–27 字节,最后一字节不检查”是完全说得通的。
把话说得更直接一点:
你贴的这段代码,看上去像在查
_x3nny,实际上大概率没在查 flag 的最后一个字符。
你要是把这段函数的调用点前后 10 来条汇编也贴出来,我可以直接帮你把 rcx 到底是“指针”还是“8 字节内容”给你定死。