当前位置: 首页 > news >正文

中控IFace考勤机二开内存问题解决方案

簇防敖墒0x00 前言

拿到一个需要逆向分析的 JS start.js。

目标环境:

Node.js:16.14.0

对应 V8:9.4.146.24-node.20(flag hash ed0ab240)

核心代码如下:

const vm = require('vm');

const v8 = require('v8');

const zlib = require('zlib');

const fs = require('fs');

const path = require('path');

const Module = require('module');

v8.setFlagsFromString('--no-lazy');

v8.setFlagsFromString('--no-flush-bytecode');

global.generateScript=function(cachedData, filename) {

cachedData = zlib.brotliDecompressSync(cachedData);

fixBytecode(cachedData);

const length = readSourceHash(cachedData);

let dummyCode = '';

if (length > 1) {

dummyCode = '"' + '\u200b'.repeat(length - 2) + '"';

}

const script = new vm.Script(dummyCode, {

cachedData,

filename

});

if (script.cachedDataRejected) {

throw new Error('');

}

return script;

}

global.compileCode = function(javascriptCode, compress) {

const script = new vm.Script(javascriptCode, {

produceCachedData: true

});

let bytecodeBuffer = (script.createCachedData && script.createCachedData.call) ?

script.createCachedData() :

script.cachedData;

if (compress) bytecodeBuffer = zlib.brotliCompressSync(bytecodeBuffer);

return bytecodeBuffer;

};

global.fixBytecode = function(bytecodeBuffer) {

const dummyBytecode = compileCode('');

dummyBytecode.subarray(12, 16).copy(bytecodeBuffer, 12);

};

global.readSourceHash = function(bytecodeBuffer) {

return bytecodeBuffer.subarray(8, 12).reduce((sum, number, power) => sum += number * Math.pow(256, power), 0);

};

try {

Module._extensions['.jsc'] = function(fileModule, filename) {

const data = fs.readFileSync(filename, 'utf8')

const bytecodeBuffer = Buffer.from(data, 'base64');

const script = generateScript(bytecodeBuffer, filename);

function require(id) {

return fileModule.require(id);

}

require.resolve = function(request, options) {

return Module._resolveFilename(request, fileModule, false, options);

};

if (process.main) {

require.main = process.main;

}

require.extensions = Module._extensions;

require.cache = Module._cache;

const compiledWrapper = script.runInThisContext({

filename: filename,

lineOffset: 0,

columnOffset: 0,

displayErrors: true

});

const dirname = path.dirname(filename);

const args = [

fileModule.exports, require, fileModule, filename, dirname, process, global

];

return compiledWrapper.apply(fileModule.exports, args);

};

} catch (ex) {

console.error('xrequire:' + ex.message);

}

require("${codeScript}")

经过搜索资料发现:

这就是V8 cachedData / bytenode 方案。

0x01 第一次尝试:View8

定位到 bytecode 后,我先上了 View8:

https://github.com/suleram/View8

然后配套 9.4.146.24.exe 去跑反编译。

发现问题:

输出一点代码后自动崩溃退出。

View8 因 d8 崩溃只导出 23 个外围函数,关键的函数基本丢失。

当时第一反应是项目太久没维护,又去github找别的项目。

0x02 第二次尝试:jsc2js

又看了 jsc2js:

https://github.com/xqy2006/jsc2js

这个仓库新一些,也有 patch + CI 体系。

把 patch 套到 v8 9.4.146.24,结果仍然和第一轮差不多。

这时候基本就炸毛了(先躺一会):

字节码本来就不太好 hook,现成工具又不稳定。

于是查阅相关资料:

https://www.aynakeya.com/articles/ctf/a-quick-guide-to-disassemble-v8-bytecode/

https://rce.moe/2025/01/07/v8-bytecode-decompiler/

V8 bytecode 就是 V8 自己序列化的一段内部数据。

想稳定拿结果,必须回到 V8 源码层改输出逻辑。

不同 V8 版本在字节码层差异很大,尤其是 opcode、参数语义、寄存器布局。

0x03 第三次尝试:拉 V8 仓库

@echo off

set PATH=E:\Dev\SDKs\depot_tools;%PATH%

set DEPOT_TOOLS_WIN_TOOLCHAIN=0

mkdir v8_941

cd v8_941

