16843184094761.jpg (438.39 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
阅前须知
[ol]
[/ol]
前言 陨落的天才
"破之力,-2147483647段!"
冷眼看着CTF全球破解Rank天梯排位上的最终定段排位,那意味着羞辱的白色文字白的刺眼,少年面无表情,只有紧握着的双手青筋绽出能表达出少年内心的痛苦,甚至由于用力过大,指甲刺进了手心也恍然未觉.
"秋城落叶,破之力,-2147483647段,级别: 超高校级史前巨低!" Rank 天梯排位主持人语气淡漠的念出了少年的最终排位,冰冷的话语代表着的事实再次让少年本就破碎淋漓的心微微抽痛!
主持人刚脱口而出这个消息,便在Rank排位赛上的选手中就引起了一阵骚动。
“-2147483647?嘿嘿,这b成绩寄存器都给他干爆了吧?”
“哎,这废物真是把我们二次元的脸丢光了。”
“要不是三年前这“天才”干碎过Adobe全家桶和几个大型商业软件,这种fw连进CTF的资格都没有,哪还有机会上来丢我们CTF全球大赛的脸?纯属拉低我们大赛的含金量!”
“哎,昔日谈笑间令反汇编代码灰飞烟灭 闻名二次元世界的天才程序员少年怎么落魄到这种程度?”
“谁知道呢?或许是天天上p站小蓝鸟⬛,又没有女朋友,现在只知道打胶易脑子打坏了吧...大家要记得戒色啊...”
“看他那个衰样,肥头大耳油腻的头发,纯死肥宅一个,光看外表就真下头...”
周围传来的不屑和來嘲笑和幸灾乐祸,全都落在少年那敏锐的顺风耳中,犹如一柄利剑,狠狠的刺穿心脏❤️,令少年双目不禁微微赤红。
少年缓缓抬起头来,露出一张肥头大耳油腻留♂️脸庞来,浑浊发黄的双眸狠狠的扫过这些嘲笑他的臭鱼烂虾戀们,少年嘴角的自嘲,更加苦涩。
“集爸们谁懂啊?今天Rank排位定级赛,碰到一堆下头男,对我冷嘲热讽...9命啊集霸!”
苦涩一笑,落寞的转身走进臭鱼烂虾人群中,心中却下定决心要干出一番大事,狠狠的打脸今日羞辱他的众人!
“顶针珍珠,破之力,2147483647段!义演顶针,鉴定为玩原神玩的!峡谷之巅最强王者!”主持人一改禁欲播报风,双眼火热的注视着这位新晋Top1!
“不愧是Xmind集团扶持的种子选手,一手bytecode技术让人无从下手,真了不起!”
“不愧是年轻一代顶级强者啊...”
强忍着悲痛的少年落寞的背影留在了Xmind丶顶针珍珠的眼中,不屑之色更重,心中冷笑道:普段は綺麗な顔立ちなのにフェラ顔は超下品!証拠を残さないためにフェラごっくんはもちろん、中出しで体内に**隠しまで!【究極のこっそり】堪能してみませんか?
三年前那意气风发的少年,一岁扣字,三岁征战孙吧,五岁楼中楼和网友对喷5000层,年仅十岁就破解了众多商业软件,凭借手中一台800块钱的i386电脑成功登顶CTF亚洲赛区最年轻的最强王者!
然而天才的道路充满曲折,三年前声望达到巅峰的天才少年,突兀的接触到了房赌毒,收到了有生以来最残酷的打击,京海市市中心房价年年增高,买了Xmind集团房烂尾上诉无果后又无家可归,只能天天刷推,还每天p站固定冲浪2小时,一夜之间梦想和大好前途化为乌有,而破之力技术也诡异的随着时间流逝越变越少!
破之力消失的直接结果,便是其实力不断倒退,去年还是-65534,直到今日竟然逼近了 int 数据类型最小值!
从天才的神坛,一夜跌落到了连普通人都不如的地步,这种打击让少年失魂落魄,天才の名,也逐渐被不屑和嘲讽取代。
站的越高摔的越狠,这次的跌落,或许再也没有爬起来的机会!
0x01 复仇计划
寂静的夜晚月光和一个寂寞的灵魂。
山崖之巅,秋城落叶躺在草地上,+塞最终叼着一根青草,任由那微微的酸涩在口中爆开。
“那Xmind财团不仅夺走了我的一切,还扶持了一个同样的天才少年,真是可恶!怎么才能...”少年恶狠狠的想着,看着模糊的夜色,突然眼中一亮,一个恶毒的计划在心中开始酝酿...
却说那 Xmind乃是思维导图行业小有盛名的公司,而旗下的 Xmind 产品更是使用了 Node 字节码技术保护了主程序,让无数天才少年铩羽而归,一举奠定了反破解的巅峰!
而此刻昏黄的灯光下,少年面前的MacBook Pro 中运行的正是XMind!
少年此时正在操作 asar 进行解包,那 Xmind 却是依赖了 Electron 技术,本质上还是 Vue3 + Pinia 实现了全平台。
16843240651983.jpg (343.38 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
随后少年用 Visual Studio Code 打开 app 文件夹,开始查阅反编译的代码.
16843241781884.jpg (236.13 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
经过少年的观察,这里的升级至Pro很有重大嫌疑。
16843242235498.jpg (923.01 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
16843242813701.jpg (879.25 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
经过进一步的搜索,发现 Xmind 4412 行代码中认为this.activationStatus === u.ACTIVATION_STATUS.VALID 表示激活,否则显示激活按钮。
而this.activationStatu来自 e.status ,搜索一番后发现:
E = (0, i.computed)(() => {
const e = (0, s.useAccountStore)();
if (!e.rawSubscriptionData) return null;
try {
return N(e.rawSubscriptionData);
} catch (e) {
return null;
}
});
S = (0, i.computed)(() => {
if (!E.value) return c.ACTIVATION_STATUS.TRIAL;
{
const { status: e, expireTime: t } = E.value && E.value;
if (e && e === c.SUBSCRIPTION_SERVER_STATUS.EXPIRED)
return c.ACTIVATION_STATUS.EXPIRED;
if (e && e === c.SUBSCRIPTION_SERVER_STATUS.VALID)
return t && p.value && new Date(t)
代码来自这里,E.value 如果为 NULL,则返回试用ACTIVATION_STATUS.TRIAL,所以我们需要关注N(e.rawSubscriptionData)这个数据。
函数 N 如下:
d=String.fromCharCode(45,45,45,45,45,66,69,71,73,78,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45,10,77,73,71,102,77,65,48,71,67,83,113,71,83,73,98,51,68,81,69,66,65,81,85,65,65,52,71,78,65,68,67,66,105,81,75,66,103,81,67,68,89,72,51,49,108,48,108,108,105,99,66,97,118,98,85,90,82,103,48,121,49,76,110,73,10,50,74,74,117,80,90,97,107,48,52,57,56,119,71,109,75,48,78,43,107,115,113,67,122,65,48,88,85,102,67,103,81,53,69,57,105,116,89,121,80,117,84,43,122,54,80,122,47,43,48,113,54,78,101,65,112,107,87,99,110,67,47,84,104,10,87,81,89,54,90,108,69,79,77,111,110,114,104,80,117,98,56,122,115,87,89,79,90,122,99,107,81,117,116,120,51,106,110,54,107,43,54,90,88,120,55,121,85,98,98,107,120,73,107,43,119,113,87,103,110,108,81,120,110,120,54,84,77,100,10,83,51,114,103,111,51,114,52,98,108,70,84,87,105,54,69,69,81,73,68,65,81,65,66,10,45,45,45,45,45,69,78,68,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45);
N = (e) => {
const t = Buffer.from(e, "base64"),
n = a.default.publicDecrypt(
{ key: d, padding: a.default.constants.RSA_PKCS1_PADDING },
t
);
return JSON.parse(n.toString());
};
而 d 实际上值为
'-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDYH31l0llicBavbUZRg0y1LnI\n2JJuPZak0498wGmK0N+ksqCzA0XUfCgQ5E9itYyPuT+z6Pz/+0q6NeApkWcnC/Th\nWQY6ZlEOMonrhPub8zsWYOZzckQutx3jn6k+6ZXx7yUbbkxIk+wqWgnlQxnx6TMd\nS3rgo3r4blFTWi6EEQIDAQAB\n-----END PUBLIC KEY-----'
由此可见,这是一个 RSA 公钥,然后我们用他解密我们的e.rawSubscriptionData 试试。
e.rawSubscriptionData 来自于抓包。
16843254634029.jpg (122.48 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
{"status": "Trial", "expireTime": 0, "ss": "", "deviceId": ""},status 如果为“sub”表示订阅有效,expireTime 表示到期时间,其他值不管。
所以我们只要伪造返回数据即可,自己生成一对密钥,然后伪造加密数据:
我的密钥对
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALuQXELwuGkDD+IYTrrSNgztWK6pdbM3bBDWVtQeP6oJWbY10PCP24Wy
kxo/6nn0xRDFM4Y+QKMrztEb64JvpKxUI4QFnn67PDJtW3QnvvQNJKzO+xWFDNKZ
wB5kPZ0WGROBgAWjp2/v6hUN/1+JWoIwDilpa0LwHZ8OMvcyu/6lAgMBAAE=
-----END RSA PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC7kFxC8LhpAw/iGE660jYM7ViuqXWzN2wQ1lbUHj+qCVm2NdDw
j9uFspMaP+p59MUQxTOGPkCjK87RG+uCb6SsVCOEBZ5+uzwybVt0J770DSSszvsV
hQzSmcAeZD2dFhkTgYAFo6dv7+oVDf9fiVqCMA4paWtC8B2fDjL3Mrv+pQIDAQAB
AoGAVJClyFiYDGChDKNA++JDFFj+nuEwe/kE9CJvS3vH4HYOyKRC6/MwWntE75TZ
ttqw7vq6XFA8/FSIDqez6z9C0tlo1Gj1qIVFSmqeDaq1DoECFtkAIfSKmMbea8nL
AshUlPiKZ7msDq38+GQmVIHvfOrN8iiyC3Jr39Z2szEN8BECQQDt8m8evi1PFoNg
TgO4a+szLHGt85ztHDOgm3OfftqSC1TL9hpAgRyIrjCukfIYNGQhyAm6RfhmE3Fu
06xFkRhbAkEAyctaIMSC9FPY/CL1MYKSRvS7ZZYoHh8DZF/NCnt9EmyEM3KPM/xJ
IKTO6UxKiqfGAtAUMLiBoyu9Y0rU5Fr0/wJANMTdC85VMgLmI8dpX87fHDwxAcjS
9mqYsHeJDsgNJPJKXek4LTH06ALpXO2U6PVFd5BrR9oYmlqZf2CGBe+FnQJBAJCc
0IwnCAn8hMW8b6b5gcaj4CAfCcT8SLwIA7L9aFZpuhv8fy+sHuPr9/QtHkZbkYW2
hKGduBmtYN3lZMf5fxUCQHRhDYJe4nVVw7spQRf5zwni4xUuTFicDMaiMLedTLBF
I7a+DNlOoXgdhlO4uivv4IPcWaRCe3/HdzJobZ8FmxQ=
-----END RSA PRIVATE KEY-----
我伪造的信息
{"status": "sub", "expireTime": 4093057076000, "ss": "", "deviceId": ""}
加密后信息
eeZRXhL4ZY6ftIFDi1JU9XA1mqJaUuiJFgmZySEz50u/HW31e4Tucf4jkCXPRJO3fsLcUYXgK9fjY4H6FnUK4Wh5xBxAdUx+3p986xXZg85fEKtyxyZmuCAff8MNvOBsOLxmJkN2i4+iyuDGQkmhhFx3k60RkeczyV80BM9lbWI=
下面就是考虑怎么替换这个返回值。
少年微微皱眉,分析到现在,却没有任何实质性进展,不禁有些急躁。
0x02 利用NodeJS模块缓存进行Hook
如本文标题所见,本文主要是通杀 Windows 版本,而 Windows 版本有 bytecode字节码加密,所以不能像 macOS 上修改 js 一样轻松。
const crypto = require("crypto");
// 保存原始的 publicDecrypt 函数
const originalPublicDecrypt = crypto.publicDecrypt;
const originalPublicDecryptEx = function (message) {
let key = `-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDYH31l0llicBavbUZRg0y1LnI\n2JJuPZak0498wGmK0N+ksqCzA0XUfCgQ5E9itYyPuT+z6Pz/+0q6NeApkWcnC/Th\nWQY6ZlEOMonrhPub8zsWYOZzckQutx3jn6k+6ZXx7yUbbkxIk+wqWgnlQxnx6TMd\nS3rgo3r4blFTWi6EEQIDAQAB\n-----END PUBLIC KEY-----`;
const n = originalPublicDecrypt(
{
key: key,
padding: 1,
},
message
);
return n;
};
// 将 publicDecrypt 函数定义为 getter 方法,返回新的实现
Object.defineProperty(crypto, "publicDecrypt", {
get() {
return function myPublicDecrypt(...args) {
console.trace("myPublicDecrypt 调用栈");
console.log("秋城落叶Hook Xmind开始");
args[0]["key"] =
"-----BEGIN RSA PUBLIC KEY-----\nMIGJAoGBALuQXELwuGkDD+IYTrrSNgztWK6pdbM3bBDWVtQeP6oJWbY10PCP24Wy\nkxo/6nn0xRDFM4Y+QKMrztEb64JvpKxUI4QFnn67PDJtW3QnvvQNJKzO+xWFDNKZ\nwB5kPZ0WGROBgAWjp2/v6hUN/1+JWoIwDilpa0LwHZ8OMvcyu/6lAgMBAAE=\n-----END RSA PUBLIC KEY-----";
let result;
try {
result = originalPublicDecrypt.call(this, ...args);
let data = JSON.parse(result.toString());
data.status = "sub";
data.expireTime = 4093057076000;
result = Buffer.from(JSON.stringify(data));
crypto.log("用自己的密钥解密成功,开始走我的密钥解密流程。", data);
} catch (e) {
crypto.log("解密出错,开始走官方密钥解密流程。");
result = null;
let ori = originalPublicDecryptEx(args[1]);
crypto.log(
"解密出错",
args[1].toString("base64"),
"\n官方密钥解密结果",
ori,
"\n错误细节\n",
e
);
result = ori;
}
// 调用原始的 publicDecrypt 函数
return result;
};
},
});
Object.defineProperty(crypto, "log", {
get() {
return function log(...args) {
console.log(...args);
};
},
});
module.exports = crypto;
我们知道 nodejs 中有一个概念叫模块缓存,这是为了优化性能而设计的。
当我们下一次 require 某个模块的时候,会从缓存里去读取模块缓存代码,而这正好为我们的攻击提供了便利。
让我们来看上方一段代码,利用模块重导出技术我们成功 Hook 了 Main.js 并修改了加密函数的 key 为我们自己的 key。
16843267162708.jpg (169.51 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
我们只需要在 main.js 文件头部加上一行引入即可。
运行试试:
16843267612014.jpg (680.13 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
我们已经成功注入进去代码,实现了无侵入式修改。
下一步,我们伪造 Http 返回值:
16843270887720.jpg (627.05 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
利用NodeJS的内部模块,我们直接监听了本地一个 socket 端口,实现了一个简易服务器,地址为: 127.0.0.1:3000.
然后分别判断 req 来源的 path 判断请求的 Http 地址是什么,并返回伪造好的数据。
const http = require("http");
const url = require("url");
const hostname = "127.0.0.1";
const port = 3000;
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
res.setHeader("Content-Type", "application/json; charset=utf-8");
if (path === "/_res/session" && method === "GET") {
res.statusCode = 200;
res.end(
JSON.stringify({
uid: "_xmind_1234567890",
group_name: "",
phone: "18888888888",
group_logo: "",
user: "_xmind_1234567890",
cloud_site: "cn",
expireDate: 4093057076000,
emailhash: "1234567890",
userid: 1234567890,
if_cxm: 0,
_code: 200,
token: "1234567890",
limit: 0,
primary_email: "QiuChenly@52pojie",
fullname: "QiuChenly@52pojie",
type: null,
})
);
} else if (path === "/_api/check_vana_trial" && method === "POST") {
res.statusCode = 200;
res.end(JSON.stringify({ code: 200, _code: 200 }));
} else if (path === "/_res/get-vana-price" && method === "GET") {
res.statusCode = 200;
res.end(
JSON.stringify({
products: [
{ month: 6, price: { cny: 0, usd: 0 }, type: "bundle" },
{ month: 12, price: { cny: 0, usd: 0 }, type: "bundle" },
],
code: 200,
_code: 200,
})
);
} else if (path === "/_api/events" && method === "GET") {
res.statusCode = 200;
res.end(JSON.stringify({ code: 200, _code: 200 }));
} else if (path === "/_res/user_sub_status" && method === "GET") {
res.statusCode = 200;
res.end(JSON.stringify({ _code: 200 }));
} else if (path === "/piwik.php" && method === "POST") {
res.statusCode = 200;
res.end(JSON.stringify({ code: 200, _code: 200 }));
} else if (path.startsWith("/_res/token/") && method === "POST") {
res.statusCode = 200;
res.end(
JSON.stringify({
uid: "_xmind_1234567890",
group_name: "",
phone: "18888888888",
group_logo: "",
user: "_xmind_1234567890",
cloud_site: "cn",
expireDate: 4093057076000,
emailhash: "1234567890",
userid: 1234567890,
if_cxm: 0,
_code: 200,
token: "1234567890",
limit: 0,
primary_email: "QiuChenly@52pojie",
fullname: "QiuChenly@52pojie",
type: null,
})
);
} else if (path === "/_res/devices" && method === "POST") {
res.statusCode = 200;
res.end(
JSON.stringify({
raw_data:
"eeZRXhL4ZY6ftIFDi1JU9XA1mqJaUuiJFgmZySEz50u/HW31e4Tucf4jkCXPRJO3fsLcUYXgK9fjY4H6FnUK4Wh5xBxAdUx+3p986xXZg85fEKtyxyZmuCAff8MNvOBsOLxmJkN2i4+iyuDGQkmhhFx3k60RkeczyV80BM9lbWI=",
license: {
status: "sub",
expireTime: 4093057076000,
},
_code: 200,
})
);
} else {
res.statusCode = 404;
res.end("Not Found");
}
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
require("./hook/crypto");
require("./hook/electron");
然后利用上面说到的代码注入技术 hook掉 electron.net.request 包的请求,拦截网络请求并修改域名:
const electron = require("electron");
// 获取原始的 net 模块
const originalNet = electron.net;
// 保存原始的 request 函数
const originalRequest = originalNet.request;
// 修改 request 函数
Object.defineProperty(originalNet, "request", {
get() {
return function (options, callback) {
options["url"] = options["url"].replace(
"https://www.xmind.cn",
"http://127.0.0.1:3000"
);
console.error(
"===== Intercepting net.request with options:",
options,
callback
);
const req = originalRequest(options, callback);
// 注册 response 事件监听器
req.on("response", (response) => {
let data = "";
response.on(
"data",
function (chunk) {
data += chunk;
chunk = "FUCKING data";
this.emit("continue", chunk);
}.bind(response)
);
response.on(
"end",
function () {
// 将数据添加到缓存
// cache[options.url] = data;
// console.log("Response ----- ", data);
this.emit("continue");
}.bind(response)
);
});
return req;
};
return function (options, ...args) {
// 对 options 进行修改或者添加自己的逻辑
console.error("===== Intercepting net.request with options:", options);
// { url: 'https://www.xmind.cn/_res/user_sub_status', method: 'GET' }
// { url: 'https://www.xmind.cn/_res/devices', method: 'POST' }
// 调用原始的 request 函数
return originalRequest.call(this, options, ...args);
};
},
});
module.exports = electron;
同样 require,我们运行看看:
16843274838200.jpg (1.02 MB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
16843275045674.jpg (532.81 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
可以看出菜单已经没有 VIP 提示了,但是主界面还有升级到 Pro 的按钮。
16843276919847.jpg (59.36 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
对于这种情况我们分析代码可知:
E = (0, i.computed)(() => {
const e = (0, s.useAccountStore)();
if (!e.rawSubscriptionData) return null;
try {
return N(e.rawSubscriptionData);
} catch (e) {
return null;
}
}),
s.useAccountStore这里就是前端的 localStorage 存储,所以肯定是读取的我们伪造的信息毋庸置疑,但是为什么还提示升级?其实是我们的公钥Hook没有覆盖到 renderer 层js代码,所以我们手动替换所有的公钥:
=String.fromCharCode(45,45,45,45,45,66,69,71,73,78,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45,10,77,73,71,102,77,65,48,71,67,83,113,71,83,73,98,51,68,81,69,66,65,81,85,65,65,52,71,78,65,68,67,66,105,81,75,66,103,81,67,68,89,72,51,49,108,48,108,108,105,99,66,97,118,98,85,90,82,103,48,121,49,76,110,73,10,50,74,74,117,80,90,97,107,48,52,57,56,119,71,109,75,48,78,43,107,115,113,67,122,65,48,88,85,102,67,103,81,53,69,57,105,116,89,121,80,117,84,43,122,54,80,122,47,43,48,113,54,78,101,65,112,107,87,99,110,67,47,84,104,10,87,81,89,54,90,108,69,79,77,111,110,114,104,80,117,98,56,122,115,87,89,79,90,122,99,107,81,117,116,120,51,106,110,54,107,43,54,90,88,120,55,121,85,98,98,107,120,73,107,43,119,113,87,103,110,108,81,120,110,120,54,84,77,100,10,83,51,114,103,111,51,114,52,98,108,70,84,87,105,54,69,69,81,73,68,65,81,65,66,10,45,45,45,45,45,69,78,68,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45)
替换为
=String.fromCharCode(45,45,45,45,45,66,69,71,73,78,32,82,83,65,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45,10,77,73,71,74,65,111,71,66,65,76,117,81,88,69,76,119,117,71,107,68,68,43,73,89,84,114,114,83,78,103,122,116,87,75,54,112,100,98,77,51,98,66,68,87,86,116,81,101,80,54,111,74,87,98,89,49,48,80,67,80,50,52,87,121,10,107,120,111,47,54,110,110,48,120,82,68,70,77,52,89,43,81,75,77,114,122,116,69,98,54,52,74,118,112,75,120,85,73,52,81,70,110,110,54,55,80,68,74,116,87,51,81,110,118,118,81,78,74,75,122,79,43,120,87,70,68,78,75,90,10,119,66,53,107,80,90,48,87,71,82,79,66,103,65,87,106,112,50,47,118,54,104,85,78,47,49,43,74,87,111,73,119,68,105,108,112,97,48,76,119,72,90,56,79,77,118,99,121,117,47,54,108,65,103,77,66,65,65,69,61,10,45,45,45,45,45,69,78,68,32,82,83,65,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45)
下载我写好的 js 文件,解压到 main文件夹内,然后在 main.js 文件头部增加一行"require("./hook")"即可。
16843293355286.jpg (370.58 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
这里不用 vscode 替换,因为 vscode换完会自动格式化代码,导致代码出现异常,所以用文本编辑器暴力替换。
替换完打包重新运行看看:
16843293910524.jpg (556.36 KB, 下载次数: 0)
下载附件
2023-5-17 21:54 上传
成功拿下。
压下内心的激动,少年用力的喝了口自来水。想起父母临别前的叮嘱:“三年内千万不要去报仇!时机尚未成熟,尔等还需隐忍三年!”
少年闭上了双眼,三年.....
0x02 打包&Windows Hook
这三年少年或游山玩水,或进入红尘,不仅没有浇灭内心复仇的火焰,反而想要在下一届CTF破之力天梯排位上手刃仇人的心越发坚定!
三年之期已到,龙王出世!
2023届全球CTF大会依然是热闹非凡,有众多顶级大手子群英荟聚。而聚光灯下,少年静静坐在台上,冷冷的看着 XMind丶顶针珍珠。
“这场 Rank 由废柴之称的“秋城落叶”和Xmind丶顶针珍珠,最强者和最弱者的对决究竟是一方完全惨败还是另一方一鸣惊人?让我们拭目以待!”主持人声嘶力竭的吼道,话音刚落台下便爆发出了尖叫声,显然顶针珍珠的粉丝在为他加油呐喊!
“这1!次,我要狠狠的测测你的瑞克5!”Xmind丶顶针珍珠不屑的说。
这一次,我要拿回属于我的荣耀!
少年眼神火热的看着 CTF 大会最高荣誉奖杯,冷笑道:“当年你欺我年少无知,今日我便双手奉还!”
少年冷笑一声,便排出四文大钱,高声叫到:“你可知道Nodejs的js有几种Hook劫持方法?”
话音刚落,便展示出 macOS 上的完整 XMind 破解版,让台下数万观众一起尖叫起来!
“是他!他回来了!那个男人回来了!”
“没错!这个自信睥睨的气息!是他!就是他!”
“没想到三年后竟然回到巅峰!此子实力竟然恐怖如斯!”
”本以为又是一场毫无悬念的Rank,没想到曾经陨落的天才居然绝地反击!实力更胜从前!“
”阿弥陀佛,这就是戒色的功劳,大家记得要戒色!“
台下观众的骚动没有影响到少年分毫,而此时顶针珍珠却是满头大汗!没想到这小子竟然偷偷恢复了实力!当下却也强撑道:”这macOS版本不过是没有加密罢了,且看你如何破我的Windows版本bytecode!“
原来这顶针珍珠自信无人能修改 bytecode,当下放下了心,却看到少年那脸上的冷笑,心中咯噔一跳,难道....
"我早知道尔等要垂死挣扎,看招!" 少年冷笑着打开 Parallels Desktop 18.1.1,这也是少年当年巅峰时期的得意之作
没想到Windows 下 Hook 破解的操作竟和 macOS 下一模一样!真的做到的通杀!
临时文件夹的路径=随便找个目录 比如D:/code即可
app.asar的路径=Xmind 安装目录中的 resources 文件夹中的app.asar文件完整路径
LB87(`X4N{72SP{0XQNMF2R.png (146.23 KB, 下载次数: 0)
下载附件
2023-5-17 23:52 上传
只见少年熟练的在 Windows 下安装 nodejs最新版本,cmd执行 npm i -g asar 安装 asar 工具包,随后打开 cmd 执行 "asar extract app.asar的路径 临时文件夹的路径"解包 asar 文件为源代码。
T}04~OXQXJ14)~CT$N2{S5G.png (171.25 KB, 下载次数: 0)
下载附件
2023-5-17 23:52 上传
extract表示解包
pack表示打包
得到了 asar 解包后的文件,照旧将附件解压出来的hook.js文件和hook文件夹复制到asar文件解包出来的 main文件夹中
G3]VV~M]CEEJ(_$(TKP}W~4.png (609.58 KB, 下载次数: 0)
下载附件
2023-5-17 23:52 上传
完成后如图所示。
打开main.js 在头部加入一行"require("./hook");",记住千万要顶部加入一行,并且结尾要有";"号,防止编译出错。至于为什么不加分号编译会出错,懂得都懂。
接下来Sublime Text 搜索替换所有js 里面的的公钥为我的 RSA 公钥,具体操作和替换的代码在上面有,仔细查看。全部替换并保存所有文件后并打包回 app.asar就完成了!
解包出来所有的js文件批量搜索替换即可,不用一个个去替换。
=String.fromCharCode(45,45,45,45,45,66,69,71,73,78,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45,10,77,73,71,102,77,65,48,71,67,83,113,71,83,73,98,51,68,81,69,66,65,81,85,65,65,52,71,78,65,68,67,66,105,81,75,66,103,81,67,68,89,72,51,49,108,48,108,108,105,99,66,97,118,98,85,90,82,103,48,121,49,76,110,73,10,50,74,74,117,80,90,97,107,48,52,57,56,119,71,109,75,48,78,43,107,115,113,67,122,65,48,88,85,102,67,103,81,53,69,57,105,116,89,121,80,117,84,43,122,54,80,122,47,43,48,113,54,78,101,65,112,107,87,99,110,67,47,84,104,10,87,81,89,54,90,108,69,79,77,111,110,114,104,80,117,98,56,122,115,87,89,79,90,122,99,107,81,117,116,120,51,106,110,54,107,43,54,90,88,120,55,121,85,98,98,107,120,73,107,43,119,113,87,103,110,108,81,120,110,120,54,84,77,100,10,83,51,114,103,111,51,114,52,98,108,70,84,87,105,54,69,69,81,73,68,65,81,65,66,10,45,45,45,45,45,69,78,68,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45)
替换为
=String.fromCharCode(45,45,45,45,45,66,69,71,73,78,32,82,83,65,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45,10,77,73,71,74,65,111,71,66,65,76,117,81,88,69,76,119,117,71,107,68,68,43,73,89,84,114,114,83,78,103,122,116,87,75,54,112,100,98,77,51,98,66,68,87,86,116,81,101,80,54,111,74,87,98,89,49,48,80,67,80,50,52,87,121,10,107,120,111,47,54,110,110,48,120,82,68,70,77,52,89,43,81,75,77,114,122,116,69,98,54,52,74,118,112,75,120,85,73,52,81,70,110,110,54,55,80,68,74,116,87,51,81,110,118,118,81,78,74,75,122,79,43,120,87,70,68,78,75,90,10,119,66,53,107,80,90,48,87,71,82,79,66,103,65,87,106,112,50,47,118,54,104,85,78,47,49,43,74,87,111,73,119,68,105,108,112,97,48,76,119,72,90,56,79,77,118,99,121,117,47,54,108,65,103,77,66,65,65,69,61,10,45,45,45,45,45,69,78,68,32,82,83,65,32,80,85,66,76,73,67,32,75,69,89,45,45,45,45,45)
替换示例:
2TDLE3K3W1ZVOF9TV3V8TNF.png (708.02 KB, 下载次数: 0)
下载附件
2023-5-17 23:59 上传
打包: cmd执行 "asar pack 临时文件夹的路径 app.asar的路径"
打开 Xmind 后登录账号 123 密码 123
随后便用力打开xmind:
0ae2d8fd708126a156abb158648e3ba9.png (819.13 KB, 下载次数: 0)
下载附件
2023-5-17 21:53 上传
"这不可能!"Xmind丶顶针珍珠惊呼道,惊骇溢于言表!台下更是爆发出阵阵尖叫!
“回来了,一切都回来了!”
少年站在聚光灯下,享受着这awesome的moment,哈哈狂笑道:“你....输了!”
Credit&Other
学习 Hook 文件:
Hook.zip
(3.52 KB, 下载次数: 34, 售价: 1 CB吾爱币)
2023-5-17 21:52 上传
点击文件名下载附件
售价: 1 CB吾爱币 [记录]
[购买]
下载积分: 吾爱币 -1 CB
今天被包工头♀️骂了,说我水泥拌的太稀了。
包工头把我的铁锹锤烂了,问我水是不是不要钱。
我不敢反驳,他♀️不知道我只是拌水泥的时候很想你,眼泪掉进了水泥里。
68f9f5d17652a95844fbce5d579d718f_0.jpg (247.98 KB, 下载次数: 0)
下载附件
2023-5-17 22:05 上传