diff --git a/tools/bytejs.js b/tools/bytejs.js new file mode 100644 index 0000000..d667436 --- /dev/null +++ b/tools/bytejs.js @@ -0,0 +1,108 @@ +// makebytejs.js +const vm = require('vm'); +const fs = require('fs').promises; +const _module = require('module'); +const v8 = require('v8'); +v8.setFlagsFromString('--no-lazy'); + +async function compileFile(filePath) { + const code = await fs.readFile(filePath, 'utf-8'); + const script = new vm.Script(_module.wrap(code)); + const bytecode = script.createCachedData(); + await fs.writeFile(filePath.replace(/\.js$/i, '.bytecode'), bytecode); +} +compileFile('./test.js'); + + + +// runbytejs.js +const _module = require('module'); +const path = require('path'); +const fs = require('fs') +const vm = require('vm'); +const v8 = require('v8'); +v8.setFlagsFromString('--no-flush-bytecode'); +function validateString(value, name) { + if (typeof value !== 'string') { + throw new Error(`${name} is not string`); + } +} +function makeRequireFunction(mod) { + const Module = mod.constructor; + const require = function require(path) { + return mod.require(path); + }; + require.resolve = function resolve(request, options) { + validateString(request, 'request'); + return Module._resolveFilename(request, mod, false, options); + } + require.resolve.paths = function paths(request) { + validateString(request, 'request'); + return Module._resolveLookupPaths(request, mod); + }; + require.main = process.mainModule; + require.extensions = Module._extensions; + require.cache = Module._cache; + return require; +} +const HeaderOffsetMap = { + 'magic': 0, + 'version_hash': 4, + 'source_hash': 8, + 'flag_hash': 12 +}; +let _flag_buf; +function getFlagBuf() { + if (!_flag_buf) { + const script = new vm.Script(""); + _flag_buf = getHeader(script.createCachedData(), 'flag_hash'); + } + return _flag_buf; +} +function getHeader(buffer, type) { + const offset = HeaderOffsetMap[type]; + return buffer.slice(offset, offset + 4); +} +function setHeader(buffer, type, vBuffer) { + vBuffer.copy(buffer, HeaderOffsetMap[type]); +} +function buf2num(buf) { + // 注意字节序问题 + let ret = 0; + ret |= buf[3] << 24; + ret |= buf[2] << 16; + ret |= buf[1] << 8; + ret |= buf[0]; + return ret; +} +function loadBytecode(filePath) { + const bytecode = fs.readFileSync(filePath, null); + console.log(bytecode.toString('latin1')) + setHeader(bytecode, 'flag_hash', getFlagBuf()); + const sourceHash = buf2num(getHeader(bytecode, 'source_hash')); + const script = new vm.Script(' '.repeat(sourceHash), { + filename: filePath, + cachedData: bytecode, + lineOffset: 0, + displayErrors: true + }); + if (script.cachedDataRejected) { + throw new Error('something is wrong'); + } + return script; +} +_module._extensions['.bytecode'] = function (module, filename) { + const script = loadBytecode(filename, false); + const wrapperFn = script.runInThisContext({ + filename: filename, + displayErrors: true, + lineOffset: 0, + columnOffset: 0, + }); + const require = makeRequireFunction(module); + wrapperFn.bind(module.exports)(module.exports, require, module, filename, path.dirname(filename)); +} + +require('./test.bytecode') + +console.log(window.top == window.self) \ No newline at end of file