news 2026/7/20 15:27:36

经gpt观察后发现,每 4 字节的第 1 个字节都像是被异或了 0x44。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
经gpt观察后发现,每 4 字节的第 1 个字节都像是被异或了 0x44。

with open(‘Driver.sys’, ‘rb’) as f:
raw = bytearray(f.read())
repaired = bytearray(raw)
for i in range(0, len(repaired), 4):
repaired[i] ^= 0x44
with open(‘Driver_repaired.sys’, ‘wb’) as f:
f.write(repaired)
按这个规律恢复后,Driver.sys 重新变成正常 PE 驱动,并能看到关键字符串:

??\DeviceDrive
\Device\MYDEVICE
flag is you input
wrong
真正缺失的符号是 Drive,并且 Drive的md5刚好是f2c6151d6c0d99f3666129b97e2100f5

再把exe修改好

然后回到Driver.sys,看看哪里引用了flag is you input

for ( i = 0; i < v5; ++i )
*((_BYTE *)buf + (int)i) = Format[i];
for ( n32 = 1; n32 < 32; ++n32 )
*((_BYTE)buf + n32 - 1) ^= (unsigned __int8)(((_BYTE *)buf + n32 - 1) % 0x12u + *((_BYTE *)buf + n32) + 5) ^ 0x34;
if ( (unsigned int)sub_140001000(buf, 32) )
{
strcpy(Format, “flag is you input”);
Irp_1->IoStatus.Information = 18;
DbgPrint(&Format__2);
}
跟踪sub_140001000

__int64 __fastcall sub_140001000(__int64 buf, __int64 n32)
{
char n52; // [rsp+20h] [rbp-28h]
char n52_1; // [rsp+21h] [rbp-27h]
char n52_2; // [rsp+22h] [rbp-26h]
int n32_3; // [rsp+24h] [rbp-24h]
int n32_2; // [rsp+28h] [rbp-20h]
_BYTE *PoolWithTag; // [rsp+30h] [rbp-18h]
int n32_1; // [rsp+58h] [rbp+10h]

n32_1 = n32;
PoolWithTag = ExAllocatePoolWithTag(NonPagedPool, 0x100u, 0x504F4F4Cu);
n52 = 52;
for ( n32_2 = 0; n32_2 < n32_1; ++n32_2 )
{ //每一个字节都是和上一个原始字节进行异或
n52_1 = *(_BYTE *)(buf + n32_2);
PoolWithTag[n32_2] = n52 ^ n52_1;
n52 = n52_1;
}
for ( n32_3 = 0; n32_3 < n32_1; ++n32_3 )
{
n52_2 = PoolWithTag[n32_3];
PoolWithTag[n32_3] = n52 ^ n52_2;
n52 = n52_2;
if ( (unsigned __int8)PoolWithTag[n32_3] != byte_140003000[n32_3] )
return 0;
}
return 1;
}
两次链式异或,结果与byte_140003000[n32_3]比较

去找byte_140003000[n32_3]

shift+E

0x66,0xA,0x9,0xE0,0xE2,0xE3,0xCB,0x9,0x14,0x15,0xC,0x38,0x1,0x1F,0x5,0x42,0x71,0x6E,0x56,0x7A,0x0,0x20,0xE4,0xBF,0xE6,0xCD,0x28,0x30,0x2C,0x75,0xA0,0x3A
重新梳理下逻辑

第一轮:从前往后,每个字节跟前一个字节(或初始值 0x34)XOR
tmp[0] = in[0] ^ 0x34 ← 第0个字节用初始值 0x34
tmp[1] = in[1] ^ in[0] ← 第1个字节用 in[0]
tmp[2] = in[2] ^ in[1] ← 第2个字节用 in[1]
tmp[3] = in[3] ^ in[2]

tmp[31] = in[31] ^ in[30]

第二轮:从前往后,每个字节跟前一个字节(或 in31)XOR
out[0] = tmp[0] ^ in[31] ← 第0个字节用 in[31]
out[1] = tmp[1] ^ tmp[0] ← 第1个字节用 tmp[0]
out[2] = tmp[2] ^ tmp[1] ← 第2个字节用 tmp[1]
out[3] = tmp[3] ^ tmp[2]

out[31] = tmp[31] ^ tmp[30]
我们把第一轮的公式代入第二轮去

out[0] = (in[0] ^ 0x34) ^ in[31]
out[1] = (in[1] ^ in[0]) ^ (in[0] ^ 0x34)

看 out1:in[0] 出现了两次,XOR 抵消了!
out[1] = in[1] ^ 0x34

继续:
out[2] = (in[2] ^ in[1]) ^ (in[1] ^ in[0])
= in[2] ^ in[0] ← in[1] 抵消了
out[3] = (in[3] ^ in[2]) ^ (in[2] ^ in[1])
= in[3] ^ in[1] ← in[2] 抵消了
out[4] = (in[4] ^ in[3]) ^ (in[3] ^ in[2])
= in[4] ^ in[2] ← in[3] 抵消了
最后:
out[31] = (in[31] ^ in[30]) ^ (in[30] ^ in[29])
= in[31] ^ in[29] ← in[30] 抵消了

合并后的完整公式:
out[0] = in[0] ^ 0x34 ^ in[31]
out[1] = in[1] ^ 0x34
out[2] = in[2] ^ in[0]
out[3] = in[3] ^ in[1]
out[4] = in[4] ^ in[2]
out[5] = in[5] ^ in[3]

out[31] = in[31] ^ in[29]
out已知,可以推出in

