diff --git a/modules/win-com.js b/modules/win-com.js index 953cd79..7c29857 100644 --- a/modules/win-com.js +++ b/modules/win-com.js @@ -26,15 +26,15 @@ const IUnknownMethods = ['QueryInterface', 'AddRef', 'Release']; var GM = require('_GenericMarshal'); var ole32 = GM.CreateNativeProxy('ole32.dll'); -ole32.CreateMethod('CLSIDFromString'); -ole32.CreateMethod('CoCreateInstance'); -ole32.CreateMethod('CoInitializeSecurity'); -ole32.CreateMethod('CoInitialize'); -ole32.CreateMethod('CoInitializeEx'); -ole32.CreateMethod('CoUninitialize'); -ole32.CreateMethod('IIDFromString'); -ole32.CreateMethod('StringFromCLSID'); -ole32.CreateMethod('StringFromIID'); +ole32.CreateMethod('CLSIDFromString'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring +ole32.CreateMethod('CoCreateInstance'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance +ole32.CreateMethod('CoInitializeSecurity'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity +ole32.CreateMethod('CoInitialize'); // https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize +ole32.CreateMethod('CoInitializeEx'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex +ole32.CreateMethod('CoUninitialize'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize +ole32.CreateMethod('IIDFromString'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-iidfromstring +ole32.CreateMethod('StringFromCLSID'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-stringfromclsid +ole32.CreateMethod('StringFromIID'); // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-stringfromiid function createInstance_finalizer() @@ -44,10 +44,14 @@ function createInstance_finalizer() } function createInstance(RFCLSID, RFIID, options) { + // Start by initializing the Windows COM Library console.info1('CoInitializeEx()'); ole32.CoInitializeEx(0, COINIT_MULTITHREADED); + + // Set default Security Values for COM ole32.CoInitializeSecurity(0, -1, 0, 0, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE, 0); + // Create Instance of COM Object var ppv = GM.CreatePointer(); var h; if ((h = ole32.CoCreateInstance(RFCLSID, 0, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, RFIID,ppv)).Val == 0) @@ -58,11 +62,13 @@ function createInstance(RFCLSID, RFIID, options) } else { + // If it fails, we can tear down the COM library ole32.CoUninitialize(); } throw ('Error calling CoCreateInstance(' + h.Val + ')'); } +// Convert from STRING to CLSID function CLSIDFromString(CLSIDString) { var v = GM.CreateVariable(CLSIDString, { wide: true }); @@ -77,6 +83,8 @@ function CLSIDFromString(CLSIDString) throw ('Error Converting CLSIDString'); } } + +// Convert from STRING to IID function IIDFromString(IIDString) { var v = GM.CreateVariable(IIDString, { wide: true }); @@ -92,10 +100,13 @@ function IIDFromString(IIDString) } } +// Create an array of functions, from the definitions function marshalFunctions(obj, arr) { return (GM.MarshalFunctions(obj.Deref(), arr)); } + +// Implement a COM interface, and attach it to the local vtable function marshalInterface(arr) { if (GM.PointerSize == 4) @@ -114,6 +125,7 @@ function marshalInterface(arr) vtbl.pointerBuffer().copy(obj.toBuffer()); obj._gcallbacks = []; + // Cleanup function, which clears all the callbacks obj.cleanup = function () { var v; @@ -125,6 +137,8 @@ function marshalInterface(arr) } }; + + // Enumerate the functions, and put them in the local vtable for the COM interface for (var i = 0; i < arr.length; ++i) { _hide(GM.GetGenericGlobalCallbackEx(arr[i].parms, GM.PointerSize == 4 ? arr[i].cx : null)); // Only 32 bit needs custom handlers diff --git a/modules/win-utils.js b/modules/win-utils.js index 79c04a7..b10e474 100644 --- a/modules/win-utils.js +++ b/modules/win-utils.js @@ -25,6 +25,9 @@ function winutils() this._ObjectID = 'win-utils'; this.taskBar = { + // + // This function will enable/disable the system taskbar autohide functionality + // autoHide: function autoHide(tsid, value) { var domain = require('user-sessions').getDomain(tsid); @@ -38,12 +41,16 @@ function winutils() } else { + // Set the state, into the registry var rv = reg.QueryKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects3', 'Settings'); rv[8] = value === true ? 3 : 2; reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects3', 'Settings', rv); + + // In order for the changes to take effect, we must restart the explorer shell. var pids = require('process-manager').getProcessEx('explorer.exe'); if(pids.length == 1) { + // Windows will automatically restart explorer if you kill it process.kill(pids[0]); } return (this.autoHide(tsid)); diff --git a/modules/win-virtual-terminal.js b/modules/win-virtual-terminal.js index 8709af7..818ab6a 100644 --- a/modules/win-virtual-terminal.js +++ b/modules/win-virtual-terminal.js @@ -47,20 +47,20 @@ function vt() var GM = require('_GenericMarshal'); var k32 = GM.CreateNativeProxy('kernel32.dll'); - k32.CreateMethod('CancelIoEx'); - k32.CreateMethod('CreatePipe'); - k32.CreateMethod('CreateProcessW'); - k32.CreateMethod('CreatePseudoConsole'); - k32.CreateMethod('CloseHandle'); - k32.CreateMethod('ClosePseudoConsole'); - k32.CreateMethod('GetProcessHeap'); - k32.CreateMethod('HeapAlloc'); - k32.CreateMethod('InitializeProcThreadAttributeList'); - k32.CreateMethod('ResizePseudoConsole'); - k32.CreateMethod('UpdateProcThreadAttribute'); - k32.CreateMethod('WriteFile'); - k32.CreateMethod('ReadFile'); - k32.CreateMethod('TerminateProcess'); + k32.CreateMethod('CancelIoEx'); // https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func + k32.CreateMethod('CreatePipe'); // https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe + k32.CreateMethod('CreateProcessW'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw + k32.CreateMethod('CreatePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/createpseudoconsole + k32.CreateMethod('CloseHandle'); // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + k32.CreateMethod('ClosePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/closepseudoconsole + k32.CreateMethod('GetProcessHeap'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap + k32.CreateMethod('HeapAlloc'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc + k32.CreateMethod('InitializeProcThreadAttributeList'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist + k32.CreateMethod('ResizePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/resizepseudoconsole + k32.CreateMethod('UpdateProcThreadAttribute'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute + k32.CreateMethod('WriteFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile + k32.CreateMethod('ReadFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile + k32.CreateMethod('TerminateProcess'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess var ret = { _h: GM.CreatePointer(), _consoleInput: GM.CreatePointer(), _consoleOutput: GM.CreatePointer(), _input: GM.CreatePointer(), _output: GM.CreatePointer(), k32: k32 }; var attrSize = GM.CreateVariable(8); @@ -77,18 +77,31 @@ function vt() throw ('Error calling CreatePseudoConsole()'); } + // + // Reference for STARTUPINFOEXW + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexw + // + + // + // Reference for STARTUPINFOW + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow + // + k32.InitializeProcThreadAttributeList(0, 1, 0, attrSize); attrList = GM.CreateVariable(attrSize.toBuffer().readUInt32LE()); - var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); - startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); - attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); + var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); // Create Structure, 64 bits is 112 bytes, 32 bits is 72 bytes + startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); // Write buffer size + attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); // Write the reference to STARTUPINFOEX if (k32.InitializeProcThreadAttributeList(attrList, 1, 0, attrSize).Val != 0) { if (k32.UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, ret._h.Deref(), GM.PointerSize, 0, 0).Val != 0) { - if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) + if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) // Create the process to run in the pseudoconsole { + // + // Create a Stream Object, to be able to read/write data to the pseudoconsole + // ret._startupinfoex = startupinfoex; ret._process = pi.Deref(0); ret._pid = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE(); @@ -111,6 +124,10 @@ function vt() flush(); } }); + + // + // The ProcessInfo object is signaled when the process exits + // ds._obj = ret; ret._waiter = require('DescriptorEvents').addDescriptor(pi.Deref(0)); ret._waiter.ds = ds; @@ -151,6 +168,7 @@ function vt() ds._rpbufRead = GM.CreateVariable(4); ds.__read = function __read() { + // Asyncronously read data from the pseudoconsole this._rp = this.terminal.k32.ReadFile.async(this.terminal._output.Deref(), this._rpbuf, this._rpbuf._size, this._rpbufRead, 0); this._rp.then(function () { @@ -173,6 +191,8 @@ function vt() } throw ('Internal Error'); } + + // This evaluates whether or not the powershell binary exists this.PowerShellCapable = function () { if (require('os').arch() == 'x64') @@ -184,10 +204,14 @@ function vt() return (require('fs').existsSync(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe')); } } + + // Start the PseudoConsole with the Command Prompt this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT) { return (this.Create(process.env['windir'] + '\\System32\\cmd.exe', CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)); } + + // Start the PseduoConsole with PowerShell this.StartPowerShell = function StartPowerShell(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT) { if (require('os').arch() == 'x64') diff --git a/modules/win-volumes.js b/modules/win-volumes.js index e0e1127..c9651d6 100644 --- a/modules/win-volumes.js +++ b/modules/win-volumes.js @@ -27,9 +27,14 @@ function trimObject(j) return (j); } - +// +// Fetches volume information from Windows +// function getVolumes() { + // + // Query Volume Information from WMI + // var v = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_Volume'); var i; @@ -40,6 +45,9 @@ function getVolumes() ret[v[i].DeviceID] = trimObject(v[i]); } + // + // Queries BitLocker status for Windows Volumes from WMI + // v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume'); for (i in v) { diff --git a/modules/win-wmi.js b/modules/win-wmi.js index eb536d1..e038c61 100644 --- a/modules/win-wmi.js +++ b/modules/win-wmi.js @@ -28,6 +28,11 @@ OleAut32.CreateMethod('SafeArrayAccessData'); var wmi_handlers = {}; const LocatorFunctions = ['QueryInterface', 'AddRef', 'Release', 'ConnectToServer']; + +// +// Reference for IWbemServices can be found at: +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemservices +// const ServiceFunctions = [ 'QueryInterface', 'AddRef', @@ -56,6 +61,11 @@ const ServiceFunctions = [ 'ExecMethod', 'ExecMethodAsync' ]; + +// +// Reference to IEnumWbemClassObject can be found at: +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-ienumwbemclassobject +// const ResultsFunctions = [ 'QueryInterface', 'AddRef', @@ -66,6 +76,11 @@ const ResultsFunctions = [ 'Clone', 'Skip' ]; + +// +// Reference to IWbemClassObject can be found at: +// https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject +// const ResultFunctions = [ 'QueryInterface', 'AddRef', @@ -96,6 +111,10 @@ const ResultFunctions = [ 'GetMethodOrigin' ]; +// +// Reference to IWbemObjectSink can be found at: +// https://learn.microsoft.com/en-us/windows/win32/wmisdk/iwbemobjectsink +// const QueryAsyncHandler = [ { @@ -203,12 +222,18 @@ const QueryAsyncHandler = function enumerateProperties(j, fields) { + // + // Reference to SafeArrayAccessData() can be found at: + // https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearrayaccessdata + // + var nme, len, nn; var properties = []; var values = {}; j.funcs = require('win-com').marshalFunctions(j.Deref(), ResultFunctions); + // First we need to enumerate the COM Array if (fields != null && Array.isArray(fields)) { properties = fields; @@ -228,12 +253,17 @@ function enumerateProperties(j, fields) } } - + // Now we need to introspect the Array Fields for (var i = 0; i < properties.length; ++i) { var tmp1 = GM.CreateVariable(24); if (j.funcs.Get(j.Deref(), GM.CreateVariable(properties[i], { wide: true }), 0, tmp1, 0, 0).Val == 0) { + // + // Reference for IWbemClassObject::Get() can be found at: + // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get + // + switch (tmp1.toBuffer().readUInt16LE()) { case 0x0000: // VT_EMPTY @@ -290,7 +320,7 @@ function queryAsync(resourceString, queryString, fields) var query = GM.CreateVariable(queryString, { wide: true }); var results = GM.CreatePointer(); - + // Setup the Async COM handler for QueryAsync() var handlers = require('win-com').marshalInterface(QueryAsyncHandler); handlers.refcount = 1; handlers.results = []; @@ -304,11 +334,13 @@ function queryAsync(resourceString, queryString, fields) handlers.services.funcs = require('win-com').marshalFunctions(handlers.services.Deref(), ServiceFunctions); handlers.p = p; + // Make the COM call if (handlers.services.funcs.ExecQueryAsync(handlers.services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, handlers).Val != 0) { throw ('Error in Query'); } + // Hold a reference to the callback object wmi_handlers[handlers._hashCode()] = handlers; return (p); } @@ -319,11 +351,13 @@ function query(resourceString, queryString, fields) var query = GM.CreateVariable(queryString, { wide: true }); var results = GM.CreatePointer(); + // Connect the locator connection for WMI var locator = require('win-com').createInstance(require('win-com').CLSIDFromString(CLSID_WbemAdministrativeLocator), require('win-com').IID_IUnknown); locator.funcs = require('win-com').marshalFunctions(locator, LocatorFunctions); var services = require('_GenericMarshal').CreatePointer(); if (locator.funcs.ConnectToServer(locator, resource, 0, 0, 0, 0, 0, 0, services).Val != 0) { throw ('Error calling ConnectToService'); } + // Execute the Query services.funcs = require('win-com').marshalFunctions(services.Deref(), ServiceFunctions); if (services.funcs.ExecQuery(services.Deref(), language, query, WBEM_FLAG_BIDIRECTIONAL, 0, results).Val != 0) { throw ('Error in Query'); } @@ -332,6 +366,7 @@ function query(resourceString, queryString, fields) var result = GM.CreatePointer(); var ret = []; + // Enumerate the results while (results.funcs.Next(results.Deref(), WBEM_INFINITE, 1, result, returnedCount).Val == 0) { ret.push(enumerateProperties(result, fields));