吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3975|回复: 33
上一主题 下一主题
收起左侧

[原创] 我把灰色的"微软软件"拆了个底朝天!!

  [复制链接]
跳转到指定楼层
楼主
a3341736201 发表于 2026-8-29 13:36 回帖奖励
本帖最后由 a3341736201 于 2026-8-29 14:09 编辑

前言

最近马上开学了,闲的无聊,无意中得到一个软件,
开始,打开看是一个微软的软件,然后 丢OD,丢ida都不行
我开始还以为,然后看属性页是微软的,心里想 微软公司这么牛逼,这俩都调试不了

一、属性页写着微软?

右键一看,Company:Microsoft Corporation,产品名 Internet Explorer。


【md图片截图】

微软什么时候开发b-c录单软件了?

当然是假的。但假得有讲究——不是改的,是 Windows 自带的 IExpress 打包器(System32\iexpress.exe,每台 Windows 都有)生成的。IExpress 打包时直接复用微软自家的 wextract.exe 当外壳,版本资源原样继承,所以全世界的 IExpress 包属性页都长一个样。

实锤靠结构。文件 0x137E8 偏移处有标准 CAB 头(MSCF),cbCFHeader=0x2C 是 IExpress 专属值,再加上签名一栏是空的——微软真发的包不可能没签。判定成立。

拆法很朴素,把 CAB 切出来用系统自带 tar 读:

$fs=[IO.File]::OpenRead($exe); $fs.Position=0x137E8
# 切出 115,964,386 字节 → payload.cab
tar.exe -tf payload.cab
# runtime.7z | launcher.vbs | 7z.exe | 7z.dll

二、 一层一层扒

launcher.vbs 的逻辑:把 7z 解压到 %LOCALAPPDATA%\ZhddBaodanSingleRun\run-随机数,取目录里第一个 .exe 运行。每次运行留 300MB 垃圾不清(运行计数 669 次),"取第一个 exe"的写法还欢迎本地恶意程序抢跑。

asar 是 Electron 的资源格式,头是 JSON 树,数据按偏移排后面。手写了个解析器:

const headerPickleSize = buf.readUInt32LE(4);
const dataOffset = 8 + headerPickleSize;
const header = JSON.parse(buf.slice(16, 16 + buf.readUInt32LE(12)).toString('utf8'));
// 递归遍历 header.files,按 offset/size 从 dataOffset 切数据

三、asar解包后全部文件解包出来,然后惊喜了——源码是明文的。中文目录名、没混淆的 JS、带注释,甚至还有二十多个单元测试文件。技术栈 Electron 38.4.0 + koffi + nut-tree,业务是六合*盘口录单:录单、兑奖、风控、套利、微信自动录单。

直接源码,dump


【截图目录】

四、 这包被人动过手脚

然后我就审查源码,在里面翻到一份不该存在的文件 04_asar_extract_tolerant_report.json,是 asar 解包作业日志,路径写着:

E:\baodanxitongup\智慧订单相关\01_原生智慧订单\逆向解包\智慧订单3.10.118.0逆向解包_20260519

厚礼蟹,这发行包是有人对 3.10.118.0 逆向解包后重新组装的。有人搞过他,并且这个包是破解版的

其中看这个文件 。integrity-check.cjs 本该做完整性校验,实际是个恒返回 true 的空壳:

function safeCheck() {
  return { safe: true, valid: true, success: true, issues: [], errors: [] };
}
module.exports = new Proxy({}, { get() { return safeCheck; } });

真正的校验逻辑编成了 .jsc 字节码躺在旁边,没人加载。加密狗检测 dongle.cjs 同样是空壳,加密狗的 DLL 还没删干净。外壳版本资源 3.10.118.0,package.json 里 3.20.120,对不上。

五、卡密体系,纸糊的

这软件靠卡密收费。卡长这样:

CLS-G00A5-xxxxx-xxxxxx-GLOBAL00-xxxxxxxxxx