尝试借助刚学的z3

from z3 import *
s = Solver()
out=[0x66, 0xA, 0x9, 0xE0, 0xE2, 0xE3, 0xCB, 0x9, 0x14, 0x15, 0xC, 0x38, 0x1, 0x1F, 0x5, 0x42, 0x71, 0x6E, 0x56, 0x7A, 0x0, 0x20, 0xE4, 0xBF, 0xE6, 0xCD, 0x28, 0x30, 0x2C, 0x75, 0xA0, 0x3A]
inn=[BitVec(f’x_{i}', 8) for i in range(32)]
s.add(
out[0] == inn[0] ^ 0x34 ^ inn[31],
out[1] == inn[1] ^ 0x34,
)
for i in range(2, 32):
s.add(out[i] == inn[i] ^ inn[i-2])
assert s.check() == sat
m = s.model()
flag = bytes([m.eval(inn[i]).as_long() for i in range(32)])
print(list(flag))
输出

[47, 62, 38, 222, 196, 61, 15, 52, 27, 33, 23, 25, 22, 6, 19, 68, 98, 42, 52, 80, 52, 112, 208, 207, 54, 2, 30, 50, 50, 71, 146, 125]
别忘了在sub_140001000的两次异或前还有一次处理

简化一下代码

buf[n32-1] ^= (buf[n32-1] % 18 + buf[n32] + 5) ^ 0x34;
自己除以18,加5,加下一位,与0x34异或,再与自己异或,赋值给自己

from z3 import *
s = Solver()
buf_new=[47, 62, 38, 222, 196, 61, 15, 52, 27, 33, 23, 25, 22, 6, 19, 68, 98, 42, 52, 80, 52, 112, 208, 207, 54, 2, 30, 50, 50, 71, 146, 125]
buf_old=[BitVec(f’x_{i}', 8) for i in range(32)]
for n32 in range(1,32):
s.add(
buf_new[n32-1] == (buf_old[n32-1] % 18 + buf_old[n32] + 5) ^ 0x34 ^ buf_old[n32-1]
)
assert s.check() == sat
m = s.model()
flag = bytes([m.eval(buf_old[i]).as_long() for i in range(32)])
print(flag.hex())
但是发现这个输出很奇怪,转换成字符是乱码

我们加一段代码看是不是有多解

s.add(Or([buf_old[i] != m[buf_old[i]] for i in range(32)]))
if s.check() == sat:
print(“many”)
m2 = s.model()
else:
print(“only one”)
输出many说明有多解,我们再加一些关于输出格式为flag的限制

限制第一个字符为f(0x66)

最终脚本

from z3 import *
s = Solver()
buf_new=[47, 62, 38, 222, 196, 61, 15, 52, 27, 33, 23, 25, 22, 6, 19, 68, 98, 42, 52, 80, 52, 112, 208, 207, 54, 2, 30, 50, 50, 71, 146, 125]
buf_old=[BitVec(f’x_{i}', 8) for i in range(32)]
for n32 in range(1,32):
s.add(
buf_new[n32-1] == (buf_old[n32-1] % 18 + buf_old[n32] + 5) ^ 0x34 ^ buf_old[n32-1],
buf_old[0]==0x66
)
assert s.check() == sat
m = s.model()
flag = bytes([m.eval(buf_old[i]).as_long() for i in range(32)])
print(flag)
s.add(Or([buf_old[i] != m[buf_old[i]] for i in range(32)]))
if s.check() == sat:
print(“many”)
m2 = s.model()
else:
print(“only one”)
flag{wnNCZJbBOqL3QA1C1cypiKYII4}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/20 15:26:10

2026论文结论与展望怎么写?okbiye AI实测,告别流水账、轻松过盲审

很多同学前面绪论、综述、实证全部写得很完美&#xff0c;最后栽在结论与展望章节。 最常见问题&#xff1a;结论重复摘要、照搬正文内容、没有提炼核心成果&#xff1b;展望空泛套话、假大空、和课题不匹配、完全没有落地性。盲审老师一眼扣分&#xff0c;评语直接写&#xf…

作者头像 李华
网站建设 2026/7/20 15:20:06

深入解析TI McASP音频接口:从寄存器配置到多通道音频系统开发

1. 项目概述与核心价值在嵌入式音频系统开发中&#xff0c;无论是消费级的智能音箱、专业级的音频接口&#xff0c;还是车载娱乐系统&#xff0c;高质量、低延迟、多通道的音频数据传输都是核心需求。德州仪器&#xff08;TI&#xff09;的许多高性能处理器&#xff0c;如Sitar…

作者头像 李华
网站建设 2026/7/20 15:18:14

Semgrep静态代码分析工具:现代开发流程中的安全扫描利器

Semgrep静态代码分析工具&#xff1a;现代开发流程中的安全扫描利器 【免费下载链接】semgrep Lightweight static analysis for many languages. Find bug variants with patterns that look like source code. 项目地址: https://gitcode.com/GitHub_Trending/se/semgrep …

作者头像 李华
网站建设 2026/7/20 15:17:44

C++高性能金融系统实战:信用卡额度管理平台架构与核心实现

1. 项目概述与核心价值最近在整理过往的项目经验&#xff0c;发现一个挺有意思的案例&#xff1a;一个用C实现的信用卡额度管理平台。这玩意儿听起来像是银行内部系统&#xff0c;但实际上&#xff0c;它是我几年前为一个中型消费金融公司做的核心风控模块原型。当时的需求很明…

作者头像 李华