echo solutions = [{ > .gclient

echo "name": "v8", >> .gclient

echo "url": "https://chromium.googlesource.com/v8/v8.git@9.4.146.24", >> .gclient

echo "deps_file": "DEPS", >> .gclient

echo "managed": False, >> .gclient

echo "custom_deps": {}, >> .gclient

echo }] >> .gclient

git clone --depth=1 --branch 9.4.146.24 https://chromium.googlesource.com/v8/v8.git v8

gclient sync -D --no-history

0x04 patch + 编译参数

先patch,再单独构建 d8:

cd /d

\v8_941\v8

python ..\..\apply_patches_v8_94.py .

gn gen out/release

ninja -C out/release d8

构建参数:

dcheck_always_on = false

is_clang = false

is_component_build = false

is_debug = false

target_cpu = "x64"

use_custom_libcxx = false

v8_monolithic = true

v8_use_external_startup_data = false

v8_static_library = true

v8_enable_disassembler = true

v8_enable_object_print = true

treat_warnings_as_errors = false

v8_enable_pointer_compression = false

v8_enable_31bit_smis_on_64bit_arch = false

v8_enable_lite_mode = false

v8_enable_i18n_support = true

v8_enable_webassembly = true

0x05 改动阶段

真男人就要硬刚v8,部分diff我就不贴出来了,把问题和思路贴一下,欸嘿~

0x06 问题一:cachedData 反序列化被拒绝

CodeSerializer::Deserialize 默认会严检 magic/version/flags/hash/checksum/source hash。

如果任何一项没通过,它会直接 reject 掉这份缓存,返回空对象。

src/snapshot/code-serializer.cc:

@@ SerializedCodeData::SanityCheck

- SanityCheckResult result = SanityCheckWithoutSource();

- if (result != CHECK_SUCCESS) return result;

- ...

- return CHECK_SUCCESS;

+ return SerializedCodeData::SanityCheckResult::CHECK_SUCCESS;

@@ SerializedCodeData::SanityCheckWithoutSource

- if (this->size_ < kHeaderSize) return INVALID_HEADER;

- uint32_t magic_number = GetMagicNumber();

- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;

- ...

- if (Checksum(ChecksummedContent()) != c) return CHECKSUM_MISMATCH;

- return CHECK_SUCCESS;

+ return SerializedCodeData::SanityCheckResult::CHECK_SUCCESS;

src/snapshot/deserializer.cc:

@@ Deserializer::Deserializer

- CHECK_EQ(magic_number_, SerializedData::kMagicNumber);

+ /*

+ CHECK_EQ(magic_number_, SerializedData::kMagicNumber);

+ */

@@ ReadSingleBytecodeData

+ std::fprintf(stderr, "[FATAL] Unknown serializer bytecode: 0x%02x\n", data);

0x07 问题二:反汇编/打印阶段栈溢出

这里就是之前view8打印不出来的主要问题:

BytecodeArray::Disassemble

打常量池

命中 SharedFunctionInfo

SharedFunctionInfoPrint

再次 Disassemble

深度叠加,最终栈爆

改动:TLS guard + SEH

src/diagnostics/objects-printer.cc:

+thread_local int g_in_bytecode_disasm = 0;

...

+ ++g_in_bytecode_disasm;

+ hbc->Disassemble(*(c->os));

+ --g_in_bytecode_disasm;

@@ SharedFunctionInfoPrint

- PrintSourceCode(os);

+ // PrintSourceCode(os);

+ int exc = SehWrapCall(DoBcDisasm, &ctx);

+ if (exc != 0) { os << ""; }

src/objects/objects.cc:

+extern thread_local int g_in_bytecode_disasm;

+void SafePrintSharedFunctionInfo(...);

+void SafePrintFixedArray(...);

...

case SHARED_FUNCTION_INFO_TYPE:

+ if (g_in_bytecode_disasm > 0) { break; }

+ SafePrintSharedFunctionInfo(shared, os);

case FIXED_ARRAY_TYPE:

+ SafePrintFixedArray(FixedArray::cast(*this), os);

对应:d8 入口改成 BFS 平铺

src/d8/d8.cc:

+void Shell::LoadBytecode(...)

+std::deque> queue;

+std::unordered_set seen;

+while (!queue.empty()) { ... }

+global_template->Set(isolate, "loadBytecode",

+ FunctionTemplate::New(isolate, LoadBytecode));

0x08 稳定性

修 Handle 生命周期和字节码迭代稳定性

- i::HandleScope inner_scope(isolateInternal);