签名算法在 license.cjs 里,明文:

// L11 —— 密钥跟着代码一起发行
const SECRET = "***";

// L218 —— "签名"就是拿密钥拼串喂给自研哈希
function signCard(parts) {
  return shortHash([SECRET, parts.kind, String(parts.days),
                    parts.issued, parts.nonce, parts.machineToken].join("|"), 12);
}

// L58 —— shortHash:FNV-1a 变体 + murmur 变体拼 base36,非加密哈希
function shortHash(input, length = 12) {
  let h1 = 0x811c9dc5, h2 = 0x9e3779b9;
  for (const c of input) { /* 两个 32 位乘法哈希 */ }
  return (h1.toString(36) + h2.toString(36)).toUpperCase().slice(0, 12);
}

L248 还有 createCardCode——发卡器本体,直接导出的。整段长这样:

function createCardCode(options = {}) {
  const mode = options.mode === "bound" ? "bound" : "generic";
  const kind = mode === "bound" ? "B" : "G";
  const days = Math.max(1, Number.parseInt(options.days, 10) || 0);
  const issued = (Number.parseInt(options.issuedAtSec, 10) || Math.floor(Date.now() / 1000))
    .toString(36)
    .toUpperCase();
  const nonce = String(options.nonce || randomToken(6))
    .toUpperCase()
    .replace(/[^A-Z0-9]/g, "")
    .slice(0, 6)
    .padEnd(6, "0");
  const token = machineToken(options.machineCode, mode);
  const signature = signCard({
    kind, days, issued, nonce, machineToken: token
  });
  return `${LICENSE_PREFIX}-${kind}${encodeDays(days)}-${issued}-${nonce}-${token}-${signature}`;
}

哈哈哈,看出来问题了吧:签发时间取本机时钟,随机数本地生成,签名本地算——从输入到输出没有一步碰网络。这函数在应该待在服务端,现在躺在客户端的导出表里,L1023 还以 generateCardCode 的名字再导出了一份。

有效期更离谱。激活时写到本地明文 JSON:

// L696
expiresAtMs: baseTime + parsed.days * DAY_MS,

而启动检查只验卡号字符串的签名,到期判断直接读这个不参与签名的字段:

// L432 —— 唯一被密码学验证的是卡号字符串本身
const parsed = record?.licenseKey ? parseCardCode(record.licenseKey) : null;
// L438 —— 到期判断读的是明文 JSON 里的数字
const expired = Boolean(record) && record.expiresAtMs <= Date.now();

防重用也是纯本机:used-cards.json 只存在每台机器自己的 userData 里。在线校验整套空操作:

// L964
function mustVerifyOnline() { return false; }
// L801 —— 所谓"在线验证"就是本地 getStatus 换了个名字
function onlineVerify(appRoot) { return runtimeVerify(appRoot); }

我写了个 PoC,只调它自己的导出函数:

const L = require('.../electron/license.cjs');
const card = L.createCardCode({ days: 365 });          // 现场发卡
L.activateLicense(root, card);                          // 激活
// 然后改 local-license.json 里的 expiresAtMs 到 2099 年

跑出来的结果:

现场生成的年卡卡号: CCLS-G00A5-xxxxx-xxxxxx-GLOBAL00-xxxxxxxxxx
{"valid":true,"status":"可激活","message":"年卡校验通过"}
{"success":true,"message":"年卡激活成功","remainingDays":365}
篡改后 -> {"valid":true,"status":"已授权","remainingDays":26788}
同卡换目录再激活 -> {"success":true,"message":"年卡激活成功"}

然后我拿去激活,成功


【md激活】

六、 有混淆?也拆一下

bootstrap.cjs 钩住 Module._compile,对 ZHENC001 开头的文件做 AES 解密。原文件长这样(节选,混淆后的样子):

