-
-
[原创] 看雪 2024 KCTF 大赛 第六题 异星文明
-
发表于: 2024-8-28 07:12 3740
-
又是这种加混淆的题目……做起来体验感真的几乎为零
现在看到用“规则二”出的题有点PTSD了,期望第七题缓一缓
(本题是晚上回家看到一血只用了5个多小时才敢尝试的;另外, 此时做题速度已经不重要了,因为按照现行的计分,除非贴着一血的时间交题,否则非一血无论如何都只能拿到一半多一点的分数)
(建议把题目使用了规则一还是二与题目分类写在一起尽早公开,这样开赛前好提早有心理准备)
目前的“规则二”要求出题人公开混淆脚本确实不错,但是作为攻击方,相对于加混淆的方法,更希望看到的是出题人自己的去混淆脚本(简单的说,防守方不能只管出不管做)
顺便,继续等待第三题出题人发布自己的去混淆脚本的那一天
先对题目做一些初始探索
静态分析,从start函数开始,进入 sub_140108580 ,然后是 sub_140108000 (位于zxvmp1区段),里面有一个大循环,未被混淆的代码差不多只有这些,另外多出来的有zxvmp开头的几个区段。导入表只有少量函数,而且无法直接找到交叉引用。
动态分析,修改exe头关闭dynamic base,然后上x64dbg调试,在调试器环境下输入公开的name-serial能正常通过,是个好消息,至少题目没有埋暗坑。
观察导入表的函数,猜测程序会通过GetWindowTextW函数获取输入框的值。下个断点观察调用栈和返回地址,向上找几层找到调用来源是0x140108207(位于sub_140108000的一个分支中)
0x140108207是 ((void (*)(void))v12->field_A8)();
间接调用,在这里下断点然后单步进入,发现总是会调用一个导入表的函数。
回到GetWindowTextW,这个函数被调用了两次,分别对应两个输入框的值。在第二次调用到的时候,对第一个参数的内存下硬件数据读取断点,继续执行,程序停在了0x140114994(movzx eax, word ptr [rax+rcx*2]
),这里是访问输入的serial的地方。
继续执行会返回到0x14010825D(sub_140108000中调用sub_1401085FB的下一行),但调用栈里却没有发现。
调试sub_1401085FB,发现它的ret并不是返回到调用处,而是会每次进入zxvmp3区段的一个不同的位置(例如刚才提到的0x140114993),直到再一次ret才会回到真正的调用点。
至此可以确定,sub_140108000是虚拟机的主循环,下方的两个分支,v12->field_A8)()
的间接调用用于导入表函数,sub_1401085FB
用于执行虚拟机指令。sub_14010848F总是返回常量0x140006000(zxvmp0区段的起始地址),保存着虚拟机的各种状态,巨大的for循环用于寻找下一条虚拟机指令。
虚拟机循环和状态储存看起来很有规律,但是先不花费精力去分析。根据上面的分析,只要在0x1401086C2(即sub_1401085FB函数最后ret指令)处下断点,单步一次即可进入zxvmp3区段的虚拟机指令块处。
人工观察这些虚拟机指令块,发现具有明显的规律:总是以popfq
开头,然后跟着一句看起来很正常的指令,然后是pushfq
(也有一些地方没有中间的指令)
继续跟踪几轮,把中间这句看着很正常的指令连起来,得到的代码非常顺眼,具有明显的编译器生成的特征。由此可以得出结论,程序的混淆并没有改变原始指令,只是把指令拆散分布到各处,然后由sub_140108000的循环不断寻找并执行。
不由想起了KCTF2021春季赛的第七题,也是类似这样把真实指令混在垃圾指令之间,不过那题用了SMC自解密而且真实指令周围没有太明显的特征,相比之下本题做追踪简单多了
将以上过程自动化,首先是一小段x64dbg脚本,作用是找到sub_1401085FB函数最后ret指令(0x1401086C2)每次跳转到的位置并记录下来:
(p.s. 一开始让chatgpt GPT-4o帮忙写,结果x64dbg不停的报错。需要严谨的场景,个人还是更信任文档而不是生成式AI)
注意实施细节:
x64dbg的“脚本”窗口‘右键-载入脚本-粘贴’可以快速放入脚本,脚本的输出展示在x64dbg的“日志”窗口
“日志”窗口‘右键-重定向日志输出’可以指定一个文件
由于是GUI程序且各种界面的事件处理函数也被混淆了,因此如果一开始就启用脚本,UI会爆卡。我们只关心数据处理的部分,点击界面按钮后可以先断点在GetWindowTextW函数,然后再启用脚本,后续就不会被UI事件影响了。
这段trace脚本要跑若干分钟(不知道是“日志”窗口刷屏的原因还是调试器频繁中断的原因,应该怎样做才能加速呢……),得到的日志文件有4w多行。筛除无关信息,只保留log {[rsp]}
记录的地址,只剩下18832行,而且可见的有大段循环重复。(见附件 trace_output_filtered.txt )
继续,写一个脚本将trace到的位置的指令提取出来(检查第一条指令是popfq
,然后提取它后面的第二条指令,并检查第三条指令是pushfq
)
(p.s. capstone的用法来自chatgpt GPT-4o,不想查文档了)
忽略重复的地址,得到的输出(见附件disasm_output2.txt)只有386行。
将这些指令拼成一个二进制用IDA打开看看:
能比较直观的看到开头部分对serial的hexdecode;但是,由于上面的脚本没有处理好基本块之间的跳转关系,丢失了循环,所以对serial具体处理不能直接照抄(最开始没意识到,被坑了很久),但基本逻辑可以用来对照参考
(p.s. 处理循环应该不难(但可能比较复杂):每个地址可以当作只包含一条指令的基本块,那么根据trace结果,相邻的两行地址即为程序中记录过的执行转移,可以作为基本块的连接。做完所有基本块的连接后,修正条件跳转指令即可生成一个真正逻辑正确的二进制文件)
鉴于不重复的汇编指令只有386条,人工处理也许效率更高。
根据trace,汇编指令大致分为4个部分
第一部分:是一个循环,循环节如下(即:0x3d8后会jmp回0x336)
结合调试,栈上的几个变量如下:
虽然不长,但看汇编还是有点难受。IDA给出的结果一般:
这里chatgpt GPT-4o的表现反而很不错,经过几轮交互要求它简化代码后给出的结果(需要人工调试验证,但从最终的分析看,基本是正确的)(变量vx代表[rsp+x])
第二部分:(不是循环)
第三部分:(另一个循环,逻辑与之前差不多)
第四部分:(不是循环)
省略过程,直接给出整理后的最终代码和逆向逻辑:
最终的答案:
name: KCTF
serial: 901AB07A40D87A7B96ED4B0420EA2B552C9E12C71F9E967E5BEA37A83BC79E1F
在调试过程中遇到了一个奇怪的问题不知道是什么原因:
过滤后的汇编,有一行是0x31f 0x140110a0f: mov dword ptr [rsp], eax
,只要在0x140110a0f下软件断点,此句执行后[rsp]保存的值就会不等于eax,而在其他地方下断点(例如前一句的0x140110a0e)则不会有问题。
具体操作:0. patch exe头禁用dynamic base 1. x64dbg (2024 Aug 5版本) 加载进程 2. cpu窗口定位到0x140110a0f,按F2下一个断点 3. 按F9运行,输入提供的name和serial,点击按钮 4. 程序停止在0x140110a0f,注意到此时rax是000000005A5F2142
5. 按F7单步执行,然后发现[rsp]
0000000140085E08
处的内存变为了D1D2F49F5A5F2042
,即eax的5A5F2142
在执行mov dword ptr [rsp], eax
后进入内存变为了5A5F2042
,有一个bit改变了
__int64
__usercall sub_140108000@<rax>(
__int32
a1@<edx>,
unsigned
__int64
a2@<rcx>,
__int64
a3@<rbx>,
__int64
a4@<rbp>,
__int64
a5@<rdi>,
__int64
a6@<rsi>,
__int64
a7@<r12>,
__int64
a8@<r13>,
__int64
a9@<r14>,
__int64
a10@<r15>)
{
__int64
result;
// rax
char
*v11;
// rax
struct
machine *v12;
// rax
struct
machine *v13;
// [rsp+20h] [rbp-78h]
__int32
v14;
// [rsp+28h] [rbp-70h]
unsigned
__int64
i;
// [rsp+30h] [rbp-68h]
unsigned
int
v16;
// [rsp+38h] [rbp-60h]
struct
instruction *current_inst;
// [rsp+40h] [rbp-58h]
__int64
v18;
// [rsp+48h] [rbp-50h]
char
*v19;
// [rsp+58h] [rbp-40h]
unsigned
__int64
v20;
// [rsp+60h] [rbp-38h]
__int64
v21;
// [rsp+70h] [rbp-28h]
__int64
v22;
// [rsp+80h] [rbp-18h]
v13 = sub_14010848F();
// it always return constant value 0x140006000
current_inst = v13->current_inst;
v13->field_D8 = a1;
v19 = &sub_140108370()[current_inst->field_10];
for
( i = a2; ; i += 4LL )
{
result = current_inst->field_18;
if
( i == result )
break
;
v16 = *(_DWORD *)&v19[i];
if
( v13->field_D4 )
{
i = sub_1401083D0(current_inst, v13->field_D0, v13->field_DC);
v16 = *(_DWORD *)&v19[i];
v13->field_D4 = 0;
v14 = v13->field_DC;
}
else
if
( v13->field_D8 )
{
v14 = v13->field_D8;
v13->field_D8 = 0;
}
else
{
v14 = *(_DWORD *)v13->maybe_rsp;
v13->maybe_rsp += 8LL;
}
v20 = current_inst->field_28 / 12uLL;
v11 = sub_140108370();
v18 = sub_1401082A0(&v11[current_inst->field_20], v14 ^ v16, 0LL, (unsigned
int
)v20);
if
( (v18 & 0x4000000000000000LL) != 0 )
{
v21 = sub_1401083A0() + (v18 & 0xBFFFFFFFFFFFFFFFuLL);
sub_14010848F()->field_A8 = v21;
v12 = sub_14010848F();
((
void
(*)(
void
))v12->field_A8)();
}
else
{
v22 = sub_1401083A0() + (v18 & 0x7FFFFFFFFFFFFFFFLL);
sub_14010848F()->field_A8 = v22;
sub_1401085FB(a3, a4, a5, a6, a7, a8, a9, a10);
if
( v18 < 0 )
return
v13->field_B0;
}
}
return
result;
}
__int64
__usercall sub_140108000@<rax>(
__int32
a1@<edx>,
unsigned
__int64
a2@<rcx>,
__int64
a3@<rbx>,
__int64
a4@<rbp>,
__int64
a5@<rdi>,
__int64
a6@<rsi>,
__int64
a7@<r12>,
__int64
a8@<r13>,
__int64
a9@<r14>,
__int64
a10@<r15>)
{
__int64
result;
// rax
char
*v11;
// rax
struct
machine *v12;
// rax
struct
machine *v13;
// [rsp+20h] [rbp-78h]
__int32
v14;
// [rsp+28h] [rbp-70h]
unsigned
__int64
i;
// [rsp+30h] [rbp-68h]
unsigned
int
v16;
// [rsp+38h] [rbp-60h]
struct
instruction *current_inst;
// [rsp+40h] [rbp-58h]
__int64
v18;
// [rsp+48h] [rbp-50h]
char
*v19;
// [rsp+58h] [rbp-40h]
unsigned
__int64
v20;
// [rsp+60h] [rbp-38h]
__int64
v21;
// [rsp+70h] [rbp-28h]
__int64
v22;
// [rsp+80h] [rbp-18h]
v13 = sub_14010848F();
// it always return constant value 0x140006000
current_inst = v13->current_inst;
v13->field_D8 = a1;
v19 = &sub_140108370()[current_inst->field_10];
for
( i = a2; ; i += 4LL )
{
result = current_inst->field_18;
if
( i == result )
break
;
v16 = *(_DWORD *)&v19[i];
if
( v13->field_D4 )
{
i = sub_1401083D0(current_inst, v13->field_D0, v13->field_DC);
v16 = *(_DWORD *)&v19[i];
v13->field_D4 = 0;
v14 = v13->field_DC;
}
else
if
( v13->field_D8 )
{
v14 = v13->field_D8;
v13->field_D8 = 0;
}
else
{
v14 = *(_DWORD *)v13->maybe_rsp;
v13->maybe_rsp += 8LL;
}
v20 = current_inst->field_28 / 12uLL;
v11 = sub_140108370();
v18 = sub_1401082A0(&v11[current_inst->field_20], v14 ^ v16, 0LL, (unsigned
int
)v20);
if
( (v18 & 0x4000000000000000LL) != 0 )
{
v21 = sub_1401083A0() + (v18 & 0xBFFFFFFFFFFFFFFFuLL);
sub_14010848F()->field_A8 = v21;
v12 = sub_14010848F();
((
void
(*)(
void
))v12->field_A8)();
}
else
{
v22 = sub_1401083A0() + (v18 & 0x7FFFFFFFFFFFFFFFLL);
sub_14010848F()->field_A8 = v22;
sub_1401085FB(a3, a4, a5, a6, a7, a8, a9, a10);
if
( v18 < 0 )
return
v13->field_B0;
}
}
return
result;
}
bp
1401086c2
mainloop:
log {[rsp]}
run
goto mainloop
bp
1401086c2
mainloop:
log {[rsp]}
run
goto mainloop
from
capstone
import
*
md
=
Cs(CS_ARCH_X86, CS_MODE_64)
def
v2f(v):
# virtual address to file offset
return
v
-
(
0x14010c000
-
0x7a00
)
def
f2v(f):
return
f
+
(
0x14010c000
-
0x7a00
)
with
open
(
"fzbz.exe"
,
"rb"
) as f:
content
=
f.read()
with
open
(
"trace_output_filtered.txt"
,
"r"
) as f:
lines
=
f.readlines()
addrs
=
[
int
(line,
16
)
for
line
in
lines]
insts_bytes
=
b""
all_insts
=
[]
insts_map
=
{}
next_block_map
=
{}
last_addr
=
-
1
for
addr
in
addrs:
if
addr
in
insts_map:
next_block_map.setdefault(last_addr,
set
()).add(addr)
continue
code
=
content[v2f(addr):v2f(addr)
+
45
]
insns
=
list
(md.disasm(code, addr))[:
3
]
if
not
(insns[
0
].mnemonic
=
=
"popfq"
):
print
(f
"0x{insns[0].address:x}: what"
)
else
:
insn
=
insns[
1
]
if
insn.mnemonic
=
=
"pushfq"
:
continue
text
=
f
"0x{insn.address:x}:\t{insn.mnemonic}\t{insn.op_str}"
all_insts.append((addr,
len
(insts_bytes), text))
insts_map[addr]
=
text
next_block_map.setdefault(last_addr,
set
()).add(addr)
insts_bytes
+
=
code[insn.address
-
addr:insn.address
-
addr
+
insn.size]
last_addr
=
addr
print
(text)
with
open
(
"disasm_output2.txt"
,
"w"
) as f:
for
addr, offset, inst_text
in
all_insts:
f.write(f
"0x{offset:x}\t{inst_text}"
.ljust(
64
)
+
"\t"
+
str
(
list
(
map
(
hex
, next_block_map.get(addr,
set
()))))
+
"\n"
)
with
open
(
"insts_bytes_1.bin"
,
"wb"
) as f:
f.write(insts_bytes)
from
capstone
import
*
md
=
Cs(CS_ARCH_X86, CS_MODE_64)
def
v2f(v):
# virtual address to file offset
return
v
-
(
0x14010c000
-
0x7a00
)
def
f2v(f):
return
f
+
(
0x14010c000
-
0x7a00
)
with
open
(
"fzbz.exe"
,
"rb"
) as f:
content
=
f.read()
with
open
(
"trace_output_filtered.txt"
,
"r"
) as f:
lines
=
f.readlines()
addrs
=
[
int
(line,
16
)
for
line
in
lines]
insts_bytes
=
b""
all_insts
=
[]
insts_map
=
{}
next_block_map
=
{}
last_addr
=
-
1
for
addr
in
addrs:
if
addr
in
insts_map:
next_block_map.setdefault(last_addr,
set
()).add(addr)
continue
code
=
content[v2f(addr):v2f(addr)
+
45
]
insns
=
list
(md.disasm(code, addr))[:
3
]
if
not
(insns[
0
].mnemonic
=
=
"popfq"
):
print
(f
"0x{insns[0].address:x}: what"
)
else
:
insn
=
insns[
1
]
if
insn.mnemonic
=
=
"pushfq"
:
continue
text
=
f
"0x{insn.address:x}:\t{insn.mnemonic}\t{insn.op_str}"
all_insts.append((addr,
len
(insts_bytes), text))
insts_map[addr]
=
text
next_block_map.setdefault(last_addr,
set
()).add(addr)
insts_bytes
+
=
code[insn.address
-
addr:insn.address
-
addr
+
insn.size]
last_addr
=
addr
print
(text)
with
open
(
"disasm_output2.txt"
,
"w"
) as f:
for
addr, offset, inst_text
in
all_insts:
f.write(f
"0x{offset:x}\t{inst_text}"
.ljust(
64
)
+
"\t"
+
str
(
list
(
map
(
hex
, next_block_map.get(addr,
set
()))))
+
"\n"
)
with
open
(
"insts_bytes_1.bin"
,
"wb"
) as f:
f.write(insts_bytes)
void
__fastcall sub_0(
__int64
a1,
__int64
a2,
__int64
a3,
__int64
a4,
__int64
a5,
__int64
a6,
__int64
a7,
__int64
a8,
__int64
a9,
__int64
a10,
int
a11,
_WORD *a12,
unsigned
__int8
*a13)
{
unsigned
__int8
*v13;
// rcx
char
v14;
// al
bool
v15;
// cc
_BYTE *v16;
// rdi
unsigned
int
v17;
// edx
__int64
v18;
// r8
__int64
v19;
// r9
unsigned
int
v20;
// [rsp+4h] [rbp-13Ch]
unsigned
int
v21;
// [rsp+4h] [rbp-13Ch]
unsigned
int
v22;
// [rsp+8h] [rbp-138h]
char
v23;
// [rsp+6Ch] [rbp-D4h]
_DWORD v24[6];
// [rsp+80h] [rbp-C0h] BYREF
_BYTE v25[33];
// [rsp+98h] [rbp-A8h] BYREF
_BYTE v26[7];
// [rsp+B9h] [rbp-87h] BYREF
_QWORD v27[5];
// [rsp+C0h] [rbp-80h] BYREF
unsigned
__int8
v28;
// [rsp+E8h] [rbp-58h] BYREF
unsigned
__int8
v29;
// [rsp+E9h] [rbp-57h]
unsigned
__int8
v30;
// [rsp+EAh] [rbp-56h]
unsigned
int
v31;
// [rsp+108h] [rbp-38h]
_BYTE *v32;
// [rsp+138h] [rbp-8h]
if
( *a12 )
{
if
( !*(_WORD *)a13 )
{
memset
(v27, 0, 0x21uLL);
memset
(v24, 0, 0x11uLL);
LOBYTE(v24[0]) = *MEMORY[0xFFFFFFFFFFEEB4DD] ^ *a12;
v28 = *a13;
if
( v28 < 0x30u )
goto
LABEL_6;
if
( v28 <= 0x39u )
JUMPOUT(0x1C7LL);
v13 = &v28;
v14 = v29;
v15 = v29 <= 0x39u;
if
( v29 > 0x39u )
{
LABEL_6:
v23 = v29 - 55;
v13 = &v28;
v14 = v28;
v15 = v28 <= 0x39u;
}
if
( !v15 )
{
v14 = (16 * (v28 - 48)) | v23;
v13 = 0LL;
}
*((_BYTE *)v27 + (_QWORD)v13) = v14;
if
( v30 >= 0x41u )
{
memset
(v25, 0,
sizeof
(v25));
v16 = v26;
v20 = ((BYTE1(v24[0]) + (HIDWORD(v27[0]) >> 3)) ^ (v24[0] + HIDWORD(v27[0])) ^ (LOBYTE(v24[0])
+ (HIDWORD(v27[0]) << 6)))
+ LODWORD(v27[0]);
v22 = (v24[1] + v24[0]) ^ ((((unsigned
__int8
)((unsigned
int
)(v24[1] + v24[0]) >> 16) + (v20 >> 3)) ^ (v24[1] + v24[0] + v20) ^ (((unsigned
int
)(v24[1] + v24[0]) >> 24) + (v20 << 6)))
+ HIDWORD(v27[0]));
v21 = ((LOBYTE(v24[2]) + (v22 >> 5)) ^ (v24[2] + v22) ^ (HIBYTE(v24[2]) + 16 * v22)) + ((v24[1] + v24[0]) ^ v20);
*(_DWORD *)v25 = (v24[3] + v24[2]) ^ v21;
*(_DWORD *)&v25[4] = (v24[3] + v24[2]) ^ ((((unsigned
__int8
)((unsigned
__int16
)(LOWORD(v24[3]) + LOWORD(v24[2])) >> 8)
+ (v21 >> 5)) ^ (v24[3] + v24[2] + v21) ^ ((unsigned
__int8
)((unsigned
int
)(v24[3] + v24[2]) >> 16)
+ 16 * v21))
+ v22);
MEMORY[0xFFFFFFFFFFFF72CC](v26, a2, v25, 4LL, 128LL);
if
( (
char
)*MEMORY[0xFFFFFFFFFFEE980A] != v25[0] )
{
v16 = v32;
if
( !(unsigned
int
)MEMORY[0xFFFFFFFFFFFF551D](v32) )
JUMPOUT(0x589LL);
v19 = 0LL;
v18 = -1148776LL;
v17 = -1155031;
}
v32 = v16;
v31 = v17;
if
( v17 != 2 )
{
if
( v31 != 16 )
{
if
( v31 == 273 )
JUMPOUT(0x5D4LL);
if
( v31 == 312 )
JUMPOUT(0x5DELL);
MEMORY[0xFFFFFFFFFFFECD0F](v32, a2, v17, 0LL, v18, v19);
}
JUMPOUT(0x5CALL);
}
JUMPOUT(0x5C3LL);
}
JUMPOUT(0x271LL);
}
JUMPOUT(0xBDLL);
}
JUMPOUT(0x86LL);
}
void
__fastcall sub_0(
__int64
a1,
__int64
a2,
__int64
a3,
__int64
a4,
__int64
a5,
__int64
a6,
__int64
a7,
__int64
a8,
__int64
a9,
__int64
a10,
int
a11,
_WORD *a12,
unsigned
__int8
*a13)
{
unsigned
__int8
*v13;
// rcx
char
v14;
// al
bool
v15;
// cc
_BYTE *v16;
// rdi
unsigned
int
v17;
// edx
__int64
v18;
// r8
__int64
v19;
// r9
unsigned
int
v20;
// [rsp+4h] [rbp-13Ch]
unsigned
int
v21;
// [rsp+4h] [rbp-13Ch]
unsigned
int
v22;
// [rsp+8h] [rbp-138h]
char
v23;
// [rsp+6Ch] [rbp-D4h]
_DWORD v24[6];
// [rsp+80h] [rbp-C0h] BYREF
_BYTE v25[33];
// [rsp+98h] [rbp-A8h] BYREF
_BYTE v26[7];
// [rsp+B9h] [rbp-87h] BYREF
_QWORD v27[5];
// [rsp+C0h] [rbp-80h] BYREF
unsigned
__int8
v28;
// [rsp+E8h] [rbp-58h] BYREF
unsigned
__int8
v29;
// [rsp+E9h] [rbp-57h]
unsigned
__int8
v30;
// [rsp+EAh] [rbp-56h]
unsigned
int
v31;
// [rsp+108h] [rbp-38h]
_BYTE *v32;
// [rsp+138h] [rbp-8h]
if
( *a12 )
{
if
( !*(_WORD *)a13 )
{
memset
(v27, 0, 0x21uLL);
memset
(v24, 0, 0x11uLL);
LOBYTE(v24[0]) = *MEMORY[0xFFFFFFFFFFEEB4DD] ^ *a12;
v28 = *a13;
if
( v28 < 0x30u )
goto
LABEL_6;
if
( v28 <= 0x39u )
JUMPOUT(0x1C7LL);
v13 = &v28;
v14 = v29;
v15 = v29 <= 0x39u;
if
( v29 > 0x39u )
{
LABEL_6:
v23 = v29 - 55;
v13 = &v28;
v14 = v28;
v15 = v28 <= 0x39u;
}
if
( !v15 )
{
v14 = (16 * (v28 - 48)) | v23;
v13 = 0LL;
}
*((_BYTE *)v27 + (_QWORD)v13) = v14;
if
( v30 >= 0x41u )
{
memset
(v25, 0,
sizeof
(v25));
v16 = v26;
v20 = ((BYTE1(v24[0]) + (HIDWORD(v27[0]) >> 3)) ^ (v24[0] + HIDWORD(v27[0])) ^ (LOBYTE(v24[0])
+ (HIDWORD(v27[0]) << 6)))
+ LODWORD(v27[0]);
v22 = (v24[1] + v24[0]) ^ ((((unsigned
__int8
)((unsigned
int
)(v24[1] + v24[0]) >> 16) + (v20 >> 3)) ^ (v24[1] + v24[0] + v20) ^ (((unsigned
int
)(v24[1] + v24[0]) >> 24) + (v20 << 6)))
+ HIDWORD(v27[0]));
v21 = ((LOBYTE(v24[2]) + (v22 >> 5)) ^ (v24[2] + v22) ^ (HIBYTE(v24[2]) + 16 * v22)) + ((v24[1] + v24[0]) ^ v20);
*(_DWORD *)v25 = (v24[3] + v24[2]) ^ v21;
*(_DWORD *)&v25[4] = (v24[3] + v24[2]) ^ ((((unsigned
__int8
)((unsigned
__int16
)(LOWORD(v24[3]) + LOWORD(v24[2])) >> 8)
+ (v21 >> 5)) ^ (v24[3] + v24[2] + v21) ^ ((unsigned
__int8
)((unsigned
int
)(v24[3] + v24[2]) >> 16)
+ 16 * v21))
+ v22);
MEMORY[0xFFFFFFFFFFFF72CC](v26, a2, v25, 4LL, 128LL);
if
( (
char
)*MEMORY[0xFFFFFFFFFFEE980A] != v25[0] )
{
v16 = v32;
if
( !(unsigned
int
)MEMORY[0xFFFFFFFFFFFF551D](v32) )
JUMPOUT(0x589LL);
v19 = 0LL;
v18 = -1148776LL;
v17 = -1155031;
}
v32 = v16;
v31 = v17;
if
( v17 != 2 )
{
if
( v31 != 16 )
{
if
( v31 == 273 )
JUMPOUT(0x5D4LL);
if
( v31 == 312 )
JUMPOUT(0x5DELL);
MEMORY[0xFFFFFFFFFFFECD0F](v32, a2, v17, 0LL, v18, v19);
}
JUMPOUT(0x5CALL);
}
JUMPOUT(0x5C3LL);
}
JUMPOUT(0x271LL);
}
JUMPOUT(0xBDLL);
}
JUMPOUT(0x86LL);
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)