+ // No inner HandleScope here — child handles stored in queue/all_sfis

+ // must survive across iterations. outer_scope keeps them all alive.

...

- i::BytecodeArray handle_storage = *hbca;

- i::Handle handle(

- reinterpret_cast(&handle_storage));

- i::interpreter::BytecodeArrayIterator iterator(handle);

+ // Use hbca directly — it's a proper Handle rooted in print_scope.

+ i::interpreter::BytecodeArrayIterator iterator(hbca);

...

+ // Re-derive base_address each iteration (GC-safe)

+ i::Address base_address = hbca->GetFirstBytecodeAddress();

调试可见性 + SFI 入队条件

+ printf("[DBG] root SFI ptr = 0x%p\n", reinterpret_cast(root->ptr()));

+ printf("[DBG] root HasBytecodeArray = %d\n", root_has_bc);

...

+ printf("[DBG] cp[%d] raw=0x%p smi=%d\n", cp_index,

+ reinterpret_cast(obj.ptr()), obj.IsSmi());

...

- if (obj.IsSharedFunctionInfo()) {

+ if (!obj.IsSmi() && obj.IsSharedFunctionInfo()) {

常量池可读性增强

+const int kMaxLiteralElementsToPrint = 1024;

+std::function print_compact_obj;

...

+if (value.IsArrayBoilerplateDescription()) { ... }

+if (value.IsFixedArray()) { ... }

+if (value.IsFixedDoubleArray()) { ... }

...

+print_compact_obj(obj, 0);

其它

src/objects/string.cc:

-if (len > kMaxShortPrintLength) {

+// if (len > kMaxShortPrintLength) {

...

-accumulator->Add("%c", c);

+accumulator->Add("\\u%04x", c);

http://www.jsqmd.com/news/470308/

相关文章:

  • 【IEEE出版、连续五届EI稳定检索、211高校主办】第六届信号图像处理与通信国际学术会议(ICSIPC 2026)
  • 使用 C++、YOLO 和 ONNX Runtime 实现实时目标检测的完整教程整理与代码实现指南。
  • Flutter 三方库 graph_kit 的鸿蒙化适配指南 - 让逻辑治理回归“拓扑之美”,打造鸿蒙应用专家级的图算法与依赖治理中台
  • 教你如何用GPT-来分析你的dump文件定位内存泄漏问题——避免无效加班必备神器
  • 高可用高并发微服务架构设计:Nginx 与 API Gateway 的协同实践
  • Xsvn:鸿蒙系统首款SVN客户端
  • ImageToTensor函数的完整实现版本,專門用在 .NET MAUI + YOLOv8 ONNX 推理流程中
  • 基于51单片机手机无线蓝牙APP遥控智能车系统论文
  • DeepSORT 参数调优指南(实用版,针对工业/安防/实时场景)
  • 使用surging 常见的几个问题
  • HTML粒子爱心代码
  • 指针与数组:高效访问的秘诀
  • 918. 环形子数组的最大和
  • JavaScript性能优化实战孟盎
  • 筑牢 AI Agent 关键业务落地的生命线:数据治理与 AI 治理的全体系解析与落地指南
  • 字节一面---客户端开发实习生
  • JavaScript性能优化实战郊蒲
  • 2026年数智项目管理品牌格局观察:平台化与业财融合趋势
  • 2026年四川达州渠县TOP1电器门店:品类超120种堪称全城最全?
  • 比赛吗,就应该有比赛的样子。规则不能够太容易了
  • 跟我学C++中级篇—悲观和乐观锁
  • OpenClaw 生态网站导航推荐
  • Python电商全维数据智能分析与随机森林销量预测系统 Django 可视化 机器学习 爬虫 大数据 大模型 agent 深度学习 计算机毕业设计源码(建议收藏)✅
  • Ruby 类案例
  • Windows实操
  • 嘎嘎降AI为什么能支持9大检测平台?多平台兼容的秘密
  • 双系统安装
  • 基于 PLC 的工业锅炉过程控制程序设计及其仿真
  • 基于离散韦格纳分布(DWVD)结合卷积神经网络(CNN)与长短期记忆网络(LSTM)的故障诊断研究附Matlab代码
  • 2026年口碑好的电动喷泵推进器厂家推荐:东莞冲浪板电动喷泵/卡丁船电动喷泵推进器行业内口碑厂家推荐 - 行业平台推荐