const ALGORITHM=_0x1e417f(0x150,'IE@0'),KEY_SEED=_0x1e417f(0x134,'IE@0'),
ENCRYPTED_MARKER=Buffer[_0x1e417f(0x146,'OPtt')](_0x1e417f(0x157,'L3iT'));

写了个 harness 把它的字符串数组和 RC4 解码器抽出来跑,常量全还原:

ALGORITHM      = "aes-256-cbc"
KEY_SEED       = "zhihui_order_asar_protection_2025_v1"
MARKER         = "ZHENC001"
key = sha256(KEY_SEED + "_key")   // 32 字节
iv  = md5(KEY_SEED + "_iv")       // 16 字节

然后全包扫 ZHENC001 头——零个文件。加密器装好了,忘了加密,就挺离谱。

其他十来个混淆文件(server.mjs、preload.cjs、微信发送模块)用了字符串数组 + RC4。解法迭代三版:暴力枚举有太多坑,最后改成先从源码解析调用点配对再精确解码,150 对命中 148。还原出的内容包括:微信发消息走 koffi 调 FindWindowW + 剪贴板粘贴 + 模拟按键,找不到窗口就落 ps1 用 -ExecutionPolicy Bypass 跑;本地 server 的 HTTPS 证书默认口令 changeit;还有个 wxapi 微信网关绑定 0.0.0.0:8062 无鉴权,同网段谁都能控制你的微信。

七、 学到什么

其实文中大多都是踩了很多坑,不过让我见识到了,win 95 后,系统自带的IExpress打包器,这也算刷新了一个知识点,其他的就大多看代码解出来的,收工!!

免费评分

参与人数 16吾爱币 +15 热心值 +7 收起 理由
QiHua7777 + 1 用心讨论,共获提升!
shiyue2925 + 1 + 1 谢谢@Thanks!
wapj20260721 + 1 用心讨论,共获提升!
ruige88 + 1 + 1 我很赞同!
Beguin + 1 我很赞同!
passaway + 1 热心回复!
5omggx + 1 学到了
laozhang4201 + 1 + 1 热心回复!
fanssong + 1 + 1 又学到了一项666
kukisama + 1 + 1 热心回复!
eqewqqewr + 1 我很赞同!
wchy056 + 1 谢谢@Thanks!
yang0828 + 1 我很赞同!
zxcvbnm12 + 1 热心回复!
星峰 + 1 + 1 我很赞同!
大头狗 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
Rx0 发表于 2026-8-30 08:59
早年软件资源没如今这么丰富,那时rar、7z压缩解压在某些情况下不太好用,CAB包就是唯一通用优选,虽然压缩率低点,但基本都能正常解压出来。
推荐
xfwww 发表于 2026-8-30 00:58
感谢分享,好熟悉的软件,感觉跟当年番禺那帮人破解湾湾的白家了的手法一样,破解了再简单加密改个名字卖给内地人的。
沙发
yifan1000 发表于 2026-8-29 13:45
感谢分享

免费评分

参与人数 2吾爱币 -4 收起 理由
fanssong -3 请勿灌水,提高帖子质量是每位会员应尽的义务!
PythonPan -1 请勿灌水,提高帖子质量是每位会员应尽的义务!

查看全部评分

3#
manbuze126 发表于 2026-8-29 14:16
貌似很强大
4#
hundunwuji111 发表于 2026-8-29 15:06
厉害,学到了
5#
yang0828 发表于 2026-8-29 15:13
感谢又学到了
6#
aabbccddzsg 发表于 2026-8-29 16:20

厉害,学到了
7#
sansuizhaixing 发表于 2026-8-29 16:43
很厉害的
8#
taidong 发表于 2026-8-29 18:11
厉害,学到了
9#
dujiu3611 发表于 2026-8-29 20:01
以前就想过,它干啥屏蔽修改,设置成灰色,一直都有想过拆开的,给你点赞,厉害,感谢分享。
10#
eatKFC 发表于 2026-8-29 20:35
大佬Nb,奥利给!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-10 08:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表