@zhuixin/engine 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/engine-main.js +1095 -140
  2. package/package.json +6 -4
@@ -363,25 +363,25 @@ var require_utils = __commonJS({
363
363
  }
364
364
  mkdirSync(folder);
365
365
  };
366
- Utils.prototype.writeFileTo = function(path9, content, overwrite, attr) {
366
+ Utils.prototype.writeFileTo = function(path10, content, overwrite, attr) {
367
367
  const self = this;
368
- if (self.fs.existsSync(path9)) {
368
+ if (self.fs.existsSync(path10)) {
369
369
  if (!overwrite) return false;
370
- var stat = self.fs.statSync(path9);
370
+ var stat = self.fs.statSync(path10);
371
371
  if (stat.isDirectory()) {
372
372
  return false;
373
373
  }
374
374
  }
375
- var folder = pth.dirname(path9);
375
+ var folder = pth.dirname(path10);
376
376
  if (!self.fs.existsSync(folder)) {
377
377
  self.makeDir(folder);
378
378
  }
379
379
  var fd;
380
380
  try {
381
- fd = self.fs.openSync(path9, "w", 438);
381
+ fd = self.fs.openSync(path10, "w", 438);
382
382
  } catch (e) {
383
- self.fs.chmodSync(path9, 438);
384
- fd = self.fs.openSync(path9, "w", 438);
383
+ self.fs.chmodSync(path10, 438);
384
+ fd = self.fs.openSync(path10, "w", 438);
385
385
  }
386
386
  if (fd) {
387
387
  try {
@@ -390,31 +390,31 @@ var require_utils = __commonJS({
390
390
  self.fs.closeSync(fd);
391
391
  }
392
392
  }
393
- self.fs.chmodSync(path9, attr || 438);
393
+ self.fs.chmodSync(path10, attr || 438);
394
394
  return true;
395
395
  };
396
- Utils.prototype.writeFileToAsync = function(path9, content, overwrite, attr, callback) {
396
+ Utils.prototype.writeFileToAsync = function(path10, content, overwrite, attr, callback) {
397
397
  if (typeof attr === "function") {
398
398
  callback = attr;
399
399
  attr = void 0;
400
400
  }
401
401
  const self = this;
402
- self.fs.exists(path9, function(exist) {
402
+ self.fs.exists(path10, function(exist) {
403
403
  if (exist && !overwrite) return callback(false);
404
- self.fs.stat(path9, function(err, stat) {
404
+ self.fs.stat(path10, function(err, stat) {
405
405
  if (exist && stat.isDirectory()) {
406
406
  return callback(false);
407
407
  }
408
- var folder = pth.dirname(path9);
408
+ var folder = pth.dirname(path10);
409
409
  self.fs.exists(folder, function(exists) {
410
410
  if (!exists) self.makeDir(folder);
411
- self.fs.open(path9, "w", 438, function(err2, fd) {
411
+ self.fs.open(path10, "w", 438, function(err2, fd) {
412
412
  if (err2) {
413
- self.fs.chmod(path9, 438, function() {
414
- self.fs.open(path9, "w", 438, function(err3, fd2) {
413
+ self.fs.chmod(path10, 438, function() {
414
+ self.fs.open(path10, "w", 438, function(err3, fd2) {
415
415
  self.fs.write(fd2, content, 0, content.length, 0, function() {
416
416
  self.fs.close(fd2, function() {
417
- self.fs.chmod(path9, attr || 438, function() {
417
+ self.fs.chmod(path10, attr || 438, function() {
418
418
  callback(true);
419
419
  });
420
420
  });
@@ -424,13 +424,13 @@ var require_utils = __commonJS({
424
424
  } else if (fd) {
425
425
  self.fs.write(fd, content, 0, content.length, 0, function() {
426
426
  self.fs.close(fd, function() {
427
- self.fs.chmod(path9, attr || 438, function() {
427
+ self.fs.chmod(path10, attr || 438, function() {
428
428
  callback(true);
429
429
  });
430
430
  });
431
431
  });
432
432
  } else {
433
- self.fs.chmod(path9, attr || 438, function() {
433
+ self.fs.chmod(path10, attr || 438, function() {
434
434
  callback(true);
435
435
  });
436
436
  }
@@ -439,7 +439,7 @@ var require_utils = __commonJS({
439
439
  });
440
440
  });
441
441
  };
442
- Utils.prototype.findFiles = function(path9) {
442
+ Utils.prototype.findFiles = function(path10) {
443
443
  const self = this;
444
444
  function findSync(dir, pattern, recursive) {
445
445
  if (typeof pattern === "boolean") {
@@ -448,16 +448,16 @@ var require_utils = __commonJS({
448
448
  }
449
449
  let files = [];
450
450
  self.fs.readdirSync(dir).forEach(function(file) {
451
- const path10 = pth.join(dir, file);
452
- const stat = self.fs.statSync(path10);
453
- if (!pattern || pattern.test(path10)) {
454
- files.push(pth.normalize(path10) + (stat.isDirectory() ? self.sep : ""));
451
+ const path11 = pth.join(dir, file);
452
+ const stat = self.fs.statSync(path11);
453
+ if (!pattern || pattern.test(path11)) {
454
+ files.push(pth.normalize(path11) + (stat.isDirectory() ? self.sep : ""));
455
455
  }
456
- if (stat.isDirectory() && recursive) files = files.concat(findSync(path10, pattern, recursive));
456
+ if (stat.isDirectory() && recursive) files = files.concat(findSync(path11, pattern, recursive));
457
457
  });
458
458
  return files;
459
459
  }
460
- return findSync(path9, void 0, true);
460
+ return findSync(path10, void 0, true);
461
461
  };
462
462
  Utils.prototype.findFilesAsync = function(dir, cb) {
463
463
  const self = this;
@@ -512,14 +512,14 @@ var require_utils = __commonJS({
512
512
  return "UNSUPPORTED (" + method + ")";
513
513
  }
514
514
  };
515
- Utils.canonical = function(path9) {
516
- if (!path9) return "";
517
- const safeSuffix = pth.posix.normalize("/" + path9.split("\\").join("/"));
515
+ Utils.canonical = function(path10) {
516
+ if (!path10) return "";
517
+ const safeSuffix = pth.posix.normalize("/" + path10.split("\\").join("/"));
518
518
  return pth.join(".", safeSuffix);
519
519
  };
520
- Utils.zipnamefix = function(path9) {
521
- if (!path9) return "";
522
- const safeSuffix = pth.posix.normalize("/" + path9.split("\\").join("/"));
520
+ Utils.zipnamefix = function(path10) {
521
+ if (!path10) return "";
522
+ const safeSuffix = pth.posix.normalize("/" + path10.split("\\").join("/"));
523
523
  return pth.posix.join(".", safeSuffix);
524
524
  };
525
525
  Utils.findLast = function(arr, callback) {
@@ -536,9 +536,9 @@ var require_utils = __commonJS({
536
536
  prefix = pth.resolve(pth.normalize(prefix));
537
537
  var parts = name.split("/");
538
538
  for (var i = 0, l = parts.length; i < l; i++) {
539
- var path9 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
540
- if (path9 === prefix || path9.startsWith(prefix + pth.sep)) {
541
- return path9;
539
+ var path10 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
540
+ if (path10 === prefix || path10.startsWith(prefix + pth.sep)) {
541
+ return path10;
542
542
  }
543
543
  }
544
544
  return pth.normalize(pth.join(prefix, pth.basename(name)));
@@ -585,8 +585,8 @@ var require_fattr = __commonJS({
585
585
  "node_modules/.pnpm/adm-zip@0.5.18/node_modules/adm-zip/util/fattr.js"(exports2, module2) {
586
586
  "use strict";
587
587
  var pth = require("path");
588
- module2.exports = function(path9, { fs: fs10 }) {
589
- var _path = path9 || "", _obj = newAttr(), _stat = null;
588
+ module2.exports = function(path10, { fs: fs12 }) {
589
+ var _path = path10 || "", _obj = newAttr(), _stat = null;
590
590
  function newAttr() {
591
591
  return {
592
592
  directory: false,
@@ -597,8 +597,8 @@ var require_fattr = __commonJS({
597
597
  atime: 0
598
598
  };
599
599
  }
600
- if (_path && fs10.existsSync(_path)) {
601
- _stat = fs10.statSync(_path);
600
+ if (_path && fs12.existsSync(_path)) {
601
+ _stat = fs12.statSync(_path);
602
602
  _obj.directory = _stat.isDirectory();
603
603
  _obj.mtime = _stat.mtime;
604
604
  _obj.atime = _stat.atime;
@@ -15019,7 +15019,7 @@ var require_BigInteger = __commonJS({
15019
15019
  var require_bplistParser = __commonJS({
15020
15020
  "node_modules/.pnpm/bplist-parser@0.3.2/node_modules/bplist-parser/bplistParser.js"(exports2) {
15021
15021
  "use strict";
15022
- var fs10 = require("fs");
15022
+ var fs12 = require("fs");
15023
15023
  var bigInt = require_BigInteger();
15024
15024
  var debug = false;
15025
15025
  exports2.maxObjectSize = 100 * 1e3 * 1e3;
@@ -15046,7 +15046,7 @@ var require_bplistParser = __commonJS({
15046
15046
  if (Buffer.isBuffer(fileNameOrBuffer)) {
15047
15047
  return tryParseBuffer(fileNameOrBuffer);
15048
15048
  }
15049
- fs10.readFile(fileNameOrBuffer, function(err, data) {
15049
+ fs12.readFile(fileNameOrBuffer, function(err, data) {
15050
15050
  if (err) {
15051
15051
  reject(err);
15052
15052
  return callback(err);
@@ -15057,7 +15057,7 @@ var require_bplistParser = __commonJS({
15057
15057
  };
15058
15058
  exports2.parseFileSync = function(fileNameOrBuffer) {
15059
15059
  if (!Buffer.isBuffer(fileNameOrBuffer)) {
15060
- fileNameOrBuffer = fs10.readFileSync(fileNameOrBuffer);
15060
+ fileNameOrBuffer = fs12.readFileSync(fileNameOrBuffer);
15061
15061
  }
15062
15062
  return parseBuffer2(fileNameOrBuffer);
15063
15063
  };
@@ -15347,8 +15347,8 @@ var require_bplistParser = __commonJS({
15347
15347
  });
15348
15348
 
15349
15349
  // src/engine-main.ts
15350
- var import_node_fs9 = __toESM(require("fs"));
15351
- var import_node_path8 = __toESM(require("path"));
15350
+ var import_node_fs11 = __toESM(require("fs"));
15351
+ var import_node_path9 = __toESM(require("path"));
15352
15352
  var import_node_readline = __toESM(require("readline"));
15353
15353
 
15354
15354
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
@@ -15829,8 +15829,8 @@ function getErrorMap() {
15829
15829
 
15830
15830
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
15831
15831
  var makeIssue = (params) => {
15832
- const { data, path: path9, errorMaps, issueData } = params;
15833
- const fullPath = [...path9, ...issueData.path || []];
15832
+ const { data, path: path10, errorMaps, issueData } = params;
15833
+ const fullPath = [...path10, ...issueData.path || []];
15834
15834
  const fullIssue = {
15835
15835
  ...issueData,
15836
15836
  path: fullPath
@@ -15946,11 +15946,11 @@ var errorUtil;
15946
15946
 
15947
15947
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
15948
15948
  var ParseInputLazyPath = class {
15949
- constructor(parent, value, path9, key) {
15949
+ constructor(parent, value, path10, key) {
15950
15950
  this._cachedPath = [];
15951
15951
  this.parent = parent;
15952
15952
  this.data = value;
15953
- this._path = path9;
15953
+ this._path = path10;
15954
15954
  this._key = key;
15955
15955
  }
15956
15956
  get path() {
@@ -19392,11 +19392,12 @@ var coerce = {
19392
19392
  };
19393
19393
  var NEVER = INVALID;
19394
19394
 
19395
- // node_modules/.pnpm/@zhuixin+protocol@0.2.4/node_modules/@zhuixin/protocol/dist/index.js
19395
+ // node_modules/.pnpm/@zhuixin+protocol@0.2.6/node_modules/@zhuixin/protocol/dist/index.js
19396
19396
  var PROTOCOL_VERSION = "1";
19397
19397
  var engineCapabilities = [
19398
19398
  "inspect:ipa",
19399
19399
  "inspect:mac-app",
19400
+ "inspect:pe",
19400
19401
  "extract:app",
19401
19402
  "javascript:analyze",
19402
19403
  "native:inspect",
@@ -19472,8 +19473,8 @@ var DEFINITIONS = [
19472
19473
  id: "javascript:analyze",
19473
19474
  label: "Analyze JS",
19474
19475
  description: "\u5BF9\u89E3\u5305\u5E94\u7528\u4E2D\u7684 uni-app / WebView \u4E1A\u52A1\u811A\u672C\u505A\u9759\u6001\u5206\u6790\u3002",
19475
- targetPlatforms: ["ios", "macos"],
19476
- packageFormats: ["ipa", "app"],
19476
+ targetPlatforms: ["ios", "macos", "windows"],
19477
+ packageFormats: ["ipa", "app", "exe"],
19477
19478
  requiresArtifact: true,
19478
19479
  requiresRea: true
19479
19480
  },
@@ -19515,13 +19516,12 @@ var DEFINITIONS = [
19515
19516
  },
19516
19517
  {
19517
19518
  id: "inspect:pe",
19518
- label: "Inspect PE",
19519
- description: "PE \u5934\u3001\u67B6\u6784\u3001\u8282\u533A\u3001\u5BFC\u5165\u8868\u4E0E .NET \u7EBF\u7D22\u3002",
19519
+ label: "Inspect Windows app",
19520
+ description: "Application directory layout, main executable PE headers, sections, imports, .NET clues, version resource, technology hints and Authenticode signature.",
19520
19521
  targetPlatforms: ["windows"],
19521
19522
  packageFormats: ["exe"],
19522
19523
  requiresArtifact: true,
19523
- available: false,
19524
- reason: "Windows Target Provider \u5F85 v1.1"
19524
+ builtIn: true
19525
19525
  },
19526
19526
  {
19527
19527
  id: "inspect:msix",
@@ -19531,7 +19531,7 @@ var DEFINITIONS = [
19531
19531
  packageFormats: ["msix", "appx"],
19532
19532
  requiresArtifact: true,
19533
19533
  available: false,
19534
- reason: "Windows Target Provider \u5F85 v1.1"
19534
+ reason: "Not implemented yet for Windows targets."
19535
19535
  },
19536
19536
  {
19537
19537
  id: "inspect:msi",
@@ -19541,7 +19541,7 @@ var DEFINITIONS = [
19541
19541
  packageFormats: ["msi"],
19542
19542
  requiresArtifact: true,
19543
19543
  available: false,
19544
- reason: "Windows Target Provider \u5F85 v1.1"
19544
+ reason: "Not implemented yet for Windows targets."
19545
19545
  },
19546
19546
  {
19547
19547
  id: "signature:check",
@@ -19551,7 +19551,7 @@ var DEFINITIONS = [
19551
19551
  packageFormats: ["exe", "msi", "msix", "appx"],
19552
19552
  requiresArtifact: true,
19553
19553
  available: false,
19554
- reason: "Windows Target Provider \u5F85 v1.1"
19554
+ reason: "Not implemented yet for Windows targets. inspect:pe already reports the main executable's signature."
19555
19555
  }
19556
19556
  ];
19557
19557
  var CapabilityRegistry = class {
@@ -19688,8 +19688,8 @@ function defaultWorkspaceRoot(hostPlatform, env) {
19688
19688
 
19689
19689
  // src/jobs/capability.ts
19690
19690
  var import_node_crypto = require("crypto");
19691
- var import_node_fs5 = __toESM(require("fs"));
19692
- var import_node_path5 = __toESM(require("path"));
19691
+ var import_node_fs7 = __toESM(require("fs"));
19692
+ var import_node_path6 = __toESM(require("path"));
19693
19693
 
19694
19694
  // src/errors.ts
19695
19695
  var CoreFailure = class extends Error {
@@ -20074,6 +20074,872 @@ async function inspectMacApp(bundlePath) {
20074
20074
  };
20075
20075
  }
20076
20076
 
20077
+ // src/inspectors/windowsApp.ts
20078
+ var import_node_child_process2 = require("child_process");
20079
+ var import_node_fs6 = __toESM(require("fs"));
20080
+ var import_node_path4 = __toESM(require("path"));
20081
+ var import_node_util2 = require("util");
20082
+
20083
+ // src/inspectors/pe.ts
20084
+ var import_node_fs5 = __toESM(require("fs"));
20085
+ var MACHINES = {
20086
+ 332: "x86",
20087
+ 34404: "x64",
20088
+ 448: "arm",
20089
+ 452: "arm (Thumb-2)",
20090
+ 43620: "arm64",
20091
+ 42561: "arm64ec",
20092
+ 42574: "arm64x",
20093
+ 512: "ia64"
20094
+ };
20095
+ var SUBSYSTEMS = {
20096
+ 1: "native",
20097
+ 2: "windows-gui",
20098
+ 3: "windows-console",
20099
+ 5: "os2-console",
20100
+ 7: "posix-console",
20101
+ 9: "windows-ce-gui",
20102
+ 10: "efi-application",
20103
+ 11: "efi-boot-service-driver",
20104
+ 12: "efi-runtime-driver",
20105
+ 14: "xbox",
20106
+ 16: "windows-boot-application"
20107
+ };
20108
+ var CERTIFICATE_TYPES = {
20109
+ 1: "x509",
20110
+ 2: "pkcs-signed-data",
20111
+ 3: "reserved",
20112
+ 4: "ts-stack-signed"
20113
+ };
20114
+ var MAX_SECTIONS = 96;
20115
+ var MAX_IMPORT_LIBRARIES = 256;
20116
+ var MAX_FUNCTIONS_PER_LIBRARY = 12;
20117
+ var MAX_THUNKS_PER_LIBRARY = 2e4;
20118
+ var ENTROPY_SAMPLE_BYTES = 4 * 1024 * 1024;
20119
+ var RESOURCE_MAX_DEPTH = 4;
20120
+ function fileReader(fd, size) {
20121
+ return {
20122
+ size,
20123
+ read(offset, length) {
20124
+ if (!Number.isSafeInteger(offset) || offset < 0 || length < 0) return void 0;
20125
+ if (offset + length > size) return void 0;
20126
+ const buffer = Buffer.alloc(length);
20127
+ let done = 0;
20128
+ while (done < length) {
20129
+ const count = import_node_fs5.default.readSync(fd, buffer, done, length - done, offset + done);
20130
+ if (count <= 0) return void 0;
20131
+ done += count;
20132
+ }
20133
+ return buffer;
20134
+ }
20135
+ };
20136
+ }
20137
+ function hex(value) {
20138
+ return `0x${value.toString(16)}`;
20139
+ }
20140
+ function cString(buffer, start = 0, limit = buffer.length) {
20141
+ let end = start;
20142
+ const max = Math.min(limit, buffer.length);
20143
+ while (end < max && buffer[end] !== 0) end += 1;
20144
+ return buffer.toString("latin1", start, end);
20145
+ }
20146
+ function entropyOf(buffer) {
20147
+ if (buffer.length === 0) return 0;
20148
+ const counts = new Array(256).fill(0);
20149
+ for (const byte of buffer) counts[byte] += 1;
20150
+ let entropy = 0;
20151
+ for (const count of counts) {
20152
+ if (count === 0) continue;
20153
+ const p = count / buffer.length;
20154
+ entropy -= p * Math.log2(p);
20155
+ }
20156
+ return Math.round(entropy * 100) / 100;
20157
+ }
20158
+ function isPeFile(filePath) {
20159
+ let fd;
20160
+ try {
20161
+ fd = import_node_fs5.default.openSync(filePath, "r");
20162
+ const head = Buffer.alloc(2);
20163
+ return import_node_fs5.default.readSync(fd, head, 0, 2, 0) === 2 && head[0] === 77 && head[1] === 90;
20164
+ } catch {
20165
+ return false;
20166
+ } finally {
20167
+ if (fd !== void 0) import_node_fs5.default.closeSync(fd);
20168
+ }
20169
+ }
20170
+ function inspectPeFile(filePath) {
20171
+ const fd = import_node_fs5.default.openSync(filePath, "r");
20172
+ try {
20173
+ const size = import_node_fs5.default.fstatSync(fd).size;
20174
+ return inspectPe(fileReader(fd, size));
20175
+ } finally {
20176
+ import_node_fs5.default.closeSync(fd);
20177
+ }
20178
+ }
20179
+ function inspectPe(reader) {
20180
+ const warnings = [];
20181
+ const dos = reader.read(0, 64);
20182
+ if (!dos || dos.readUInt16LE(0) !== 23117) {
20183
+ throw new Error("Not a PE file: the MZ signature is missing.");
20184
+ }
20185
+ const peOffset = dos.readUInt32LE(60);
20186
+ const signature = reader.read(peOffset, 4);
20187
+ if (!signature || signature.toString("latin1") !== "PE\0\0") {
20188
+ throw new Error("Not a PE file: the PE signature is missing.");
20189
+ }
20190
+ const coff = reader.read(peOffset + 4, 20);
20191
+ if (!coff) throw new Error("The COFF header is truncated.");
20192
+ const machine = coff.readUInt16LE(0);
20193
+ const sectionCount = coff.readUInt16LE(2);
20194
+ const timeDateStamp = coff.readUInt32LE(4);
20195
+ const optionalSize = coff.readUInt16LE(16);
20196
+ const characteristics = coff.readUInt16LE(18);
20197
+ const optionalOffset = peOffset + 24;
20198
+ const optional = reader.read(optionalOffset, Math.min(optionalSize, 240));
20199
+ if (!optional || optional.length < 96) {
20200
+ throw new Error("The optional header is truncated.");
20201
+ }
20202
+ const magic = optional.readUInt16LE(0);
20203
+ if (magic !== 267 && magic !== 523) {
20204
+ throw new Error(`Unsupported optional header magic ${hex(magic)}.`);
20205
+ }
20206
+ const plus = magic === 523;
20207
+ const directoriesOffset = plus ? 112 : 96;
20208
+ const entryPointRva = optional.readUInt32LE(16);
20209
+ const imageBase = plus ? optional.readBigUInt64LE(24) : BigInt(optional.readUInt32LE(28));
20210
+ const linker = `${optional[2]}.${optional[3]}`;
20211
+ const minimumOs = `${optional.readUInt16LE(40)}.${optional.readUInt16LE(42)}`;
20212
+ const subsystemId = optional.readUInt16LE(68);
20213
+ const dllCharacteristics = optional.readUInt16LE(70);
20214
+ const declaredDirectories = optional.length >= directoriesOffset ? optional.readUInt32LE(directoriesOffset - 4) : 0;
20215
+ const directory = (index) => {
20216
+ if (index >= declaredDirectories || index >= 16) return void 0;
20217
+ const at = directoriesOffset + index * 8;
20218
+ if (at + 8 > optional.length) return void 0;
20219
+ const rva = optional.readUInt32LE(at);
20220
+ const sizeValue = optional.readUInt32LE(at + 4);
20221
+ return rva === 0 && sizeValue === 0 ? void 0 : { rva, size: sizeValue };
20222
+ };
20223
+ const sections = [];
20224
+ const sectionTableOffset = optionalOffset + optionalSize;
20225
+ const boundedCount = Math.min(sectionCount, MAX_SECTIONS);
20226
+ if (sectionCount > MAX_SECTIONS) {
20227
+ warnings.push(`The file declares ${sectionCount} sections; only the first ${MAX_SECTIONS} were read.`);
20228
+ }
20229
+ for (let index = 0; index < boundedCount; index += 1) {
20230
+ const raw = reader.read(sectionTableOffset + index * 40, 40);
20231
+ if (!raw) {
20232
+ warnings.push("The section table is truncated.");
20233
+ break;
20234
+ }
20235
+ const sectionCharacteristics = raw.readUInt32LE(36);
20236
+ const rawSize = raw.readUInt32LE(16);
20237
+ const rawOffset = raw.readUInt32LE(20);
20238
+ const section = {
20239
+ name: cString(raw, 0, 8),
20240
+ virtualSize: raw.readUInt32LE(8),
20241
+ rawSize,
20242
+ rawOffset,
20243
+ characteristics: sectionCharacteristics,
20244
+ executable: (sectionCharacteristics & 536870912) !== 0,
20245
+ writable: (sectionCharacteristics & 2147483648) !== 0
20246
+ };
20247
+ if (rawSize > 0 && rawOffset > 0) {
20248
+ const sample = reader.read(rawOffset, Math.min(rawSize, ENTROPY_SAMPLE_BYTES));
20249
+ if (sample) section.entropy = entropyOf(sample);
20250
+ }
20251
+ sections.push(section);
20252
+ }
20253
+ const sectionRva = raws(sectionTableOffset, reader, boundedCount);
20254
+ const rvaToOffset = (rva) => {
20255
+ for (const entry of sectionRva) {
20256
+ const span = Math.max(entry.virtualSize, entry.rawSize);
20257
+ if (rva >= entry.rva && rva < entry.rva + span) {
20258
+ const offset = entry.rawOffset + (rva - entry.rva);
20259
+ return offset < reader.size ? offset : void 0;
20260
+ }
20261
+ }
20262
+ return rva < reader.size && sectionRva.every((entry) => rva < entry.rva) ? rva : void 0;
20263
+ };
20264
+ const readRva = (rva, length) => {
20265
+ const offset = rvaToOffset(rva);
20266
+ return offset === void 0 ? void 0 : reader.read(offset, length);
20267
+ };
20268
+ const stringAtRva = (rva, max = 256) => {
20269
+ const offset = rvaToOffset(rva);
20270
+ if (offset === void 0) return void 0;
20271
+ const chunk = reader.read(offset, Math.min(max, reader.size - offset));
20272
+ return chunk ? cString(chunk) : void 0;
20273
+ };
20274
+ const imports = { libraryCount: 0, libraries: [], truncated: false };
20275
+ const importDirectory = directory(1);
20276
+ if (importDirectory) {
20277
+ const thunkSize = plus ? 8 : 4;
20278
+ const collectThunks = (lookupRva, library) => {
20279
+ if (!lookupRva) return;
20280
+ for (let i = 0; i < MAX_THUNKS_PER_LIBRARY; i += 1) {
20281
+ const thunk = readRva(lookupRva + i * thunkSize, thunkSize);
20282
+ if (!thunk) break;
20283
+ const value = plus ? thunk.readBigUInt64LE(0) : BigInt(thunk.readUInt32LE(0));
20284
+ if (value === 0n) break;
20285
+ library.functionCount += 1;
20286
+ if (library.functions.length >= MAX_FUNCTIONS_PER_LIBRARY) continue;
20287
+ const ordinalFlag = plus ? 1n << 63n : 1n << 31n;
20288
+ if (value & ordinalFlag) {
20289
+ library.functions.push(`#${Number(value & 0xffffn)}`);
20290
+ } else {
20291
+ const name = stringAtRva(Number(value & 0x7fffffffn) + 2, 256);
20292
+ if (name) library.functions.push(name);
20293
+ }
20294
+ }
20295
+ };
20296
+ for (let index = 0; index < 4096; index += 1) {
20297
+ const descriptor = readRva(importDirectory.rva + index * 20, 20);
20298
+ if (!descriptor) {
20299
+ if (index === 0) warnings.push("The import table could not be read.");
20300
+ break;
20301
+ }
20302
+ const nameRva = descriptor.readUInt32LE(12);
20303
+ const lookupRva = descriptor.readUInt32LE(0) || descriptor.readUInt32LE(16);
20304
+ if (nameRva === 0 && lookupRva === 0) break;
20305
+ imports.libraryCount += 1;
20306
+ if (imports.libraries.length >= MAX_IMPORT_LIBRARIES) {
20307
+ imports.truncated = true;
20308
+ continue;
20309
+ }
20310
+ const library = {
20311
+ name: stringAtRva(nameRva, 260) ?? "?",
20312
+ functionCount: 0,
20313
+ functions: [],
20314
+ delayLoaded: false
20315
+ };
20316
+ collectThunks(lookupRva, library);
20317
+ imports.libraries.push(library);
20318
+ }
20319
+ }
20320
+ const delayDirectory = directory(13);
20321
+ if (delayDirectory) {
20322
+ for (let index = 0; index < 64; index += 1) {
20323
+ const descriptor = readRva(delayDirectory.rva + index * 32, 32);
20324
+ if (!descriptor) break;
20325
+ const attributes = descriptor.readUInt32LE(0);
20326
+ const nameField = descriptor.readUInt32LE(4);
20327
+ if (nameField === 0) break;
20328
+ const nameRva = attributes & 1 ? nameField : nameField - Number(imageBase & 0xffffffffn);
20329
+ const name = stringAtRva(nameRva, 260);
20330
+ if (!name) continue;
20331
+ imports.libraryCount += 1;
20332
+ if (imports.libraries.length < MAX_IMPORT_LIBRARIES) {
20333
+ imports.libraries.push({ name, functionCount: 0, functions: [], delayLoaded: true });
20334
+ } else {
20335
+ imports.truncated = true;
20336
+ }
20337
+ }
20338
+ }
20339
+ const exportsInfo = { count: 0, namedCount: 0 };
20340
+ const exportDirectory = directory(0);
20341
+ if (exportDirectory) {
20342
+ const table = readRva(exportDirectory.rva, 40);
20343
+ if (table) {
20344
+ exportsInfo.count = table.readUInt32LE(20);
20345
+ exportsInfo.namedCount = table.readUInt32LE(24);
20346
+ exportsInfo.dllName = stringAtRva(table.readUInt32LE(12), 260);
20347
+ }
20348
+ }
20349
+ let dotnet;
20350
+ const clrDirectory = directory(14);
20351
+ if (clrDirectory) {
20352
+ const header = readRva(clrDirectory.rva, 72);
20353
+ if (header) {
20354
+ const flags = header.readUInt32LE(16);
20355
+ dotnet = {
20356
+ runtimeVersion: `${header.readUInt16LE(4)}.${header.readUInt16LE(6)}`,
20357
+ ilOnly: (flags & 1) !== 0,
20358
+ requires32Bit: (flags & 2) !== 0,
20359
+ strongNameSigned: (flags & 8) !== 0,
20360
+ nativeEntryPoint: (flags & 16) !== 0
20361
+ };
20362
+ const metadataRva = header.readUInt32LE(8);
20363
+ const root = metadataRva ? readRva(metadataRva, 32) : void 0;
20364
+ if (root && root.readUInt32LE(0) === 1112167234) {
20365
+ const versionLength = root.readUInt32LE(12);
20366
+ if (versionLength > 0 && versionLength <= 255) {
20367
+ const version2 = readRva(metadataRva + 16, versionLength);
20368
+ if (version2) dotnet.metadataVersion = cString(version2);
20369
+ }
20370
+ }
20371
+ }
20372
+ }
20373
+ const version = readVersionInfo(directory(2), readRva, rvaToOffset, reader, warnings);
20374
+ let debug;
20375
+ const debugDirectory = directory(6);
20376
+ if (debugDirectory) {
20377
+ const entries = Math.min(Math.floor(debugDirectory.size / 28), 16);
20378
+ for (let index = 0; index < entries && !debug; index += 1) {
20379
+ const entry = readRva(debugDirectory.rva + index * 28, 28);
20380
+ if (!entry || entry.readUInt32LE(12) !== 2) continue;
20381
+ const dataSize = entry.readUInt32LE(16);
20382
+ const pointer = entry.readUInt32LE(24);
20383
+ const data = pointer && dataSize >= 24 && dataSize < 4096 ? reader.read(pointer, dataSize) : void 0;
20384
+ if (data && data.toString("latin1", 0, 4) === "RSDS") {
20385
+ debug = {
20386
+ guid: guidString(data.subarray(4, 20)),
20387
+ age: data.readUInt32LE(20),
20388
+ pdbPath: cString(data, 24)
20389
+ };
20390
+ }
20391
+ }
20392
+ }
20393
+ const certificate = { present: false, sizeBytes: 0 };
20394
+ const certificateEntry = directory(4);
20395
+ if (certificateEntry) {
20396
+ certificate.sizeBytes = certificateEntry.size;
20397
+ const header = reader.read(certificateEntry.rva, 8);
20398
+ if (header) {
20399
+ certificate.present = true;
20400
+ certificate.type = CERTIFICATE_TYPES[header.readUInt16LE(6)] ?? `type-${header.readUInt16LE(6)}`;
20401
+ } else {
20402
+ warnings.push("The certificate table points outside the file.");
20403
+ }
20404
+ }
20405
+ let endOfImage = 0;
20406
+ for (const section of sections) {
20407
+ endOfImage = Math.max(endOfImage, section.rawOffset + section.rawSize);
20408
+ }
20409
+ const certificateStart = certificate.present ? certificateEntry.rva : reader.size;
20410
+ const overlayEnd = Math.min(reader.size, certificateStart);
20411
+ const overlaySizeBytes = Math.max(0, overlayEnd - endOfImage);
20412
+ const mitigations = [];
20413
+ if (dllCharacteristics & 64) mitigations.push("ASLR");
20414
+ if (dllCharacteristics & 32) mitigations.push("high-entropy-ASLR");
20415
+ if (dllCharacteristics & 256) mitigations.push("DEP");
20416
+ if (dllCharacteristics & 16384) mitigations.push("CFG");
20417
+ if (dllCharacteristics & 1024) mitigations.push("no-SEH");
20418
+ if (dllCharacteristics & 4096) mitigations.push("app-container");
20419
+ const machineName = MACHINES[machine] ?? `machine-${hex(machine)}`;
20420
+ const reproducible = debugHasReproFlag(debugDirectory, readRva) || timeDateStamp === 0;
20421
+ const timestamp = timeDateStamp !== 0 && !reproducible ? new Date(timeDateStamp * 1e3).toISOString() : void 0;
20422
+ return {
20423
+ kind: "pe",
20424
+ sizeBytes: reader.size,
20425
+ format: plus ? "PE32+" : "PE32",
20426
+ architecture: machineName,
20427
+ isDll: (characteristics & 8192) !== 0,
20428
+ subsystem: SUBSYSTEMS[subsystemId] ?? `subsystem-${subsystemId}`,
20429
+ timestamp,
20430
+ timestampIsReproducible: reproducible,
20431
+ entryPointRva,
20432
+ imageBase: hex(imageBase),
20433
+ linkerVersion: linker,
20434
+ minimumOsVersion: minimumOs,
20435
+ mitigations,
20436
+ sections,
20437
+ imports,
20438
+ exports: exportsInfo,
20439
+ dotnet,
20440
+ version,
20441
+ debug,
20442
+ certificate,
20443
+ overlaySizeBytes,
20444
+ warnings
20445
+ };
20446
+ }
20447
+ function raws(tableOffset, reader, count) {
20448
+ const result = [];
20449
+ for (let index = 0; index < count; index += 1) {
20450
+ const raw = reader.read(tableOffset + index * 40, 40);
20451
+ if (!raw) break;
20452
+ result.push({
20453
+ virtualSize: raw.readUInt32LE(8),
20454
+ rva: raw.readUInt32LE(12),
20455
+ rawSize: raw.readUInt32LE(16),
20456
+ rawOffset: raw.readUInt32LE(20)
20457
+ });
20458
+ }
20459
+ return result;
20460
+ }
20461
+ function guidString(bytes) {
20462
+ const part = (start, end) => [...bytes.subarray(start, end)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
20463
+ const reverse = (start, end) => [...bytes.subarray(start, end)].reverse().map((byte) => byte.toString(16).padStart(2, "0")).join("");
20464
+ return `${reverse(0, 4)}-${reverse(4, 6)}-${reverse(6, 8)}-${part(8, 10)}-${part(10, 16)}`;
20465
+ }
20466
+ function debugHasReproFlag(directory, readRva) {
20467
+ if (!directory) return false;
20468
+ const entries = Math.min(Math.floor(directory.size / 28), 16);
20469
+ for (let index = 0; index < entries; index += 1) {
20470
+ const entry = readRva(directory.rva + index * 28, 28);
20471
+ if (entry && entry.readUInt32LE(12) === 16) return true;
20472
+ }
20473
+ return false;
20474
+ }
20475
+ function readVersionInfo(resources, readRva, rvaToOffset, reader, warnings) {
20476
+ if (!resources) return void 0;
20477
+ const base = resources.rva;
20478
+ const readDirectory = (offset2) => {
20479
+ const header = readRva(base + offset2, 16);
20480
+ if (!header) return void 0;
20481
+ const named = header.readUInt16LE(12);
20482
+ const ids = header.readUInt16LE(14);
20483
+ const count = Math.min(named + ids, 512);
20484
+ const table = count ? readRva(base + offset2 + 16, count * 8) : Buffer.alloc(0);
20485
+ if (!table) return void 0;
20486
+ const entries = [];
20487
+ for (let index = 0; index < count; index += 1) {
20488
+ const nameOrId = table.readUInt32LE(index * 8);
20489
+ const target = table.readUInt32LE(index * 8 + 4);
20490
+ entries.push({
20491
+ id: nameOrId & 2147483647,
20492
+ named: (nameOrId & 2147483648) !== 0,
20493
+ isDirectory: (target & 2147483648) !== 0,
20494
+ target: target & 2147483647
20495
+ });
20496
+ }
20497
+ return entries;
20498
+ };
20499
+ const root = readDirectory(0);
20500
+ const typeEntry = root?.find((entry) => !entry.named && entry.id === 16 && entry.isDirectory);
20501
+ if (!typeEntry) return void 0;
20502
+ let level = readDirectory(typeEntry.target);
20503
+ let depth = 1;
20504
+ let leaf;
20505
+ while (level && level.length > 0 && depth <= RESOURCE_MAX_DEPTH) {
20506
+ const entry = level[0];
20507
+ if (!entry.isDirectory) {
20508
+ leaf = entry;
20509
+ break;
20510
+ }
20511
+ level = readDirectory(entry.target);
20512
+ depth += 1;
20513
+ }
20514
+ if (!leaf) return void 0;
20515
+ const dataEntry = readRva(base + leaf.target, 16);
20516
+ if (!dataEntry) return void 0;
20517
+ const dataRva = dataEntry.readUInt32LE(0);
20518
+ const dataSize = dataEntry.readUInt32LE(4);
20519
+ if (dataSize < 8 || dataSize > 256 * 1024) {
20520
+ warnings.push("The version resource has an unexpected size and was skipped.");
20521
+ return void 0;
20522
+ }
20523
+ const offset = rvaToOffset(dataRva);
20524
+ const data = offset === void 0 ? void 0 : reader.read(offset, dataSize);
20525
+ if (!data) return void 0;
20526
+ return parseVersionResource(data);
20527
+ }
20528
+ function align4(value) {
20529
+ return value + 3 & ~3;
20530
+ }
20531
+ function readVersionBlock(buffer, offset, limit) {
20532
+ if (offset + 6 > limit) return void 0;
20533
+ const length = buffer.readUInt16LE(offset);
20534
+ const valueLength = buffer.readUInt16LE(offset + 2);
20535
+ const type = buffer.readUInt16LE(offset + 4);
20536
+ if (length < 6 || offset + length > limit) return void 0;
20537
+ let cursor = offset + 6;
20538
+ let key = "";
20539
+ while (cursor + 2 <= offset + length) {
20540
+ const unit = buffer.readUInt16LE(cursor);
20541
+ cursor += 2;
20542
+ if (unit === 0) break;
20543
+ key += String.fromCharCode(unit);
20544
+ if (key.length > 64) return void 0;
20545
+ }
20546
+ const valueOffset = align4(cursor);
20547
+ const valueBytes = type === 1 ? valueLength * 2 : valueLength;
20548
+ return {
20549
+ key,
20550
+ valueOffset,
20551
+ valueLength,
20552
+ type,
20553
+ childrenOffset: align4(valueOffset + valueBytes),
20554
+ end: offset + length
20555
+ };
20556
+ }
20557
+ var VERSION_FIELDS = {
20558
+ CompanyName: "companyName",
20559
+ FileDescription: "fileDescription",
20560
+ FileVersion: "fileVersion",
20561
+ InternalName: "internalName",
20562
+ LegalCopyright: "legalCopyright",
20563
+ OriginalFilename: "originalFilename",
20564
+ ProductName: "productName",
20565
+ ProductVersion: "productVersion"
20566
+ };
20567
+ function parseVersionResource(data) {
20568
+ const root = readVersionBlock(data, 0, data.length);
20569
+ if (!root || root.key !== "VS_VERSION_INFO") return void 0;
20570
+ const result = {};
20571
+ let cursor = root.childrenOffset;
20572
+ while (cursor < root.end) {
20573
+ const group = readVersionBlock(data, cursor, root.end);
20574
+ if (!group) break;
20575
+ if (group.key === "StringFileInfo") {
20576
+ let tableCursor = group.childrenOffset;
20577
+ const table = readVersionBlock(data, tableCursor, group.end);
20578
+ if (table) {
20579
+ tableCursor = table.childrenOffset;
20580
+ while (tableCursor < table.end) {
20581
+ const entry = readVersionBlock(data, tableCursor, table.end);
20582
+ if (!entry) break;
20583
+ const field = VERSION_FIELDS[entry.key];
20584
+ if (field && entry.type === 1 && entry.valueLength > 0) {
20585
+ const raw = data.toString(
20586
+ "utf16le",
20587
+ entry.valueOffset,
20588
+ Math.min(entry.valueOffset + entry.valueLength * 2, entry.end)
20589
+ );
20590
+ const value = raw.replace(/\0+$/, "").trim();
20591
+ if (value) result[field] = value.slice(0, 256);
20592
+ }
20593
+ tableCursor = align4(entry.end);
20594
+ }
20595
+ }
20596
+ }
20597
+ cursor = align4(group.end);
20598
+ }
20599
+ return Object.keys(result).length > 0 ? result : void 0;
20600
+ }
20601
+
20602
+ // src/inspectors/windowsApp.ts
20603
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
20604
+ var WALK_ENTRY_LIMIT = 2e4;
20605
+ var WALK_DEPTH_LIMIT = 4;
20606
+ var HELPER_EXECUTABLE = /^(unins\d*|uninstall.*|update|squirrel|setup.*|install.*|vc_?redist.*|vcredist.*|dxsetup|crashpad_handler|crashreporter.*|crashsender.*|notification_helper|elevate|createdump|.*helper.*|.*updater.*)\.exe$/i;
20607
+ function normalizeName(value) {
20608
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
20609
+ }
20610
+ function relative(root, target) {
20611
+ const value = import_node_path4.default.relative(root, target).split(import_node_path4.default.sep).join("/");
20612
+ return value === "" ? "." : value;
20613
+ }
20614
+ function walk(root) {
20615
+ const files = [];
20616
+ const directories = [];
20617
+ let seen = 0;
20618
+ let truncated = false;
20619
+ const visit = (dir, depth) => {
20620
+ let entries;
20621
+ try {
20622
+ entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
20623
+ } catch {
20624
+ return;
20625
+ }
20626
+ for (const entry of entries) {
20627
+ if (seen >= WALK_ENTRY_LIMIT) {
20628
+ truncated = true;
20629
+ return;
20630
+ }
20631
+ seen += 1;
20632
+ if (entry.isSymbolicLink()) continue;
20633
+ const full = import_node_path4.default.join(dir, entry.name);
20634
+ const rel = relative(root, full);
20635
+ if (entry.isDirectory()) {
20636
+ directories.push(rel.toLowerCase());
20637
+ if (depth < WALK_DEPTH_LIMIT) visit(full, depth + 1);
20638
+ } else if (entry.isFile()) {
20639
+ let size = 0;
20640
+ try {
20641
+ size = import_node_fs6.default.statSync(full).size;
20642
+ } catch {
20643
+ }
20644
+ files.push({ relative: rel, lower: rel.toLowerCase(), size });
20645
+ }
20646
+ }
20647
+ };
20648
+ visit(root, 0);
20649
+ return { files, directories, truncated };
20650
+ }
20651
+ function topLevelExecutables(dir) {
20652
+ try {
20653
+ return import_node_fs6.default.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.exe$/i.test(entry.name)).map((entry) => entry.name);
20654
+ } catch {
20655
+ return [];
20656
+ }
20657
+ }
20658
+ function newestSquirrelVersion(dir) {
20659
+ try {
20660
+ const versions = import_node_fs6.default.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && /^app-\d/i.test(entry.name)).map((entry) => entry.name);
20661
+ versions.sort(
20662
+ (a, b) => a.localeCompare(b, void 0, { numeric: true, sensitivity: "base" })
20663
+ );
20664
+ return versions.length ? versions[versions.length - 1] : void 0;
20665
+ } catch {
20666
+ return void 0;
20667
+ }
20668
+ }
20669
+ function findWindowsElectronRoot(appPath) {
20670
+ let base = appPath;
20671
+ try {
20672
+ if (import_node_fs6.default.statSync(appPath).isFile()) base = import_node_path4.default.dirname(appPath);
20673
+ } catch {
20674
+ return void 0;
20675
+ }
20676
+ const roots = [base];
20677
+ const squirrel = newestSquirrelVersion(base);
20678
+ if (squirrel) roots.push(import_node_path4.default.join(base, squirrel));
20679
+ for (const root of roots) {
20680
+ const asar = import_node_path4.default.join(root, "resources", "app.asar");
20681
+ if (import_node_fs6.default.existsSync(asar)) return asar;
20682
+ const unpacked = import_node_path4.default.join(root, "resources", "app");
20683
+ if (import_node_fs6.default.existsSync(import_node_path4.default.join(unpacked, "package.json"))) return unpacked;
20684
+ }
20685
+ return void 0;
20686
+ }
20687
+ function rankExecutables(root, names, appName) {
20688
+ const wanted = normalizeName(appName);
20689
+ const scored = names.map((name) => {
20690
+ let size = 0;
20691
+ try {
20692
+ size = import_node_fs6.default.statSync(import_node_path4.default.join(root, name)).size;
20693
+ } catch {
20694
+ }
20695
+ let score = Math.log10(size + 1);
20696
+ if (HELPER_EXECUTABLE.test(name)) score -= 100;
20697
+ if (wanted && normalizeName(name.replace(/\.exe$/i, "")) === wanted) score += 50;
20698
+ return { name, score };
20699
+ });
20700
+ scored.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name));
20701
+ return scored.map((item) => item.name);
20702
+ }
20703
+ var FILE_MARKERS = [
20704
+ { hint: "CEF (Chromium Embedded Framework)", test: (f) => /(^|\/)libcef\.dll$/.test(f), basis: "libcef.dll" },
20705
+ { hint: "WebView2", test: (f) => /(^|\/)webview2loader\.dll$/.test(f), basis: "WebView2Loader.dll" },
20706
+ { hint: "Qt", test: (f) => /(^|\/)qt\d?core(d)?\.dll$/.test(f), basis: "QtCore library" },
20707
+ { hint: "Flutter", test: (f) => /(^|\/)flutter_windows\.dll$/.test(f), basis: "flutter_windows.dll" },
20708
+ { hint: "Unity", test: (f) => /(^|\/)unityplayer\.dll$/.test(f), basis: "UnityPlayer.dll" },
20709
+ { hint: "NW.js", test: (f) => /(^|\/)nw(_elf)?\.dll$/.test(f), basis: "nw.dll" },
20710
+ { hint: "Java", test: (f) => /(^|\/)jvm\.dll$/.test(f), basis: "bundled jvm.dll" },
20711
+ { hint: "Python", test: (f) => /(^|\/)python3\d*\.dll$/.test(f), basis: "python3 runtime DLL" },
20712
+ { hint: "PyInstaller", test: (f) => /(^|\/)base_library\.zip$/.test(f), basis: "base_library.zip" },
20713
+ { hint: ".NET (modern runtime)", test: (f) => /(^|\/)(hostfxr|coreclr)\.dll$/.test(f) || /\.runtimeconfig\.json$/.test(f), basis: "hostfxr/coreclr or runtimeconfig.json" },
20714
+ { hint: "WPF", test: (f) => /(^|\/)presentationframework\.dll$/.test(f), basis: "PresentationFramework.dll" },
20715
+ { hint: "Windows Forms", test: (f) => /(^|\/)system\.windows\.forms\.dll$/.test(f), basis: "System.Windows.Forms.dll" },
20716
+ { hint: "WinUI", test: (f) => /(^|\/)microsoft\.ui\.xaml\.dll$/.test(f), basis: "Microsoft.UI.Xaml.dll" },
20717
+ { hint: "Squirrel installer", test: (f) => f === "update.exe", basis: "Update.exe" },
20718
+ { hint: "Inno Setup uninstaller", test: (f) => /(^|\/)unins\d+\.exe$/.test(f), basis: "unins000.exe" },
20719
+ { hint: "NSIS uninstaller", test: (f) => /(^|\/)uninstall[^/]*\.exe$/.test(f), basis: "Uninstall*.exe" }
20720
+ ];
20721
+ var BINARY_MARKERS = [
20722
+ { hint: "Go", needle: Buffer.from("Go buildinf:", "latin1"), basis: "Go build info in the executable" },
20723
+ { hint: "Rust", needle: Buffer.from("/rustc/", "latin1"), basis: "rustc source paths in the executable" },
20724
+ { hint: "Tauri", needle: Buffer.from("tauri-runtime", "latin1"), basis: "tauri-runtime crate paths in the executable" },
20725
+ { hint: "Wails", needle: Buffer.from("wailsapp/wails", "latin1"), basis: "wails module path in the executable" },
20726
+ { hint: "PyInstaller", needle: Buffer.from("PyInstaller", "latin1"), basis: "PyInstaller bootloader strings" },
20727
+ { hint: "Electron", needle: Buffer.from("dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX", "latin1"), basis: "Electron fuse sentinel in the executable" }
20728
+ ];
20729
+ var BINARY_SCAN_LIMIT = 192 * 1024 * 1024;
20730
+ var BINARY_SCAN_CHUNK = 8 * 1024 * 1024;
20731
+ function scanBinaryMarkers(filePath) {
20732
+ const found = [];
20733
+ let fd;
20734
+ try {
20735
+ fd = import_node_fs6.default.openSync(filePath, "r");
20736
+ const size = import_node_fs6.default.fstatSync(fd).size;
20737
+ const overlap = Math.max(...BINARY_MARKERS.map((marker) => marker.needle.length));
20738
+ const buffer = Buffer.alloc(BINARY_SCAN_CHUNK + overlap);
20739
+ let position = 0;
20740
+ let carried = 0;
20741
+ while (position < Math.min(size, BINARY_SCAN_LIMIT)) {
20742
+ const read = import_node_fs6.default.readSync(fd, buffer, carried, BINARY_SCAN_CHUNK, position);
20743
+ if (read <= 0) break;
20744
+ const view = buffer.subarray(0, carried + read);
20745
+ for (const marker of BINARY_MARKERS) {
20746
+ if (!found.some((item) => item.hint === marker.hint) && view.includes(marker.needle)) {
20747
+ found.push({ hint: marker.hint, basis: marker.basis });
20748
+ }
20749
+ }
20750
+ position += read;
20751
+ carried = Math.min(overlap - 1, view.length);
20752
+ view.copy(buffer, 0, view.length - carried);
20753
+ }
20754
+ } catch {
20755
+ } finally {
20756
+ if (fd !== void 0) import_node_fs6.default.closeSync(fd);
20757
+ }
20758
+ return found;
20759
+ }
20760
+ function detectTechnology(files, directories, electron, pe, mainPath) {
20761
+ const evidence = [];
20762
+ const add = (hint, basis) => {
20763
+ if (!evidence.some((item) => item.hint === hint)) evidence.push({ hint, basis });
20764
+ };
20765
+ if (electron.asar) add("Electron", "resources/app.asar");
20766
+ else if (electron.unpackedApp) add("Electron", "resources/app");
20767
+ const lower = files.map((file) => file.lower);
20768
+ if (!electron.asar && !electron.unpackedApp && lower.includes("chrome_100_percent.pak") && lower.includes("resources.pak")) {
20769
+ add("Chromium-based", "chrome_100_percent.pak and resources.pak");
20770
+ }
20771
+ for (const marker of FILE_MARKERS) {
20772
+ if (lower.some(marker.test)) add(marker.hint, marker.basis);
20773
+ }
20774
+ if (directories.some((dir) => /(^|\/)[^/]+_data$/.test(dir)) && lower.some((f) => /(^|\/)unityplayer\.dll$/.test(f))) {
20775
+ add("Unity", "*_Data directory");
20776
+ }
20777
+ if (pe?.dotnet) {
20778
+ add(".NET", pe.dotnet.metadataVersion ? `CLR header (${pe.dotnet.metadataVersion})` : "CLR header");
20779
+ }
20780
+ if (pe?.imports.libraries.some((library) => /^mscoree\.dll$/i.test(library.name))) {
20781
+ add(".NET Framework", "imports mscoree.dll");
20782
+ }
20783
+ const libraries = pe?.imports.libraries.map((library) => library.name.toLowerCase()) ?? [];
20784
+ if (libraries.some((name) => /^mfc\d+/.test(name))) add("MFC", "imports mfc*.dll");
20785
+ if (libraries.some((name) => /^qt\d?(core|gui|widgets)/.test(name))) add("Qt", "imports Qt libraries");
20786
+ if (libraries.some((name) => /^webview2loader\.dll$/.test(name))) add("WebView2", "imports WebView2Loader.dll");
20787
+ if (mainPath) {
20788
+ for (const found of scanBinaryMarkers(mainPath)) add(found.hint, found.basis);
20789
+ }
20790
+ return { hints: evidence.map((item) => item.hint), evidence };
20791
+ }
20792
+ function powershellPath() {
20793
+ const root = process.env.SystemRoot || "C:\\Windows";
20794
+ return import_node_path4.default.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
20795
+ }
20796
+ async function verifyAuthenticode(filePath, warnings) {
20797
+ if (process.platform !== "win32") {
20798
+ warnings.push("Authenticode verification requires a Windows host; only the embedded signature block was read.");
20799
+ return void 0;
20800
+ }
20801
+ const script = "$s = Get-AuthenticodeSignature -LiteralPath $env:APPTRACE_SIGNATURE_PATH; [pscustomobject]@{ Status = [string]$s.Status; Message = $s.StatusMessage; Subject = $s.SignerCertificate.Subject; Issuer = $s.SignerCertificate.Issuer; Thumbprint = $s.SignerCertificate.Thumbprint; NotAfter = if ($s.SignerCertificate) { $s.SignerCertificate.NotAfter.ToString('o') } else { $null }; Timestamper = $s.TimeStamperCertificate.Subject } | ConvertTo-Json -Compress";
20802
+ try {
20803
+ const { stdout } = await execFileAsync2(
20804
+ powershellPath(),
20805
+ ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script],
20806
+ {
20807
+ timeout: 45e3,
20808
+ maxBuffer: 1024 * 1024,
20809
+ windowsHide: true,
20810
+ env: { ...process.env, APPTRACE_SIGNATURE_PATH: filePath }
20811
+ }
20812
+ );
20813
+ const parsed = JSON.parse(stdout.trim());
20814
+ const text2 = (value) => typeof value === "string" && value ? value : void 0;
20815
+ const status = text2(parsed.Status);
20816
+ return {
20817
+ verified: status === "Valid",
20818
+ status,
20819
+ signer: text2(parsed.Subject),
20820
+ issuer: text2(parsed.Issuer),
20821
+ thumbprint: text2(parsed.Thumbprint),
20822
+ notAfter: text2(parsed.NotAfter),
20823
+ timestamper: text2(parsed.Timestamper)
20824
+ };
20825
+ } catch (error) {
20826
+ warnings.push(
20827
+ `Authenticode verification did not complete: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}`
20828
+ );
20829
+ return void 0;
20830
+ }
20831
+ }
20832
+ function packerWarnings(pe, warnings) {
20833
+ const packerNames = /^(upx\d|\.upx|\.aspack|\.adata|\.themida|\.vmp\d|\.petite|\.mpress|\.enigma\d|\.nsp\d|\.packed)/i;
20834
+ for (const section of pe.sections) {
20835
+ if (packerNames.test(section.name)) {
20836
+ warnings.push(`Section "${section.name}" is typical of a packer; static results may cover only the unpacker stub.`);
20837
+ return;
20838
+ }
20839
+ }
20840
+ const dense = pe.sections.filter((section) => section.executable && (section.entropy ?? 0) >= 7.4 && section.rawSize > 32 * 1024);
20841
+ if (dense.length > 0) {
20842
+ warnings.push(
20843
+ `Executable section "${dense[0].name}" has entropy ${dense[0].entropy}; the code may be packed or encrypted.`
20844
+ );
20845
+ }
20846
+ }
20847
+ async function inspectWindowsApp(appPath) {
20848
+ const warnings = [];
20849
+ const stat = import_node_fs6.default.statSync(appPath);
20850
+ let appRoot = stat.isDirectory() ? appPath : import_node_path4.default.dirname(appPath);
20851
+ const requestedExecutable = stat.isFile() ? import_node_path4.default.basename(appPath) : void 0;
20852
+ const appName = import_node_path4.default.basename(appRoot);
20853
+ let executables = requestedExecutable ? [requestedExecutable] : topLevelExecutables(appRoot);
20854
+ let ranked = rankExecutables(appRoot, executables, appName);
20855
+ const onlyHelpers = ranked.length > 0 && ranked.every((name) => HELPER_EXECUTABLE.test(name));
20856
+ if (!requestedExecutable && (ranked.length === 0 || onlyHelpers)) {
20857
+ const version2 = newestSquirrelVersion(appRoot);
20858
+ if (version2) {
20859
+ const nested = import_node_path4.default.join(appRoot, version2);
20860
+ const nestedRanked = rankExecutables(nested, topLevelExecutables(nested), appName);
20861
+ if (nestedRanked.length > 0) {
20862
+ warnings.push(`The program lives in "${version2}"; the newest versioned folder was inspected.`);
20863
+ appRoot = nested;
20864
+ executables = topLevelExecutables(nested);
20865
+ ranked = nestedRanked;
20866
+ }
20867
+ }
20868
+ }
20869
+ if (ranked.length === 0) {
20870
+ throw new Error("No Windows executable (.exe) was found at the top level of the application directory.");
20871
+ }
20872
+ const mainName = ranked[0];
20873
+ const mainPath = import_node_path4.default.join(appRoot, mainName);
20874
+ if (!isPeFile(mainPath)) {
20875
+ throw new Error(`"${mainName}" is not a Windows executable (the MZ signature is missing).`);
20876
+ }
20877
+ if (HELPER_EXECUTABLE.test(mainName)) {
20878
+ warnings.push(`Only helper-style executables were found; "${mainName}" was inspected but may not be the application itself.`);
20879
+ }
20880
+ if (ranked.length > 1) {
20881
+ const second = ranked[1];
20882
+ if (!HELPER_EXECUTABLE.test(second) && !requestedExecutable) {
20883
+ warnings.push(`Several executables could be the main program (${ranked.slice(0, 4).join(", ")}); "${mainName}" was chosen.`);
20884
+ }
20885
+ }
20886
+ const pe = inspectPeFile(mainPath);
20887
+ warnings.push(...pe.warnings);
20888
+ packerWarnings(pe, warnings);
20889
+ const walked = walk(appRoot);
20890
+ const asar = import_node_path4.default.join(appRoot, "resources", "app.asar");
20891
+ const unpacked = import_node_path4.default.join(appRoot, "resources", "app");
20892
+ let asarSize;
20893
+ try {
20894
+ asarSize = import_node_fs6.default.statSync(asar).size;
20895
+ } catch {
20896
+ }
20897
+ const electron = {
20898
+ asar: asarSize !== void 0,
20899
+ unpackedApp: import_node_fs6.default.existsSync(import_node_path4.default.join(unpacked, "package.json")),
20900
+ ...asarSize !== void 0 ? { asarSizeBytes: asarSize } : {}
20901
+ };
20902
+ let topLevel = [];
20903
+ try {
20904
+ topLevel = import_node_fs6.default.readdirSync(appRoot).sort((a, b) => a.localeCompare(b)).slice(0, 200);
20905
+ } catch {
20906
+ }
20907
+ const signature = { embedded: pe.certificate.present };
20908
+ const verified = await verifyAuthenticode(mainPath, warnings);
20909
+ if (verified) Object.assign(signature, verified);
20910
+ if (!pe.certificate.present && (!verified || verified.status === "NotSigned")) {
20911
+ warnings.push("The main executable carries no Authenticode signature.");
20912
+ }
20913
+ const version = pe.version?.productVersion ?? pe.version?.fileVersion;
20914
+ return {
20915
+ kind: "windows-app",
20916
+ app: {
20917
+ path: appPath,
20918
+ name: pe.version?.productName ?? pe.version?.fileDescription ?? appName,
20919
+ version,
20920
+ publisher: pe.version?.companyName
20921
+ },
20922
+ layout: {
20923
+ root: relative(stat.isDirectory() ? appPath : import_node_path4.default.dirname(appPath), appRoot),
20924
+ topLevel,
20925
+ executableCount: walked.files.filter((file) => file.lower.endsWith(".exe")).length,
20926
+ dllCount: walked.files.filter((file) => file.lower.endsWith(".dll")).length,
20927
+ fileCount: walked.files.length,
20928
+ truncated: walked.truncated,
20929
+ electron
20930
+ },
20931
+ mainExecutable: {
20932
+ path: relative(stat.isDirectory() ? appPath : import_node_path4.default.dirname(appPath), mainPath),
20933
+ sizeBytes: pe.sizeBytes,
20934
+ candidates: ranked.slice(0, 8),
20935
+ pe
20936
+ },
20937
+ technology: detectTechnology(walked.files, walked.directories, electron, pe, mainPath),
20938
+ signature,
20939
+ warnings
20940
+ };
20941
+ }
20942
+
20077
20943
  // src/inspectors/report.ts
20078
20944
  function cell(value) {
20079
20945
  return String(value ?? "\u2014").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
@@ -20128,6 +20994,42 @@ function renderMacAppInspection(lines, inspection, warnings) {
20128
20994
  lines.push("");
20129
20995
  }
20130
20996
  }
20997
+ function renderWindowsAppInspection(lines, inspection, warnings) {
20998
+ const app = record(inspection.app) ?? {};
20999
+ const layout = record(inspection.layout) ?? {};
21000
+ const electron = record(layout.electron);
21001
+ const main = record(inspection.mainExecutable);
21002
+ const pe = record(main?.pe);
21003
+ const imports = record(pe?.imports);
21004
+ const dotnet = record(pe?.dotnet);
21005
+ const signature = record(inspection.signature);
21006
+ const technology = record(inspection.technology);
21007
+ const hints = Array.isArray(technology?.hints) ? technology.hints.map(String) : [];
21008
+ lines.push(
21009
+ "| Field | Value |",
21010
+ "| --- | --- |",
21011
+ `| Name | ${cell(app.name)} |`,
21012
+ `| Version | ${cell(app.version)} |`,
21013
+ `| Publisher | ${cell(app.publisher)} |`,
21014
+ `| Main executable | ${cell(main?.path)} |`,
21015
+ `| Architecture | ${cell(pe?.architecture)} (${cell(pe?.format)}) |`,
21016
+ `| Subsystem | ${cell(pe?.subsystem)} |`,
21017
+ `| Imported libraries | ${cell(imports?.libraryCount)} |`,
21018
+ `| .NET runtime | ${cell(dotnet ? dotnet.runtimeVersion ?? "managed" : void 0)} |`,
21019
+ `| Executables / DLLs | ${cell(layout.executableCount)} / ${cell(layout.dllCount)} |`,
21020
+ `| Electron bundle | ${cell(electron?.asar ? "app.asar" : electron?.unpackedApp ? "unpacked app" : "none")} |`,
21021
+ `| Technology hints | ${cell(hints.length > 0 ? hints.join(", ") : void 0)} |`,
21022
+ `| Signature embedded | ${cell(signature?.embedded)} |`,
21023
+ `| Signature verified | ${cell(signature?.verified ?? "not checked on this host")} |`,
21024
+ `| Signer | ${cell(signature?.signer)} |`,
21025
+ ""
21026
+ );
21027
+ if (warnings.length > 0) {
21028
+ lines.push("### Inspection warnings", "");
21029
+ for (const warning of warnings) lines.push(`- ${warning}`);
21030
+ lines.push("");
21031
+ }
21032
+ }
20131
21033
  function renderIpaInspection(lines, inspection, warnings) {
20132
21034
  lines.push(
20133
21035
  "| Field | Value |",
@@ -20219,6 +21121,8 @@ function renderReportMarkdown(input2) {
20219
21121
  lines.push(`Inspection failed: ${cell(inspection.error)}`, "");
20220
21122
  } else if (inspection.kind === "mac-app") {
20221
21123
  renderMacAppInspection(lines, inspection, warnings);
21124
+ } else if (inspection.kind === "windows-app") {
21125
+ renderWindowsAppInspection(lines, inspection, warnings);
20222
21126
  } else {
20223
21127
  renderIpaInspection(lines, inspection, warnings);
20224
21128
  }
@@ -20311,8 +21215,8 @@ function describeResult(result) {
20311
21215
  }
20312
21216
 
20313
21217
  // src/process/run.ts
20314
- var import_node_child_process2 = require("child_process");
20315
- var import_node_path4 = __toESM(require("path"));
21218
+ var import_node_child_process3 = require("child_process");
21219
+ var import_node_path5 = __toESM(require("path"));
20316
21220
  function quoteWindowsArgument(value) {
20317
21221
  if (value.length === 0) return '""';
20318
21222
  if (!/[\s"&|<>^()%!]/.test(value)) return value;
@@ -20322,7 +21226,7 @@ function windowsCommandLine(command, args) {
20322
21226
  return [command, ...args].map(quoteWindowsArgument).join(" ");
20323
21227
  }
20324
21228
  function windowsSpawnSpec(command, args) {
20325
- const extension = import_node_path4.default.extname(command).toLowerCase();
21229
+ const extension = import_node_path5.default.extname(command).toLowerCase();
20326
21230
  if (extension !== ".cmd" && extension !== ".bat") {
20327
21231
  return { command, args, verbatim: false };
20328
21232
  }
@@ -20340,7 +21244,7 @@ function runCommand(command, args, options = {}) {
20340
21244
  let child;
20341
21245
  try {
20342
21246
  const spec = process.platform === "win32" ? windowsSpawnSpec(command, args) : { command, args, verbatim: false };
20343
- child = (0, import_node_child_process2.spawn)(spec.command, spec.args, {
21247
+ child = (0, import_node_child_process3.spawn)(spec.command, spec.args, {
20344
21248
  env: options.env ?? process.env,
20345
21249
  cwd: options.cwd,
20346
21250
  stdio: ["ignore", "pipe", "pipe"],
@@ -20464,7 +21368,7 @@ function uniqueStrings(values2, limit) {
20464
21368
  function isNetworkEndpointValue(value) {
20465
21369
  return /^(?:https?|wss?):\/\//i.test(value) || /^\/\//.test(value) || /^[a-z0-9.-]+\.[a-z]{2,}(?:[/:?#]|$)/i.test(value) || /^\/[a-z0-9._~!$&'()*+,;=:@%/-]+$/i.test(value);
20466
21370
  }
20467
- function detectTechnology(subjectName, modulePaths, assetPaths) {
21371
+ function detectTechnology2(subjectName, modulePaths, assetPaths) {
20468
21372
  const text2 = [subjectName, ...modulePaths, ...assetPaths].filter((value) => typeof value === "string").join("\n").toLowerCase();
20469
21373
  const hints = [];
20470
21374
  if (/__uni__|uni-app|uni-jsframework|hbuilder/.test(text2)) {
@@ -20516,7 +21420,7 @@ function javascriptFindings(job, artifact, evidenceId, parsed, summary) {
20516
21420
  }
20517
21421
  }
20518
21422
  }
20519
- if (artifact.packageFormat === "app") {
21423
+ if (artifact.packageFormat === "app" || artifact.packageFormat === "exe") {
20520
21424
  push("technology", "Electron", {
20521
21425
  group: "technology",
20522
21426
  confidence: "high",
@@ -20613,10 +21517,10 @@ function javascriptFindings(job, artifact, evidenceId, parsed, summary) {
20613
21517
  return findings;
20614
21518
  }
20615
21519
  function findElectronJavascriptRoot(appPath) {
20616
- const asar = import_node_path5.default.join(appPath, "Contents", "Resources", "app.asar");
20617
- if (import_node_fs5.default.existsSync(asar)) return asar;
20618
- const unpacked = import_node_path5.default.join(appPath, "Contents", "Resources", "app");
20619
- if (import_node_fs5.default.existsSync(unpacked) && import_node_fs5.default.statSync(unpacked).isDirectory()) {
21520
+ const asar = import_node_path6.default.join(appPath, "Contents", "Resources", "app.asar");
21521
+ if (import_node_fs7.default.existsSync(asar)) return asar;
21522
+ const unpacked = import_node_path6.default.join(appPath, "Contents", "Resources", "app");
21523
+ if (import_node_fs7.default.existsSync(unpacked) && import_node_fs7.default.statSync(unpacked).isDirectory()) {
20620
21524
  return unpacked;
20621
21525
  }
20622
21526
  fail(
@@ -20712,7 +21616,7 @@ function summarizeRea(parsed) {
20712
21616
  operation: parsed.operation,
20713
21617
  technology: {
20714
21618
  confidence: "static-hint",
20715
- hints: detectTechnology(subject?.name, modulePaths, assetPaths)
21619
+ hints: detectTechnology2(subject?.name, modulePaths, assetPaths)
20716
21620
  },
20717
21621
  subject: subject ? {
20718
21622
  name: subject.name,
@@ -20885,6 +21789,9 @@ var CapabilityJobRunner = class {
20885
21789
  case "inspect:mac-app":
20886
21790
  await this.runInspectMacApp(job, target, artifact);
20887
21791
  return;
21792
+ case "inspect:pe":
21793
+ await this.runInspectPe(job, target, artifact);
21794
+ return;
20888
21795
  case "extract:app":
20889
21796
  await this.runExtract(job, target, artifact);
20890
21797
  return;
@@ -20975,10 +21882,36 @@ var CapabilityJobRunner = class {
20975
21882
  warnings: inspection.warnings.length
20976
21883
  });
20977
21884
  }
21885
+ async runInspectPe(job, target, artifact) {
21886
+ if (!artifact) fail("ARTIFACT_REQUIRED", "Acquire an artifact first.");
21887
+ this.log(job, "info", "Inspecting the Windows application.");
21888
+ this.patch(job, { progress: 25 });
21889
+ const inspection = await inspectWindowsApp(
21890
+ this.workspace.resolveStoredPath(artifact.path)
21891
+ );
21892
+ const pe = inspection.mainExecutable?.pe;
21893
+ const updated = {
21894
+ ...artifact,
21895
+ version: inspection.app.version ?? artifact.version,
21896
+ architecture: pe?.architecture ?? artifact.architecture,
21897
+ inspection
21898
+ };
21899
+ this.store.insertArtifact(updated);
21900
+ this.workspace.saveArtifactMetadata(target, updated);
21901
+ this.patch(job, {
21902
+ status: "analyzed",
21903
+ progress: 100,
21904
+ result: { inspection },
21905
+ finishedAt: now()
21906
+ });
21907
+ this.log(job, "info", "Windows application inspection complete.", {
21908
+ warnings: inspection.warnings.length
21909
+ });
21910
+ }
20978
21911
  async runExtract(job, target, artifact) {
20979
21912
  if (!artifact) fail("ARTIFACT_REQUIRED", "\u8BF7\u5148\u83B7\u53D6 artifact\u3002");
20980
21913
  this.log(job, "info", "\u5F00\u59CB\u89E3\u5305 .app\u3002");
20981
- const outputDir = import_node_path5.default.join(
21914
+ const outputDir = import_node_path6.default.join(
20982
21915
  this.workspace.analysisDir(target),
20983
21916
  "extract-app",
20984
21917
  job.id
@@ -20992,7 +21925,7 @@ var CapabilityJobRunner = class {
20992
21925
  progress: 100,
20993
21926
  result: {
20994
21927
  ...extracted,
20995
- outputDir: import_node_path5.default.relative(this.workspace.root, extracted.outputDir)
21928
+ outputDir: import_node_path6.default.relative(this.workspace.root, extracted.outputDir)
20996
21929
  },
20997
21930
  finishedAt: now()
20998
21931
  });
@@ -21003,19 +21936,34 @@ var CapabilityJobRunner = class {
21003
21936
  async runReaJavascript(job, target, artifact) {
21004
21937
  if (!artifact) fail("ARTIFACT_REQUIRED", "\u8BF7\u5148\u83B7\u53D6 artifact\u3002");
21005
21938
  let javascriptRoot;
21006
- if (artifact.packageFormat === "app") {
21939
+ if (artifact.packageFormat === "exe") {
21940
+ const found = findWindowsElectronRoot(
21941
+ this.workspace.resolveStoredPath(artifact.path)
21942
+ );
21943
+ if (!found) {
21944
+ fail(
21945
+ "CAPABILITY_UNAVAILABLE",
21946
+ "No Electron JavaScript bundle (resources/app.asar or resources/app) was found in this application."
21947
+ );
21948
+ }
21949
+ javascriptRoot = found;
21950
+ this.log(job, "info", "Running static analysis on the Windows JavaScript bundle.", {
21951
+ path: import_node_path6.default.relative(this.workspace.root, javascriptRoot)
21952
+ });
21953
+ this.patch(job, { progress: 25 });
21954
+ } else if (artifact.packageFormat === "app") {
21007
21955
  javascriptRoot = findElectronJavascriptRoot(
21008
21956
  this.workspace.resolveStoredPath(artifact.path)
21009
21957
  );
21010
21958
  this.log(job, "info", "Running static analysis on the macOS JavaScript bundle.", {
21011
- path: import_node_path5.default.relative(this.workspace.root, javascriptRoot)
21959
+ path: import_node_path6.default.relative(this.workspace.root, javascriptRoot)
21012
21960
  });
21013
21961
  this.patch(job, { progress: 25 });
21014
21962
  } else {
21015
21963
  const extraction = await this.ensureExtraction(job, target, artifact);
21016
21964
  javascriptRoot = extraction.appRoot;
21017
21965
  this.log(job, "info", "\u5BF9\u89E3\u5305\u76EE\u5F55\u8FD0\u884C JavaScript \u9759\u6001\u5206\u6790\u3002", {
21018
- path: import_node_path5.default.relative(this.workspace.root, javascriptRoot)
21966
+ path: import_node_path6.default.relative(this.workspace.root, javascriptRoot)
21019
21967
  });
21020
21968
  this.patch(job, { progress: 25 });
21021
21969
  }
@@ -21027,7 +21975,11 @@ var CapabilityJobRunner = class {
21027
21975
  "analyze-javascript-application",
21028
21976
  javascriptRoot,
21029
21977
  "--analysis-timeout-ms",
21030
- "300000"
21978
+ "300000",
21979
+ // Signed Electron apps often carry unpacked native binaries whose
21980
+ // bytes no longer match the integrity recorded in app.asar. Keep
21981
+ // going and let REA mark those files untrusted rather than abort.
21982
+ ...artifact.packageFormat === "ipa" ? [] : ["--integrity-policy", "record-and-continue"]
21031
21983
  ],
21032
21984
  // Electron bundles are much larger than iOS web bundles; a 136 MB asar
21033
21985
  // takes several minutes on its own.
@@ -21035,7 +21987,7 @@ var CapabilityJobRunner = class {
21035
21987
  );
21036
21988
  const evidenceId = this.reaEvidenceId(rea);
21037
21989
  const summary = { ...rea.summary };
21038
- if (artifact.packageFormat === "app") {
21990
+ if (artifact.packageFormat === "app" || artifact.packageFormat === "exe") {
21039
21991
  const technology = record2(summary.technology) ?? {};
21040
21992
  const hints = Array.isArray(technology.hints) ? [...technology.hints] : [];
21041
21993
  if (!hints.includes("Electron")) hints.unshift("Electron");
@@ -21064,7 +22016,7 @@ var CapabilityJobRunner = class {
21064
22016
  result: {
21065
22017
  ...summary,
21066
22018
  evidenceId,
21067
- outputDir: import_node_path5.default.relative(this.workspace.root, javascriptRoot),
22019
+ outputDir: import_node_path6.default.relative(this.workspace.root, javascriptRoot),
21068
22020
  evidencePath: rea.rawPath
21069
22021
  },
21070
22022
  finishedAt: now()
@@ -21108,7 +22060,7 @@ var CapabilityJobRunner = class {
21108
22060
  result: {
21109
22061
  ...rea.summary,
21110
22062
  evidenceId,
21111
- binaryPath: import_node_path5.default.relative(this.workspace.root, prepared.binaryPath),
22063
+ binaryPath: import_node_path6.default.relative(this.workspace.root, prepared.binaryPath),
21112
22064
  evidencePath: rea.rawPath,
21113
22065
  encryption,
21114
22066
  warning: encryption.encryptedSlices > 0 ? "\u4E3B\u7A0B\u5E8F\u5305\u542B\u58F0\u660E\u52A0\u5BC6\u7684\u5207\u7247\uFF1B\u4E0D\u8981\u628A\u52A0\u5BC6\u533A\u53CD\u7F16\u8BD1\u7ED3\u679C\u5F53\u4F5C\u53EF\u4FE1\u539F\u59CB\u5B9E\u73B0\u3002" : void 0
@@ -21171,7 +22123,7 @@ var CapabilityJobRunner = class {
21171
22123
  mode,
21172
22124
  matchCount: rawMatches.length,
21173
22125
  matches,
21174
- binaryPath: import_node_path5.default.relative(this.workspace.root, prepared.binaryPath),
22126
+ binaryPath: import_node_path6.default.relative(this.workspace.root, prepared.binaryPath),
21175
22127
  evidencePath: rea.rawPath,
21176
22128
  limitations: Array.isArray(rea.parsed.limitations) ? rea.parsed.limitations : [],
21177
22129
  encryption: encryptionState(prepared.inspection)
@@ -21216,7 +22168,7 @@ var CapabilityJobRunner = class {
21216
22168
  result: {
21217
22169
  ...rea.summary,
21218
22170
  functionName: input2.functionName,
21219
- binaryPath: import_node_path5.default.relative(this.workspace.root, prepared.binaryPath),
22171
+ binaryPath: import_node_path6.default.relative(this.workspace.root, prepared.binaryPath),
21220
22172
  evidencePath: rea.rawPath,
21221
22173
  encryption
21222
22174
  },
@@ -21231,7 +22183,7 @@ var CapabilityJobRunner = class {
21231
22183
  this.log(job, "info", "\u6C47\u603B Target\u3001artifact \u548C\u4EFB\u52A1\u8BC1\u636E\u3002");
21232
22184
  this.patch(job, { progress: 35 });
21233
22185
  const generatedAt = now();
21234
- const reportPath = import_node_path5.default.join(
22186
+ const reportPath = import_node_path6.default.join(
21235
22187
  this.workspace.targetDir(target),
21236
22188
  "reports",
21237
22189
  `${job.id}.md`
@@ -21268,7 +22220,7 @@ var CapabilityJobRunner = class {
21268
22220
  generatedAt
21269
22221
  });
21270
22222
  this.workspace.writeText(reportPath, markdown);
21271
- const relativePath = import_node_path5.default.relative(this.workspace.root, reportPath);
22223
+ const relativePath = import_node_path6.default.relative(this.workspace.root, reportPath);
21272
22224
  this.patch(job, {
21273
22225
  status: "analyzed",
21274
22226
  progress: 100,
@@ -21300,12 +22252,12 @@ var CapabilityJobRunner = class {
21300
22252
  fail("MAIN_EXECUTABLE_NOT_FOUND", "IPA \u68C0\u67E5\u7ED3\u679C\u4E2D\u6CA1\u6709\u4E3B\u7A0B\u5E8F\u8DEF\u5F84\u3002");
21301
22253
  }
21302
22254
  const extraction = await this.ensureExtraction(job, target, current);
21303
- const binaryPath = import_node_path5.default.resolve(extraction.outputDir, executable);
21304
- const root = import_node_path5.default.resolve(extraction.outputDir);
21305
- if (binaryPath !== root && !binaryPath.startsWith(root + import_node_path5.default.sep)) {
22255
+ const binaryPath = import_node_path6.default.resolve(extraction.outputDir, executable);
22256
+ const root = import_node_path6.default.resolve(extraction.outputDir);
22257
+ if (binaryPath !== root && !binaryPath.startsWith(root + import_node_path6.default.sep)) {
21306
22258
  fail("UNSAFE_ARTIFACT_PATH", "\u4E3B\u7A0B\u5E8F\u8DEF\u5F84\u8D8A\u51FA\u89E3\u5305\u76EE\u5F55\uFF0C\u5DF2\u62D2\u7EDD\u6267\u884C\u3002");
21307
22259
  }
21308
- if (!import_node_fs5.default.existsSync(binaryPath)) {
22260
+ if (!import_node_fs7.default.existsSync(binaryPath)) {
21309
22261
  fail("MAIN_EXECUTABLE_NOT_FOUND", `\u89E3\u5305\u76EE\u5F55\u4E2D\u6CA1\u6709\u4E3B\u7A0B\u5E8F\uFF1A${executable}`);
21310
22262
  }
21311
22263
  return { inspection, binaryPath };
@@ -21314,24 +22266,24 @@ var CapabilityJobRunner = class {
21314
22266
  const previous = this.findExtraction(target.id, artifact.id);
21315
22267
  if (previous) {
21316
22268
  this.log(job, "info", "\u590D\u7528\u5DF2\u6709\u89E3\u5305\u76EE\u5F55\u3002", {
21317
- path: import_node_path5.default.relative(this.workspace.root, previous.outputDir)
22269
+ path: import_node_path6.default.relative(this.workspace.root, previous.outputDir)
21318
22270
  });
21319
22271
  return previous;
21320
22272
  }
21321
- const outputDir = import_node_path5.default.join(
22273
+ const outputDir = import_node_path6.default.join(
21322
22274
  this.workspace.analysisDir(target),
21323
22275
  "extracted",
21324
22276
  artifact.id
21325
22277
  );
21326
- const existingApp = import_node_fs5.default.existsSync(outputDir) ? findAppPrefix(outputDir) : void 0;
22278
+ const existingApp = import_node_fs7.default.existsSync(outputDir) ? findAppPrefix(outputDir) : void 0;
21327
22279
  if (existingApp) {
21328
22280
  const location = {
21329
22281
  outputDir,
21330
22282
  prefix: existingApp,
21331
- appRoot: import_node_path5.default.join(outputDir, existingApp)
22283
+ appRoot: import_node_path6.default.join(outputDir, existingApp)
21332
22284
  };
21333
22285
  this.log(job, "info", "\u590D\u7528\u6309 artifact \u54C8\u5E0C\u5F52\u6863\u7684\u89E3\u5305\u76EE\u5F55\u3002", {
21334
- path: import_node_path5.default.relative(this.workspace.root, outputDir)
22286
+ path: import_node_path6.default.relative(this.workspace.root, outputDir)
21335
22287
  });
21336
22288
  return location;
21337
22289
  }
@@ -21341,8 +22293,8 @@ var CapabilityJobRunner = class {
21341
22293
  this.workspace.resolveStoredPath(artifact.path),
21342
22294
  outputDir
21343
22295
  );
21344
- const appRoot = import_node_path5.default.resolve(outputDir, extracted.prefix);
21345
- if (appRoot !== outputDir && !appRoot.startsWith(outputDir + import_node_path5.default.sep)) {
22296
+ const appRoot = import_node_path6.default.resolve(outputDir, extracted.prefix);
22297
+ if (appRoot !== outputDir && !appRoot.startsWith(outputDir + import_node_path6.default.sep)) {
21346
22298
  fail("UNSAFE_ARTIFACT_PATH", "\u89E3\u5305\u524D\u7F00\u8D8A\u51FA\u8F93\u51FA\u76EE\u5F55\uFF0C\u5DF2\u62D2\u7EDD\u7EE7\u7EED\u3002");
21347
22299
  }
21348
22300
  return { outputDir, appRoot, prefix: extracted.prefix };
@@ -21357,8 +22309,8 @@ var CapabilityJobRunner = class {
21357
22309
  if (typeof output !== "string" || typeof prefix !== "string") continue;
21358
22310
  try {
21359
22311
  const outputDir = this.workspace.resolveStoredPath(output);
21360
- const appRoot = import_node_path5.default.resolve(outputDir, prefix);
21361
- if (import_node_fs5.default.existsSync(appRoot) && (appRoot === outputDir || appRoot.startsWith(outputDir + import_node_path5.default.sep))) {
22312
+ const appRoot = import_node_path6.default.resolve(outputDir, prefix);
22313
+ if (import_node_fs7.default.existsSync(appRoot) && (appRoot === outputDir || appRoot.startsWith(outputDir + import_node_path6.default.sep))) {
21362
22314
  return { outputDir, appRoot, prefix };
21363
22315
  }
21364
22316
  } catch {
@@ -21367,11 +22319,11 @@ var CapabilityJobRunner = class {
21367
22319
  return void 0;
21368
22320
  }
21369
22321
  async runReaJson(job, target, folder, args, timeoutMs) {
21370
- const dir = import_node_path5.default.join(this.workspace.analysisDir(target), folder, job.id);
21371
- const rawPath = import_node_path5.default.join(dir, "result.json");
21372
- const stderrPath = import_node_path5.default.join(dir, "stderr.log");
21373
- const commandPath = import_node_path5.default.join(dir, "command.json");
21374
- import_node_fs5.default.mkdirSync(dir, { recursive: true, mode: 448 });
22322
+ const dir = import_node_path6.default.join(this.workspace.analysisDir(target), folder, job.id);
22323
+ const rawPath = import_node_path6.default.join(dir, "result.json");
22324
+ const stderrPath = import_node_path6.default.join(dir, "stderr.log");
22325
+ const commandPath = import_node_path6.default.join(dir, "command.json");
22326
+ import_node_fs7.default.mkdirSync(dir, { recursive: true, mode: 448 });
21375
22327
  this.workspace.writeJson(commandPath, {
21376
22328
  command: this.config.reaPath,
21377
22329
  args,
@@ -21390,7 +22342,7 @@ var CapabilityJobRunner = class {
21390
22342
  });
21391
22343
  this.workspace.writeText(rawPath, result.stdout);
21392
22344
  this.workspace.writeText(stderrPath, result.stderr);
21393
- this.workspace.writeJson(import_node_path5.default.join(dir, "status.json"), {
22345
+ this.workspace.writeJson(import_node_path6.default.join(dir, "status.json"), {
21394
22346
  code: result.code,
21395
22347
  timedOut: result.timedOut,
21396
22348
  finishedAt: now()
@@ -21404,7 +22356,7 @@ var CapabilityJobRunner = class {
21404
22356
  if (result.code !== 0) {
21405
22357
  const parsed2 = parseJsonDocument(result.stdout);
21406
22358
  this.log(job, "warn", "\u5206\u6790\u5F15\u64CE\u672A\u6210\u529F\u5B8C\u6210\uFF0C\u539F\u59CB\u8F93\u51FA\u5DF2\u4FDD\u7559\u3002", {
21407
- evidencePath: import_node_path5.default.relative(this.workspace.root, rawPath)
22359
+ evidencePath: import_node_path6.default.relative(this.workspace.root, rawPath)
21408
22360
  });
21409
22361
  const message = reaErrorMessage(parsed2) ?? shortFailure(result.stderr, result.stdout);
21410
22362
  fail("ENGINE_FAILED", message);
@@ -21418,7 +22370,7 @@ var CapabilityJobRunner = class {
21418
22370
  }
21419
22371
  return {
21420
22372
  parsed,
21421
- rawPath: import_node_path5.default.relative(this.workspace.root, rawPath),
22373
+ rawPath: import_node_path6.default.relative(this.workspace.root, rawPath),
21422
22374
  sha256: hashText(result.stdout),
21423
22375
  summary: summarizeRea(parsed)
21424
22376
  };
@@ -21466,10 +22418,10 @@ var CapabilityJobRunner = class {
21466
22418
  }
21467
22419
  };
21468
22420
  function findAppPrefix(outputDir) {
21469
- const payload = import_node_path5.default.join(outputDir, "Payload");
21470
- if (!import_node_fs5.default.existsSync(payload)) return void 0;
22421
+ const payload = import_node_path6.default.join(outputDir, "Payload");
22422
+ if (!import_node_fs7.default.existsSync(payload)) return void 0;
21471
22423
  try {
21472
- const app = import_node_fs5.default.readdirSync(payload, { withFileTypes: true }).find((entry) => entry.isDirectory() && entry.name.endsWith(".app"));
22424
+ const app = import_node_fs7.default.readdirSync(payload, { withFileTypes: true }).find((entry) => entry.isDirectory() && entry.name.endsWith(".app"));
21473
22425
  return app ? `Payload/${app.name}/` : void 0;
21474
22426
  } catch {
21475
22427
  return void 0;
@@ -21477,11 +22429,12 @@ function findAppPrefix(outputDir) {
21477
22429
  }
21478
22430
 
21479
22431
  // src/license.ts
21480
- var import_node_fs6 = __toESM(require("fs"));
22432
+ var import_node_fs8 = __toESM(require("fs"));
21481
22433
  var import_node_crypto2 = __toESM(require("crypto"));
21482
22434
  var FREE_FEATURES = /* @__PURE__ */ new Set([
21483
22435
  "inspect:ipa",
21484
22436
  "inspect:mac-app",
22437
+ "inspect:pe",
21485
22438
  "extract:app",
21486
22439
  "javascript:analyze",
21487
22440
  "generate:report"
@@ -21497,7 +22450,7 @@ function verifyLicense(token) {
21497
22450
  if (!encodedPayload || !encodedSignature) {
21498
22451
  throw new Error("Invalid license token.");
21499
22452
  }
21500
- const publicKeyValue = process.env.APPTRACE_LICENSE_PUBLIC_KEY || (process.env.APPTRACE_LICENSE_PUBLIC_KEY_FILE ? import_node_fs6.default.readFileSync(process.env.APPTRACE_LICENSE_PUBLIC_KEY_FILE, "utf8") : void 0);
22453
+ const publicKeyValue = process.env.APPTRACE_LICENSE_PUBLIC_KEY || (process.env.APPTRACE_LICENSE_PUBLIC_KEY_FILE ? import_node_fs8.default.readFileSync(process.env.APPTRACE_LICENSE_PUBLIC_KEY_FILE, "utf8") : void 0);
21501
22454
  if (!publicKeyValue) {
21502
22455
  throw new Error("APPTRACE_LICENSE_PUBLIC_KEY is not configured.");
21503
22456
  }
@@ -21554,8 +22507,8 @@ function compareVersionData(input2) {
21554
22507
  }
21555
22508
 
21556
22509
  // src/store.ts
21557
- var import_node_fs7 = __toESM(require("fs"));
21558
- var import_node_path6 = __toESM(require("path"));
22510
+ var import_node_fs9 = __toESM(require("fs"));
22511
+ var import_node_path7 = __toESM(require("path"));
21559
22512
  var import_node_module = require("module");
21560
22513
  var import_meta = {};
21561
22514
  function openSqlite(databasePath) {
@@ -21808,7 +22761,7 @@ var SqliteStore = class {
21808
22761
  kind = "sqlite";
21809
22762
  db;
21810
22763
  constructor(databasePath) {
21811
- import_node_fs7.default.mkdirSync(import_node_path6.default.dirname(databasePath), { recursive: true, mode: 448 });
22764
+ import_node_fs9.default.mkdirSync(import_node_path7.default.dirname(databasePath), { recursive: true, mode: 448 });
21812
22765
  const db = openSqlite(databasePath);
21813
22766
  if (!db) throw new Error("node:sqlite is not available");
21814
22767
  this.db = db;
@@ -22141,11 +23094,11 @@ var JsonStore = class {
22141
23094
  data;
22142
23095
  constructor(databasePath) {
22143
23096
  this.filePath = databasePath.replace(/\.sqlite$/i, "") + ".json";
22144
- import_node_fs7.default.mkdirSync(import_node_path6.default.dirname(this.filePath), { recursive: true, mode: 448 });
23097
+ import_node_fs9.default.mkdirSync(import_node_path7.default.dirname(this.filePath), { recursive: true, mode: 448 });
22145
23098
  this.data = this.load();
22146
23099
  }
22147
23100
  load() {
22148
- if (!import_node_fs7.default.existsSync(this.filePath)) {
23101
+ if (!import_node_fs9.default.existsSync(this.filePath)) {
22149
23102
  return {
22150
23103
  targets: [],
22151
23104
  artifacts: [],
@@ -22157,7 +23110,7 @@ var JsonStore = class {
22157
23110
  };
22158
23111
  }
22159
23112
  try {
22160
- const parsed = JSON.parse(import_node_fs7.default.readFileSync(this.filePath, "utf8"));
23113
+ const parsed = JSON.parse(import_node_fs9.default.readFileSync(this.filePath, "utf8"));
22161
23114
  return {
22162
23115
  targets: parsed.targets ?? [],
22163
23116
  artifacts: parsed.artifacts ?? [],
@@ -22181,8 +23134,8 @@ var JsonStore = class {
22181
23134
  }
22182
23135
  save() {
22183
23136
  const temp = `${this.filePath}.${process.pid}.tmp`;
22184
- import_node_fs7.default.writeFileSync(temp, JSON.stringify(this.data, null, 2), { mode: 384 });
22185
- import_node_fs7.default.renameSync(temp, this.filePath);
23137
+ import_node_fs9.default.writeFileSync(temp, JSON.stringify(this.data, null, 2), { mode: 384 });
23138
+ import_node_fs9.default.renameSync(temp, this.filePath);
22186
23139
  }
22187
23140
  listTargets() {
22188
23141
  return [...this.data.targets].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
@@ -22323,44 +23276,44 @@ function createStore(databasePath) {
22323
23276
  }
22324
23277
 
22325
23278
  // src/workspace.ts
22326
- var import_node_fs8 = __toESM(require("fs"));
22327
- var import_node_path7 = __toESM(require("path"));
23279
+ var import_node_fs10 = __toESM(require("fs"));
23280
+ var import_node_path8 = __toESM(require("path"));
22328
23281
  var WorkspaceService = class {
22329
23282
  root;
22330
23283
  constructor(root) {
22331
- this.root = import_node_path7.default.resolve(root);
22332
- import_node_fs8.default.mkdirSync(this.root, { recursive: true, mode: 448 });
22333
- import_node_fs8.default.mkdirSync(import_node_path7.default.join(this.root, "targets"), { recursive: true, mode: 448 });
22334
- import_node_fs8.default.mkdirSync(import_node_path7.default.join(this.root, "tmp"), { recursive: true, mode: 448 });
23284
+ this.root = import_node_path8.default.resolve(root);
23285
+ import_node_fs10.default.mkdirSync(this.root, { recursive: true, mode: 448 });
23286
+ import_node_fs10.default.mkdirSync(import_node_path8.default.join(this.root, "targets"), { recursive: true, mode: 448 });
23287
+ import_node_fs10.default.mkdirSync(import_node_path8.default.join(this.root, "tmp"), { recursive: true, mode: 448 });
22335
23288
  }
22336
23289
  targetDir(target) {
22337
- return import_node_path7.default.join(
23290
+ return import_node_path8.default.join(
22338
23291
  this.root,
22339
23292
  "targets",
22340
23293
  `${target.targetRef.platform}-${target.targetRef.sourceId}-${target.slug}-${target.id.slice(0, 8)}`
22341
23294
  );
22342
23295
  }
22343
23296
  artifactDir(target) {
22344
- return import_node_path7.default.join(this.targetDir(target), "artifacts");
23297
+ return import_node_path8.default.join(this.targetDir(target), "artifacts");
22345
23298
  }
22346
23299
  analysisDir(target) {
22347
- return import_node_path7.default.join(this.targetDir(target), "analysis");
23300
+ return import_node_path8.default.join(this.targetDir(target), "analysis");
22348
23301
  }
22349
23302
  ensureTarget(target) {
22350
23303
  const dir = this.targetDir(target);
22351
23304
  for (const subdir of ["", "artifacts", "analysis", "reports"]) {
22352
- import_node_fs8.default.mkdirSync(import_node_path7.default.join(dir, subdir), { recursive: true, mode: 448 });
23305
+ import_node_fs10.default.mkdirSync(import_node_path8.default.join(dir, subdir), { recursive: true, mode: 448 });
22353
23306
  }
22354
23307
  }
22355
23308
  saveResolvedTarget(target, rawSource) {
22356
23309
  this.ensureTarget(target);
22357
23310
  const dir = this.targetDir(target);
22358
- this.writeJson(import_node_path7.default.join(dir, "meta.json"), target);
22359
- this.writeJson(import_node_path7.default.join(dir, "source.json"), rawSource);
23311
+ this.writeJson(import_node_path8.default.join(dir, "meta.json"), target);
23312
+ this.writeJson(import_node_path8.default.join(dir, "source.json"), rawSource);
22360
23313
  }
22361
23314
  saveArtifactMetadata(target, artifact, extra = {}) {
22362
23315
  const dir = this.targetDir(target);
22363
- this.writeJson(import_node_path7.default.join(dir, "artifact.json"), {
23316
+ this.writeJson(import_node_path8.default.join(dir, "artifact.json"), {
22364
23317
  schemaVersion: 1,
22365
23318
  target: {
22366
23319
  id: target.id,
@@ -22384,7 +23337,7 @@ var WorkspaceService = class {
22384
23337
  },
22385
23338
  ...extra
22386
23339
  });
22387
- this.writeJson(import_node_path7.default.join(dir, "current.json"), {
23340
+ this.writeJson(import_node_path8.default.join(dir, "current.json"), {
22388
23341
  artifactId: artifact.id,
22389
23342
  path: artifact.path,
22390
23343
  sha256: artifact.sha256,
@@ -22392,11 +23345,11 @@ var WorkspaceService = class {
22392
23345
  });
22393
23346
  }
22394
23347
  artifactRelativePath(target, filePath) {
22395
- return import_node_path7.default.relative(this.root, filePath);
23348
+ return import_node_path8.default.relative(this.root, filePath);
22396
23349
  }
22397
23350
  resolveStoredPath(relativePath) {
22398
- const resolved = import_node_path7.default.resolve(this.root, relativePath);
22399
- if (resolved !== this.root && !resolved.startsWith(this.root + import_node_path7.default.sep)) {
23351
+ const resolved = import_node_path8.default.resolve(this.root, relativePath);
23352
+ if (resolved !== this.root && !resolved.startsWith(this.root + import_node_path8.default.sep)) {
22400
23353
  throw new Error(`Path escapes workspace: ${relativePath}`);
22401
23354
  }
22402
23355
  return resolved;
@@ -22406,10 +23359,10 @@ var WorkspaceService = class {
22406
23359
  `);
22407
23360
  }
22408
23361
  writeText(filePath, value) {
22409
- import_node_fs8.default.mkdirSync(import_node_path7.default.dirname(filePath), { recursive: true, mode: 448 });
23362
+ import_node_fs10.default.mkdirSync(import_node_path8.default.dirname(filePath), { recursive: true, mode: 448 });
22410
23363
  const temp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
22411
- import_node_fs8.default.writeFileSync(temp, value, { mode: 384 });
22412
- import_node_fs8.default.renameSync(temp, filePath);
23364
+ import_node_fs10.default.writeFileSync(temp, value, { mode: 384 });
23365
+ import_node_fs10.default.renameSync(temp, filePath);
22413
23366
  }
22414
23367
  };
22415
23368
 
@@ -22448,6 +23401,8 @@ async function handle(line) {
22448
23401
  ok: true,
22449
23402
  result: { protocolVersion: PROTOCOL_VERSION, capabilities: [
22450
23403
  "inspect:ipa",
23404
+ "inspect:mac-app",
23405
+ "inspect:pe",
22451
23406
  "extract:app",
22452
23407
  "javascript:analyze",
22453
23408
  "native:inspect",
@@ -22475,12 +23430,12 @@ async function handle(line) {
22475
23430
  });
22476
23431
  return;
22477
23432
  }
22478
- const workspaceRoot = import_node_path8.default.resolve(request.workspacePath);
22479
- if (!import_node_fs9.default.existsSync(workspaceRoot)) {
23433
+ const workspaceRoot = import_node_path9.default.resolve(request.workspacePath);
23434
+ if (!import_node_fs11.default.existsSync(workspaceRoot)) {
22480
23435
  send({ id: request.id, ok: false, error: { code: "WORKSPACE_NOT_FOUND", message: workspaceRoot } });
22481
23436
  return;
22482
23437
  }
22483
- const store = createStore(import_node_path8.default.join(workspaceRoot, "workbench.sqlite"));
23438
+ const store = createStore(import_node_path9.default.join(workspaceRoot, "workbench.sqlite"));
22484
23439
  try {
22485
23440
  if (request.capability === "compare:versions") {
22486
23441
  send({