replace av and chassistype with wmi instead of powershell

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Nov 16, 2025 at 16:18 UTC 9545bec218b31555e2814d4d2775cdac7a64ca1f
3 files changed +477 -54
agents/modules_meshcore/computer-identifiers.js
+5 -10
@@ -702,17 +702,12 @@ function hexToAscii(hexString) {
702
703 function win_chassisType()
704 {
705 - // needs to be replaced with win-wmi but due to bug in win-wmi it doesnt handle arrays correctly
706 - var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
707 - if (child == null) { return ([]); }
708 - child.descriptorMetadata = 'process-manager';
709 - child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
710 - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
711 - child.stdin.write('Get-WmiObject Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes\r\n');
712 - child.stdin.write('exit\r\n');
713 - child.waitExit();
705 + // use new win-wmi-fixed module to get arrays correctly for time being
706 try {
715 - return (parseInt(child.stdout.str));
707 + var tokens = require('win-wmi-fixed').query('ROOT\\CIMV2', 'SELECT ChassisTypes FROM Win32_SystemEnclosure', ['ChassisTypes']);
708 + if (tokens[0]) {
709 + return (parseInt(tokens[0]['ChassisTypes'][0]));
710 + }
711 } catch (e) {
712 return (2); // unknown
713 }
agents/modules_meshcore/win-info.js
+39 -44
@@ -36,53 +36,48 @@ function qfe()
36 }
37 function av()
38 {
39 - var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
40 - if (child == null) { return ([]); }
41 -
42 - child.descriptorMetadata = 'process-manager';
43 - child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
44 - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
45 -
46 - child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n');
47 - child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | ');
48 - child.stdin.write('ForEach-Object -Process { ');
49 - child.stdin.write('$matches = [regex]::Matches($_.pathToSignedProductExe, "%(.*?)%"); ');
50 - child.stdin.write('$modifiedPath = $_.pathToSignedProductExe; ');
51 - child.stdin.write('foreach ($match in $matches) { ');
52 - child.stdin.write('$modifiedPath = $modifiedPath -replace [regex]::Escape($match.Value), [System.Environment]::GetEnvironmentVariable($match.Groups[1].Value, "Process") ');
53 - child.stdin.write('} ');
54 - child.stdin.write('$flag = $true; ');
55 - child.stdin.write('if ($modifiedPath -ne "windowsdefender://"){ ');
56 - child.stdin.write('if (-not (Test-Path -Path $modifiedPath -PathType Leaf)) { ');
57 - child.stdin.write('$flag = $false; ');
58 - child.stdin.write('} ');
59 - child.stdin.write('} ');
60 - child.stdin.write('if ($flag -eq $true) { ')
61 - child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); ');
62 - child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); ');
63 - child.stdin.write('Write-Output ("{0},{1}" -f $_.productState,$EncodedText); ');
64 - child.stdin.write('} ');
65 - child.stdin.write('}\r\n ');
66 - child.stdin.write('exit\r\n');
67 - child.waitExit();
68 -
69 - if (child.stdout.str == '') { return ([]); }
70 -
71 - var lines = child.stdout.str.trim().split('\r\n');
39 var result = [];
73 - for (i = 0; i < lines.length; ++i)
74 - {
75 - var keys = lines[i].split(',');
76 - if(keys.length == 2)
77 - {
78 - var status = {};
79 - status.product = Buffer.from(keys[1], 'base64').toString();
80 - status.updated = (parseInt(keys[0]) & 0x10) == 0;
81 - status.enabled = (parseInt(keys[0]) & 0x1000) == 0x1000;
82 - result.push(status);
40 + try {
41 + var tokens = require('win-wmi').query('ROOT\\SecurityCenter2', 'SELECT * FROM AntiVirusProduct');
42 + if (tokens.length == 0) { return ([]); }
43 + // Process each antivirus product
44 + for (var i = 0; i < tokens.length; ++i) {
45 + var product = tokens[i];
46 + var modifiedPath = product.pathToSignedProductExe || '';
47 + // Expand environment variables (e.g., %ProgramFiles%)
48 + var regex = /%([^%]+)%/g;
49 + var match;
50 + while ((match = regex.exec(product.pathToSignedProductExe)) !== null) {
51 + var envVar = match[1];
52 + var envValue = process.env[envVar] || '';
53 + if (envValue) {
54 + modifiedPath = modifiedPath.replace(match[0], envValue);
55 + }
56 + }
57 + // Check if the executable exists (unless it's Windows Defender pseudo-path)
58 + var flag = true;
59 + if (modifiedPath !== 'windowsdefender://') {
60 + try {
61 + if (!require('fs').existsSync(modifiedPath)) {
62 + flag = false;
63 + }
64 + } catch (ex) {
65 + flag = false;
66 + }
67 + }
68 + // Only include products with valid executables
69 + if (flag) {
70 + var status = {};
71 + status.product = product.displayName || '';
72 + status.updated = (parseInt(product.productState) & 0x10) == 0;
73 + status.enabled = (parseInt(product.productState) & 0x1000) == 0x1000;
74 + result.push(status);
75 + }
76 }
77 + return (result);
78 + } catch (ex) {
79 + return ([]);
80 }
85 - return (result);
81 }
82 function defrag(options)
83 {
agents/modules_meshcore/win-wmi-fixed.js new
+433
@@ -0,0 +1,433 @@
1 +/*
2 +Copyright 2021 Intel Corporation
3 +
4 +Licensed under the Apache License, Version 2.0 (the "License");
5 +you may not use this file except in compliance with the License.
6 +You may obtain a copy of the License at
7 +
8 + http://www.apache.org/licenses/LICENSE-2.0
9 +
10 +Unless required by applicable law or agreed to in writing, software
11 +distributed under the License is distributed on an "AS IS" BASIS,
12 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 +See the License for the specific language governing permissions and
14 +limitations under the License.
15 +*/
16 +
17 +var promise = require('promise');
18 +var GM = require('_GenericMarshal');
19 +const CLSID_WbemAdministrativeLocator = '{CB8555CC-9128-11D1-AD9B-00C04FD8FDFF}';
20 +const IID_WbemLocator = '{dc12a687-737f-11cf-884d-00aa004b2e24}';
21 +const WBEM_FLAG_BIDIRECTIONAL = 0;
22 +const WBEM_INFINITE = -1;
23 +const WBEM_FLAG_ALWAYS = 0;
24 +const E_NOINTERFACE = 0x80004002;
25 +var OleAut32 = GM.CreateNativeProxy('OleAut32.dll');
26 +OleAut32.CreateMethod('SafeArrayAccessData');
27 +
28 +var wmi_handlers = {};
29 +
30 +const LocatorFunctions = ['QueryInterface', 'AddRef', 'Release', 'ConnectToServer'];
31 +
32 +//
33 +// Reference for IWbemServices can be found at:
34 +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemservices
35 +//
36 +const ServiceFunctions = [
37 + 'QueryInterface',
38 + 'AddRef',
39 + 'Release',
40 + 'OpenNamespace',
41 + 'CancelAsyncCall',
42 + 'QueryObjectSink',
43 + 'GetObject',
44 + 'GetObjectAsync',
45 + 'PutClass',
46 + 'PutClassAsync',
47 + 'DeleteClass',
48 + 'DeleteClassAsync',
49 + 'CreateClassEnum',
50 + 'CreateClassEnumAsync',
51 + 'PutInstance',
52 + 'PutInstanceAsync',
53 + 'DeleteInstance',
54 + 'DeleteInstanceAsync',
55 + 'CreateInstanceEnum',
56 + 'CreateInstanceEnumAsync',
57 + 'ExecQuery',
58 + 'ExecQueryAsync',
59 + 'ExecNotificationQuery',
60 + 'ExecNotificationQueryAsync',
61 + 'ExecMethod',
62 + 'ExecMethodAsync'
63 +];
64 +
65 +//
66 +// Reference to IEnumWbemClassObject can be found at:
67 +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-ienumwbemclassobject
68 +//
69 +const ResultsFunctions = [
70 + 'QueryInterface',
71 + 'AddRef',
72 + 'Release',
73 + 'Reset',
74 + 'Next',
75 + 'NextAsync',
76 + 'Clone',
77 + 'Skip'
78 +];
79 +
80 +//
81 +// Reference to IWbemClassObject can be found at:
82 +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject
83 +//
84 +const ResultFunctions = [
85 + 'QueryInterface',
86 + 'AddRef',
87 + 'Release',
88 + 'GetQualifierSet',
89 + 'Get',
90 + 'Put',
91 + 'Delete',
92 + 'GetNames',
93 + 'BeginEnumeration',
94 + 'Next',
95 + 'EndEnumeration',
96 + 'GetPropertyQualifierSet',
97 + 'Clone',
98 + 'GetObjectText',
99 + 'SpawnDerivedClass',
100 + 'SpawnInstance',
101 + 'CompareTo',
102 + 'GetPropertyOrigin',
103 + 'InheritsFrom',
104 + 'GetMethod',
105 + 'PutMethod',
106 + 'DeleteMethod',
107 + 'BeginMethodEnumeration',
108 + 'NextMethod',
109 + 'EndMethodEnumeration',
110 + 'GetMethodQualifierSet',
111 + 'GetMethodOrigin'
112 +];
113 +
114 +//
115 +// Reference to IWbemObjectSink can be found at:
116 +// https://learn.microsoft.com/en-us/windows/win32/wmisdk/iwbemobjectsink
117 +//
118 +const QueryAsyncHandler =
119 + [
120 + {
121 + cx: 10, parms: 3, name: 'QueryInterface', func: function (j, riid, ppv)
122 + {
123 + var ret = GM.CreateVariable(4);
124 + console.info1('QueryInterface', riid.Deref(0, 16).toBuffer().toString('hex'));
125 + switch (riid.Deref(0, 16).toBuffer().toString('hex'))
126 + {
127 + case '0000000000000000C000000000000046': // IID_IUnknown
128 + j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
129 + ret.increment(0, true);
130 + //++this.p.refcount;
131 + console.info1('QueryInterface (IID_IUnknown)', this.refcount);
132 + break;
133 + case '0178857C8173CF11884D00AA004B2E24': // IID_IWmiObjectSink
134 + j.pointerBuffer().copy(ppv.Deref(0, GM.PointerSize).toBuffer());
135 + ret.increment(0, true);
136 + //++this.p.refcount;
137 + console.info1('QueryInterface (IID_IWmiObjectSink)', this.refcount);
138 + break;
139 + default:
140 + ret.increment(E_NOINTERFACE, true);
141 + console.info1(riid.Deref(0, 16).toBuffer().toString('hex'), 'returning E_NOINTERFACE');
142 + break;
143 + }
144 +
145 + return (ret);
146 + }
147 + },
148 + {
149 + cx: 11, parms: 1, name: 'AddRef', func: function ()
150 + {
151 + ++this.refcount;
152 + console.info1('AddRef', this.refcount);
153 + return (GM.CreateVariable(4));
154 + }
155 + },
156 + {
157 + cx: 12, parms: 1, name: 'Release', func: function ()
158 + {
159 + --this.refcount;
160 + console.info1('Release', this.refcount);
161 + if (this.refcount == 0)
162 + {
163 + console.info1('No More References');
164 +
165 + this.cleanup();
166 + this.services.funcs.Release(this.services.Deref());
167 +
168 + this.services = null;
169 + this.p = null;
170 + if (this.callbackDispatched)
171 + {
172 + setImmediate(function (j) { j.locator = null; }, this);
173 + }
174 + else
175 + {
176 + this.locator = null;
177 + }
178 +
179 + console.info1('No More References [END]');
180 + }
181 + return (GM.CreateVariable(4));
182 + }
183 + },
184 + {
185 + cx: 13, parms: 3, name: 'Indicate', func: function (j, count, arr)
186 + {
187 + console.info1('Indicate', count.Val);
188 + var j, nme, len, nn;
189 +
190 + for (var i = 0; i < count.Val; ++i)
191 + {
192 + j = arr.Deref((i * GM.PointerSize) + 0, GM.PointerSize);
193 + this.results.push(enumerateProperties(j, this.fields));
194 + }
195 +
196 + var ret = GM.CreateVariable(4);
197 + ret.increment(0, true);
198 + return (ret);
199 + }
200 + },
201 + {
202 + cx: 14, parms: 5, name: 'SetStatus', func: function (j, lFlags, hResult, strParam, pObjParam)
203 + {
204 + console.info1('SetStatus', hResult.Val);
205 +
206 + var ret = GM.CreateVariable(4);
207 + ret.increment(0, true);
208 +
209 + if (hResult.Val == 0)
210 + {
211 + this.p.resolve(this.results);
212 + }
213 + else
214 + {
215 + this.p.reject(hResult.Val);
216 + }
217 + return (ret);
218 + }
219 + }
220 + ];
221 +
222 +
223 +function enumerateProperties(j, fields)
224 +{
225 + //
226 + // Reference to SafeArrayAccessData() can be found at:
227 + // https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata
228 + //
229 +
230 + var nme, len, nn;
231 + var properties = [];
232 + var values = {};
233 +
234 + j.funcs = require('win-com').marshalFunctions(j.Deref(), ResultFunctions);
235 +
236 + // First we need to enumerate the COM Array
237 + if (fields != null && Array.isArray(fields))
238 + {
239 + properties = fields;
240 + }
241 + else
242 + {
243 + nme = GM.CreatePointer();
244 + j.funcs.GetNames(j.Deref(), 0, WBEM_FLAG_ALWAYS, 0, nme);
245 + len = nme.Deref().Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
246 + nn = GM.CreatePointer();
247 + OleAut32.SafeArrayAccessData(nme.Deref(), nn);
248 +
249 +
250 + for (var i = 0; i < len - 1; ++i)
251 + {
252 + properties.push(nn.Deref().increment(i * GM.PointerSize).Deref().Wide2UTF8);
253 + }
254 + }
255 +
256 + // Now we need to introspect the Array Fields
257 + for (var i = 0; i < properties.length; ++i)
258 + {
259 + var tmp1 = GM.CreateVariable(24);
260 + if (j.funcs.Get(j.Deref(), GM.CreateVariable(properties[i], { wide: true }), 0, tmp1, 0, 0).Val == 0)
261 + {
262 + //
263 + // Reference for IWbemClassObject::Get() can be found at:
264 + // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
265 + //
266 +
267 + var vartype = tmp1.toBuffer().readUInt16LE();
268 + var isArray = (vartype & 0x2000) != 0; // VT_ARRAY flag
269 + var baseType = vartype & 0x0FFF;
270 +
271 + if (isArray)
272 + {
273 + // Handle array types (VT_ARRAY | base type)
274 + var safeArray = tmp1.Deref(8, GM.PointerSize).Deref();
275 + var arrayLength = safeArray.Deref(GM.PointerSize == 8 ? 24 : 16, 4).toBuffer().readUInt32LE();
276 + var arrayData = GM.CreatePointer();
277 + OleAut32.SafeArrayAccessData(safeArray, arrayData);
278 +
279 + var arrayValues = [];
280 + for (var k = 0; k < arrayLength; ++k)
281 + {
282 + switch (baseType)
283 + {
284 + case 0x0002: // VT_I2
285 + arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE());
286 + break;
287 + case 0x0003: // VT_I4
288 + case 0x0016: // VT_INT
289 + arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readInt32LE());
290 + break;
291 + case 0x000B: // VT_BOOL
292 + arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readInt16LE() != 0);
293 + break;
294 + case 0x0010: // VT_I1
295 + arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readInt8());
296 + break;
297 + case 0x0011: // VT_UI1
298 + arrayValues.push(arrayData.Deref().Deref(k, 1).toBuffer().readUInt8());
299 + break;
300 + case 0x0012: // VT_UI2
301 + arrayValues.push(arrayData.Deref().Deref(k * 2, 2).toBuffer().readUInt16LE());
302 + break;
303 + case 0x0013: // VT_UI4
304 + case 0x0017: // VT_UINT
305 + arrayValues.push(arrayData.Deref().Deref(k * 4, 4).toBuffer().readUInt32LE());
306 + break;
307 + case 0x0008: // VT_BSTR
308 + arrayValues.push(arrayData.Deref().Deref(k * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
309 + break;
310 + }
311 + }
312 + values[properties[i]] = arrayValues;
313 + }
314 + else
315 + {
316 + // Handle scalar types
317 + switch (vartype)
318 + {
319 + case 0x0000: // VT_EMPTY
320 + case 0x0001: // VT_NULL
321 + values[properties[i]] = null;
322 + break;
323 + case 0x0002: // VT_I2
324 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt16LE();
325 + break;
326 + case 0x0003: // VT_I4
327 + case 0x0016: // VT_INT
328 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE();
329 + break;
330 + case 0x000B: // VT_BOOL
331 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt32LE() != 0;
332 + break;
333 + case 0x000E: // VT_DECIMAL
334 + break;
335 + case 0x0010: // VT_I1
336 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readInt8();
337 + break;
338 + case 0x0011: // VT_UI1
339 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt8();
340 + break;
341 + case 0x0012: // VT_UI2
342 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt16LE();
343 + break;
344 + case 0x0013: // VT_UI4
345 + case 0x0017: // VT_UINT
346 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).toBuffer().readUInt32LE();
347 + break;
348 + //case 0x0014: // VT_I8
349 + // break;
350 + //case 0x0015: // VT_UI8
351 + // break;
352 + case 0x0008: // VT_BSTR
353 + values[properties[i]] = tmp1.Deref(8, GM.PointerSize).Deref().Wide2UTF8;
354 + break;
355 + default:
356 + console.info1('VARTYPE: ' + vartype);
357 + break;
358 + }
359 + }
360 + }
361 + }
362 +
363 + return (values);
364 +}
365 +
366 +function queryAsync(resourceString, queryString, fields)
367 +{
368 + var p = new promise(require('promise').defaultInit);
369 + var resource = GM.CreateVariable(resourceString, { wide: true });
370 + var language = GM.CreateVariable("WQL", { wide: true });
371 + var query = GM.CreateVariable(queryString, { wide: true });
372 + var results = GM.CreatePointer();
373 +
374 + // Setup the Async COM handler for QueryAsync()
375 + var handlers = require('win-com').marshalInterface(QueryAsyncHandler);
376 + handlers.refcount = 1;
377 + handlers.results = [];
378 + handlers.fields = fields;
379 + handlers.locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
380 + handlers.locator.funcs = require('win-com').marshalFunctions(handlers.locator, LocatorFunctions);
381 +
382 + handlers.services = require('_GenericMarshal').CreatePointer();
383 + if (handlers.locator.funcs.ConnectToServer(handlers.locator, resource, 0, 0, 0, 0, 0, 0, handlers.services).Val != 0) { throw ('Error calling ConnectToService'); }
384 +
385 + handlers.services.funcs = require('win-com').marshalFunctions(handlers.services.Deref(), ServiceFunctions);
386 + handlers.p = p;
387 +
388 + // Make the COM call
389 + if (handlers.services.funcs.ExecQueryAsync(handlers.services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, handlers).Val != 0)
390 + {
391 + throw ('Error in Query');
392 + }
393 +
394 + // Hold a reference to the callback object
395 + wmi_handlers[handlers._hashCode()] = handlers;
396 + return (p);
397 +}
398 +function query(resourceString, queryString, fields)
399 +{
400 + var resource = GM.CreateVariable(resourceString, { wide: true });
401 + var language = GM.CreateVariable("WQL", { wide: true });
402 + var query = GM.CreateVariable(queryString, { wide: true });
403 + var results = GM.CreatePointer();
404 +
405 + // Connect the locator connection for WMI
406 + var locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown);
407 + locator.funcs = require('win-com').marshalFunctions(locator, LocatorFunctions);
408 + var services = require('_GenericMarshal').CreatePointer();
409 + if (locator.funcs.ConnectToServer(locator, resource, 0, 0, 0, 0, 0, 0, services).Val != 0) { throw ('Error calling ConnectToService'); }
410 +
411 + // Execute the Query
412 + services.funcs = require('win-com').marshalFunctions(services.Deref(), ServiceFunctions);
413 + if (services.funcs.ExecQuery(services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, results).Val != 0) { throw ('Error in Query'); }
414 +
415 + results.funcs = require('win-com').marshalFunctions(results.Deref(), ResultsFunctions);
416 + var returnedCount = GM.CreateVariable(8);
417 + var result = GM.CreatePointer();
418 + var ret = [];
419 +
420 + // Enumerate the results
421 + while (results.funcs.Next(results.Deref(), WBEM_INFINITE, 1, result, returnedCount).Val == 0)
422 + {
423 + ret.push(enumerateProperties(result, fields));
424 + }
425 +
426 + results.funcs.Release(results.Deref());
427 + services.funcs.Release(services.Deref());
428 + locator.funcs.Release(locator);
429 +
430 + return (ret);
431 +}
432 +
433 +module.exports = { query: query, queryAsync: queryAsync };