mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-25 06:35:54 -05:00
Improved Windows Terminal
This commit is contained in:
parent
c65f417e9b
commit
d31b3336bd
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1892
agents/meshcore-01.js
Normal file
1892
agents/meshcore-01.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
process.on('uncaughtException', function (ex) {
|
||||
require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": "uncaughtException1: " + ex });
|
||||
});
|
||||
@ -652,18 +651,24 @@ function createMeshCore(agent) {
|
||||
}
|
||||
|
||||
// Remote terminal using native pipes
|
||||
if (process.platform == "win32") {
|
||||
this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
|
||||
} else {
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
this.httprequest._term = require('win-terminal').Start(80, 25);
|
||||
this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
|
||||
this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
|
||||
this.prependListener('end', function () { this.httprequest._term.end(function () { console.log('Terminal was closed');}); });
|
||||
//this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
|
||||
} else
|
||||
{
|
||||
this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
|
||||
this.httprequest.process.tunnel = this;
|
||||
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
|
||||
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
|
||||
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
this.prependListener('end', function () { this.httprequest.process.kill(); });
|
||||
}
|
||||
|
||||
this.httprequest.process.tunnel = this;
|
||||
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
|
||||
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
|
||||
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
this.prependListener('end', function () { this.httprequest.process.kill(); });
|
||||
this.removeAllListeners('data');
|
||||
this.on('data', onTunnelControlData);
|
||||
//this.write('MeshCore Terminal Hello');
|
||||
@ -914,8 +919,15 @@ function createMeshCore(agent) {
|
||||
} else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
|
||||
if (ws.httprequest.protocol == 1) { // Terminal
|
||||
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
|
||||
ws.httprequest.process.stdout.unpipe(ws);
|
||||
ws.httprequest.process.stderr.unpipe(ws);
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
ws.httprequest._term.unpipe(ws);
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.httprequest.process.stdout.unpipe(ws);
|
||||
ws.httprequest.process.stderr.unpipe(ws);
|
||||
}
|
||||
} else if (ws.httprequest.protocol == 2) { // Desktop
|
||||
// This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
|
||||
ws.httprequest.desktop.kvm.unpipe(ws);
|
||||
@ -929,8 +941,16 @@ function createMeshCore(agent) {
|
||||
} else if (obj.type == 'webrtc1') {
|
||||
if (ws.httprequest.protocol == 1) { // Terminal
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
ws.unpipe(ws.httprequest.process.stdin);
|
||||
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
ws.unpipe(ws.httprequest._term);
|
||||
ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.unpipe(ws.httprequest.process.stdin);
|
||||
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
ws.resume(); // Resume the websocket to keep receiving control data
|
||||
} else if (ws.httprequest.protocol == 2) { // Desktop
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
@ -942,8 +962,15 @@ function createMeshCore(agent) {
|
||||
} else if (obj.type == 'webrtc2') {
|
||||
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
||||
if (ws.httprequest.protocol == 1) { // Terminal
|
||||
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
} else if (ws.httprequest.protocol == 2) { // Desktop
|
||||
ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var red = 0xFF;
|
||||
var yellow = 0xFFFF;
|
||||
var GXxor = 0x6; // src XOR dst
|
||||
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var promise = require('promise');
|
||||
var PPosition = 4;
|
||||
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var refTable = {};
|
||||
|
||||
function event_switcher_helper(desired_callee, target)
|
||||
{
|
||||
this._ObjectID = 'event_switcher';
|
||||
this.func = function func()
|
||||
{
|
||||
var args = [];
|
||||
for(var i in arguments)
|
||||
{
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
return (func.target.apply(func.desired, args));
|
||||
};
|
||||
this.func.desired = desired_callee;
|
||||
this.func.target = target;
|
||||
this.func.self = this;
|
||||
}
|
||||
function event_switcher(desired_callee, target)
|
||||
{
|
||||
return (new event_switcher_helper(desired_callee, target));
|
||||
}
|
||||
|
||||
function Promise(promiseFunc)
|
||||
{
|
||||
this._ObjectID = 'promise';
|
||||
this.promise = this;
|
||||
this._internal = { _ObjectID: 'promise.internal', promise: this, func: promiseFunc, completed: false, errors: false, completedArgs: [] };
|
||||
require('events').EventEmitter.call(this._internal);
|
||||
this._internal.on('_eventHook', function (eventName, eventCallback)
|
||||
{
|
||||
//console.log('hook', eventName, 'errors/' + this.errors + ' completed/' + this.completed);
|
||||
var r = null;
|
||||
|
||||
if (eventName == 'resolved' && !this.errors && this.completed)
|
||||
{
|
||||
r = eventCallback.apply(this, this.completedArgs);
|
||||
if(r!=null)
|
||||
{
|
||||
this.emit_returnValue('resolved', r);
|
||||
}
|
||||
}
|
||||
if (eventName == 'rejected' && this.errors && this.completed)
|
||||
{
|
||||
eventCallback.apply(this, this.completedArgs);
|
||||
}
|
||||
if (eventName == 'settled' && this.completed)
|
||||
{
|
||||
eventCallback.apply(this, []);
|
||||
}
|
||||
});
|
||||
this._internal.resolver = function _resolver()
|
||||
{
|
||||
_resolver._self.errors = false;
|
||||
_resolver._self.completed = true;
|
||||
_resolver._self.completedArgs = [];
|
||||
var args = ['resolved'];
|
||||
if (this.emit_returnValue && this.emit_returnValue('resolved') != null)
|
||||
{
|
||||
_resolver._self.completedArgs.push(this.emit_returnValue('resolved'));
|
||||
args.push(this.emit_returnValue('resolved'));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var a in arguments)
|
||||
{
|
||||
_resolver._self.completedArgs.push(arguments[a]);
|
||||
args.push(arguments[a]);
|
||||
}
|
||||
}
|
||||
_resolver._self.emit.apply(_resolver._self, args);
|
||||
_resolver._self.emit('settled');
|
||||
};
|
||||
this._internal.rejector = function _rejector()
|
||||
{
|
||||
_rejector._self.errors = true;
|
||||
_rejector._self.completed = true;
|
||||
_rejector._self.completedArgs = [];
|
||||
var args = ['rejected'];
|
||||
for (var a in arguments)
|
||||
{
|
||||
_rejector._self.completedArgs.push(arguments[a]);
|
||||
args.push(arguments[a]);
|
||||
}
|
||||
|
||||
_rejector._self.emit.apply(_rejector._self, args);
|
||||
_rejector._self.emit('settled');
|
||||
};
|
||||
this.catch = function(func)
|
||||
{
|
||||
this._internal.once('rejected', event_switcher(this, func).func);
|
||||
}
|
||||
this.finally = function (func)
|
||||
{
|
||||
this._internal.once('settled', event_switcher(this, func).func);
|
||||
};
|
||||
this.then = function (resolved, rejected)
|
||||
{
|
||||
if (resolved) { this._internal.once('resolved', event_switcher(this, resolved).func); }
|
||||
if (rejected) { this._internal.once('rejected', event_switcher(this, rejected).func); }
|
||||
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
this._internal.once('resolved', retVal._internal.resolver);
|
||||
this._internal.once('rejected', retVal._internal.rejector);
|
||||
retVal.parentPromise = this;
|
||||
return (retVal);
|
||||
};
|
||||
|
||||
this._internal.resolver._self = this._internal;
|
||||
this._internal.rejector._self = this._internal;;
|
||||
|
||||
try
|
||||
{
|
||||
promiseFunc.call(this, this._internal.resolver, this._internal.rejector);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this._internal.errors = true;
|
||||
this._internal.completed = true;
|
||||
this._internal.completedArgs = [e];
|
||||
this._internal.emit('rejected', e);
|
||||
this._internal.emit('settled');
|
||||
}
|
||||
|
||||
if(!this._internal.completed)
|
||||
{
|
||||
// Save reference of this object
|
||||
refTable[this._internal._hashCode()] = this._internal;
|
||||
this._internal.once('settled', function () { refTable[this._hashCode()] = null; });
|
||||
}
|
||||
}
|
||||
|
||||
Promise.resolve = function resolve()
|
||||
{
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
var args = [];
|
||||
for (var i in arguments)
|
||||
{
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
retVal._internal.resolver.apply(retVal._internal, args);
|
||||
return (retVal);
|
||||
};
|
||||
Promise.reject = function reject() {
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
var args = [];
|
||||
for (var i in arguments) {
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
retVal._internal.rejector.apply(retVal._internal, args);
|
||||
return (retVal);
|
||||
};
|
||||
Promise.all = function all(promiseList)
|
||||
{
|
||||
var ret = new Promise(function (res, rej)
|
||||
{
|
||||
this.__rejector = rej;
|
||||
this.__resolver = res;
|
||||
this.__promiseList = promiseList;
|
||||
this.__done = false;
|
||||
this.__count = 0;
|
||||
});
|
||||
|
||||
for (var i in promiseList)
|
||||
{
|
||||
promiseList[i].then(function ()
|
||||
{
|
||||
// Success
|
||||
if(++ret.__count == ret.__promiseList.length)
|
||||
{
|
||||
ret.__done = true;
|
||||
ret.__resolver(ret.__promiseList);
|
||||
}
|
||||
}, function (arg)
|
||||
{
|
||||
// Failure
|
||||
if(!ret.__done)
|
||||
{
|
||||
ret.__done = true;
|
||||
ret.__rejector(arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (promiseList.length == 0)
|
||||
{
|
||||
ret.__resolver(promiseList);
|
||||
}
|
||||
return (ret);
|
||||
};
|
||||
|
||||
module.exports = Promise;
|
@ -214,6 +214,13 @@ function serviceManager()
|
||||
throw ('could not find service: ' + name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isAdmin = function isAdmin()
|
||||
{
|
||||
return (require('user-sessions').isRoot());
|
||||
}
|
||||
}
|
||||
this.installService = function installService(options)
|
||||
{
|
||||
if (process.platform == 'win32')
|
||||
@ -273,6 +280,8 @@ function serviceManager()
|
||||
}
|
||||
if(process.platform == 'linux')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
|
||||
|
||||
switch (this.getServiceType())
|
||||
{
|
||||
case 'init':
|
||||
@ -311,14 +320,70 @@ function serviceManager()
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(process.platform == 'darwin')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
|
||||
|
||||
// Mac OS
|
||||
var stdoutpath = (options.stdout ? ('<key>StandardOutPath</key>\n<string>' + options.stdout + '</string>') : '');
|
||||
var autoStart = (options.startType == 'AUTO_START' ? '<true/>' : '<false/>');
|
||||
var params = ' <key>ProgramArguments</key>\n';
|
||||
params += ' <array>\n';
|
||||
params += (' <string>/usr/local/mesh_services/' + options.name + '/' + options.name + '</string>\n');
|
||||
if(options.parameters)
|
||||
{
|
||||
for(var itm in options.parameters)
|
||||
{
|
||||
params += (' <string>' + options.parameters[itm] + '</string>\n');
|
||||
}
|
||||
}
|
||||
params += ' </array>\n';
|
||||
|
||||
var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
||||
plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
|
||||
plist += '<plist version="1.0">\n';
|
||||
plist += ' <dict>\n';
|
||||
plist += ' <key>Label</key>\n';
|
||||
plist += (' <string>' + options.name + '</string>\n');
|
||||
plist += (params + '\n');
|
||||
plist += ' <key>WorkingDirectory</key>\n';
|
||||
plist += (' <string>/usr/local/mesh_services/' + options.name + '</string>\n');
|
||||
plist += (stdoutpath + '\n');
|
||||
plist += ' <key>RunAtLoad</key>\n';
|
||||
plist += (autoStart + '\n');
|
||||
plist += ' </dict>\n';
|
||||
plist += '</plist>';
|
||||
|
||||
if (!require('fs').existsSync('/usr/local/mesh_services')) { require('fs').mkdirSync('/usr/local/mesh_services'); }
|
||||
if (!require('fs').existsSync('/Library/LaunchDaemons/' + options.name + '.plist'))
|
||||
{
|
||||
if (!require('fs').existsSync('/usr/local/mesh_services/' + options.name)) { require('fs').mkdirSync('/usr/local/mesh_services/' + options.name); }
|
||||
if (options.binary)
|
||||
{
|
||||
require('fs').writeFileSync('/usr/local/mesh_services/' + options.name + '/' + options.name, options.binary);
|
||||
}
|
||||
else
|
||||
{
|
||||
require('fs').copyFileSync(options.servicePath, '/usr/local/mesh_services/' + options.name + '/' + options.name);
|
||||
}
|
||||
require('fs').writeFileSync('/Library/LaunchDaemons/' + options.name + '.plist', plist);
|
||||
var m = require('fs').statSync('/usr/local/mesh_services/' + options.name + '/' + options.name).mode;
|
||||
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP);
|
||||
require('fs').chmodSync('/usr/local/mesh_services/' + options.name + '/' + options.name, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('Service: ' + options.name + ' already exists');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.uninstallService = function uninstallService(name)
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
|
||||
|
||||
if (typeof (name) == 'object') { name = name.name; }
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
|
||||
|
||||
var service = this.getService(name);
|
||||
if (service.status.state == undefined || service.status.state == 'STOPPED')
|
||||
{
|
||||
@ -388,6 +453,39 @@ function serviceManager()
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(process.platform == 'darwin')
|
||||
{
|
||||
if (require('fs').existsSync('/Library/LaunchDaemons/' + name + '.plist'))
|
||||
{
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.on('data', function (chunk) { });
|
||||
child.stdin.write('launchctl stop ' + name + '\n');
|
||||
child.stdin.write('launchctl unload /Library/LaunchDaemons/' + name + '.plist\n');
|
||||
child.stdin.write('exit\n');
|
||||
child.waitExit();
|
||||
|
||||
try
|
||||
{
|
||||
require('fs').unlinkSync('/usr/local/mesh_services/' + name + '/' + name);
|
||||
require('fs').unlinkSync('/Library/LaunchDaemons/' + name + '.plist');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
throw ('Error uninstalling service: ' + name + ' => ' + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
require('fs').rmdirSync('/usr/local/mesh_services/' + name);
|
||||
}
|
||||
catch(e)
|
||||
{}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('Service: ' + name + ' does not exist');
|
||||
}
|
||||
}
|
||||
}
|
||||
if(process.platform == 'linux')
|
||||
{
|
||||
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
function _Scan()
|
||||
{
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var MemoryStream = require('MemoryStream');
|
||||
var WindowsChildScript = 'var parent = require("ScriptContainer");var Wireless = require("wifi-scanner-windows");Wireless.on("Scan", function (ap) { parent.send(ap); });Wireless.Scan();';
|
||||
|
||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
||||
var WH_CALLWNDPROC = 4;
|
||||
var WM_QUIT = 0x0012;
|
||||
|
||||
var GM = require('_GenericMarshal');
|
||||
|
||||
function WindowsMessagePump(options)
|
||||
{
|
||||
this._ObjectID = 'win-message-pump';
|
||||
@ -27,92 +29,94 @@ function WindowsMessagePump(options)
|
||||
emitterUtils.createEvent('message');
|
||||
emitterUtils.createEvent('exit');
|
||||
|
||||
this._child = require('ScriptContainer').Create({ processIsolation: 0 });
|
||||
this._child.MessagePump = this;
|
||||
this._child.prependListener('~', function _childFinalizer() { this.MessagePump.emit('exit', 0); this.MessagePump.stop(); });
|
||||
this._child.once('exit', function onExit(code) { this.MessagePump.emit('exit', code); });
|
||||
this._child.once('ready', function onReady()
|
||||
{
|
||||
var execString =
|
||||
"var m = require('_GenericMarshal');\
|
||||
var h = null;\
|
||||
var k = m.CreateNativeProxy('Kernel32.dll');\
|
||||
k.CreateMethod('GetLastError');\
|
||||
k.CreateMethod('GetModuleHandleA');\
|
||||
var u = m.CreateNativeProxy('User32.dll');\
|
||||
u.CreateMethod('GetMessageA');\
|
||||
u.CreateMethod('CreateWindowExA');\
|
||||
u.CreateMethod('TranslateMessage');\
|
||||
u.CreateMethod('DispatchMessageA');\
|
||||
u.CreateMethod('RegisterClassExA');\
|
||||
u.CreateMethod('DefWindowProcA');\
|
||||
var wndclass = m.CreateVariable(m.PointerSize == 4 ? 48 : 80);\
|
||||
wndclass.hinstance = k.GetModuleHandleA(0);\
|
||||
wndclass.cname = m.CreateVariable('MainWWWClass');\
|
||||
wndclass.wndproc = m.GetGenericGlobalCallback(4);\
|
||||
wndclass.toBuffer().writeUInt32LE(wndclass._size);\
|
||||
wndclass.cname.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 40 : 64, m.PointerSize).toBuffer());\
|
||||
wndclass.wndproc.pointerBuffer().copy(wndclass.Deref(8, m.PointerSize).toBuffer());\
|
||||
wndclass.hinstance.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 20 : 24, m.PointerSize).toBuffer());\
|
||||
wndclass.wndproc.on('GlobalCallback', function onWndProc(xhwnd, xmsg, wparam, lparam)\
|
||||
{\
|
||||
if(h==null || h.Val == xhwnd.Val)\
|
||||
{\
|
||||
require('ScriptContainer').send({message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val, lparam_hex: lparam.pointerBuffer().toString('hex')});\
|
||||
var retVal = u.DefWindowProcA(xhwnd, xmsg, wparam, lparam);\
|
||||
return(retVal);\
|
||||
}\
|
||||
});\
|
||||
u.RegisterClassExA(wndclass);\
|
||||
h = u.CreateWindowExA(0x00000088, wndclass.cname, 0, 0x00800000, 0, 0, 100, 100, 0, 0, 0, 0);\
|
||||
if(h.Val == 0)\
|
||||
{\
|
||||
require('ScriptContainer').send({error: 'Error Creating Hidden Window'});\
|
||||
process.exit();\
|
||||
}\
|
||||
require('ScriptContainer').send({hwnd: h.pointerBuffer().toString('hex')});\
|
||||
require('ScriptContainer').on('data', function onData(jmsg)\
|
||||
{\
|
||||
if(jmsg.listen)\
|
||||
{\
|
||||
var msg = m.CreateVariable(m.PointerSize == 4 ? 28 : 48);\
|
||||
while(u.GetMessageA(msg, h, 0, 0).Val>0)\
|
||||
{\
|
||||
u.TranslateMessage(msg);\
|
||||
u.DispatchMessageA(msg);\
|
||||
}\
|
||||
process.exit();\
|
||||
}\
|
||||
});";
|
||||
this._msg = GM.CreateVariable(GM.PointerSize == 4 ? 28 : 48);
|
||||
this._kernel32 = GM.CreateNativeProxy('Kernel32.dll');
|
||||
this._kernel32.mp = this;
|
||||
this._kernel32.CreateMethod('GetLastError');
|
||||
this._kernel32.CreateMethod('GetModuleHandleA');
|
||||
|
||||
this.ExecuteString(execString);
|
||||
});
|
||||
this._child.on('data', function onChildData(msg)
|
||||
this._user32 = GM.CreateNativeProxy('User32.dll');
|
||||
this._user32.mp = this;
|
||||
this._user32.CreateMethod('GetMessageA');
|
||||
this._user32.CreateMethod('CreateWindowExA');
|
||||
this._user32.CreateMethod('TranslateMessage');
|
||||
this._user32.CreateMethod('DispatchMessageA');
|
||||
this._user32.CreateMethod('RegisterClassExA');
|
||||
this._user32.CreateMethod('DefWindowProcA');
|
||||
this._user32.CreateMethod('PostMessageA');
|
||||
|
||||
|
||||
this.wndclass = GM.CreateVariable(GM.PointerSize == 4 ? 48 : 80);
|
||||
this.wndclass.mp = this;
|
||||
this.wndclass.hinstance = this._kernel32.GetModuleHandleA(0);
|
||||
this.wndclass.cname = GM.CreateVariable('MainWWWClass');
|
||||
this.wndclass.wndproc = GM.GetGenericGlobalCallback(4);
|
||||
this.wndclass.wndproc.mp = this;
|
||||
this.wndclass.toBuffer().writeUInt32LE(this.wndclass._size);
|
||||
this.wndclass.cname.pointerBuffer().copy(this.wndclass.Deref(GM.PointerSize == 4 ? 40 : 64, GM.PointerSize).toBuffer());
|
||||
this.wndclass.wndproc.pointerBuffer().copy(this.wndclass.Deref(8, GM.PointerSize).toBuffer());
|
||||
this.wndclass.hinstance.pointerBuffer().copy(this.wndclass.Deref(GM.PointerSize == 4 ? 20 : 24, GM.PointerSize).toBuffer());
|
||||
this.wndclass.wndproc.on('GlobalCallback', function onWndProc(xhwnd, xmsg, wparam, lparam)
|
||||
{
|
||||
if (msg.hwnd)
|
||||
if (this.mp._hwnd != null && this.mp._hwnd.Val == xhwnd.Val)
|
||||
{
|
||||
var m = require('_GenericMarshal');
|
||||
this._hwnd = m.CreatePointer(Buffer.from(msg.hwnd, 'hex'));
|
||||
this.MessagePump.emit('hwnd', this._hwnd);
|
||||
this.send({ listen: this.MessagePump._options.filter });
|
||||
// This is for us
|
||||
this.mp.emit('message', { message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val, lparam_hex: lparam.pointerBuffer().toString('hex') });
|
||||
return (this.mp._user32.DefWindowProcA(xhwnd, xmsg, wparam, lparam));
|
||||
}
|
||||
else if(msg.message)
|
||||
else if(this.mp._hwnd == null && this.CallingThread() == this.mp._user32.RegisterClassExA.async.threadId())
|
||||
{
|
||||
this.MessagePump.emit('message', msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log('Received: ', msg);
|
||||
// This message was generated from our CreateWindowExA method
|
||||
return (this.mp._user32.DefWindowProcA(xhwnd, xmsg, wparam, lparam));
|
||||
}
|
||||
});
|
||||
|
||||
this._user32.RegisterClassExA.async(this.wndclass).then(function ()
|
||||
{
|
||||
this.nativeProxy.CreateWindowExA.async(this.nativeProxy.RegisterClassExA.async, 0x00000088, this.nativeProxy.mp.wndclass.cname, 0, 0x00800000, 0, 0, 100, 100, 0, 0, 0, 0)
|
||||
.then(function(h)
|
||||
{
|
||||
if (h.Val == 0)
|
||||
{
|
||||
// Error creating hidden window
|
||||
this.nativeProxy.mp.emit('error', 'Error creating hidden window');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nativeProxy.mp._hwnd = h;
|
||||
this.nativeProxy.mp.emit('hwnd', h);
|
||||
this.nativeProxy.mp._startPump();
|
||||
}
|
||||
});
|
||||
});
|
||||
this._startPump = function _startPump()
|
||||
{
|
||||
this._user32.GetMessageA.async(this._user32.RegisterClassExA.async, this._msg, this._hwnd, 0, 0).then(function (r)
|
||||
{
|
||||
if(r.Val > 0)
|
||||
{
|
||||
this.nativeProxy.TranslateMessage.async(this.nativeProxy.RegisterClassExA.async, this.nativeProxy.mp._msg).then(function ()
|
||||
{
|
||||
this.nativeProxy.DispatchMessageA.async(this.nativeProxy.RegisterClassExA.async, this.nativeProxy.mp._msg).then(function ()
|
||||
{
|
||||
this.nativeProxy.mp._startPump();
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// We got a 'QUIT' message
|
||||
delete this.nativeProxy.mp._hwnd;
|
||||
this.nativeProxy.mp.emit('exit', 0);
|
||||
}
|
||||
}, function (err) { this.nativeProxy.mp.stop(); });
|
||||
}
|
||||
|
||||
this.stop = function stop()
|
||||
{
|
||||
if(this._child && this._child._hwnd)
|
||||
if (this._hwnd)
|
||||
{
|
||||
var marshal = require('_GenericMarshal');
|
||||
var User32 = marshal.CreateNativeProxy('User32.dll');
|
||||
User32.CreateMethod('PostMessageA');
|
||||
User32.PostMessageA(this._child._hwnd, WM_QUIT, 0, 0);
|
||||
this._user32.PostMessageA(this._hwnd, WM_QUIT, 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
555
agents/modules_meshcore/win-terminal.js
Normal file
555
agents/modules_meshcore/win-terminal.js
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var promise = require('promise');
|
||||
var duplex = require('stream').Duplex;
|
||||
|
||||
var SW_HIDE = 0;
|
||||
var SW_MINIMIZE = 6;
|
||||
var STARTF_USESHOWWINDOW = 0x1;
|
||||
var STD_INPUT_HANDLE = -10;
|
||||
var STD_OUTPUT_HANDLE = -11;
|
||||
var EVENT_CONSOLE_CARET = 0x4001;
|
||||
var EVENT_CONSOLE_END_APPLICATION = 0x4007;
|
||||
var WINEVENT_OUTOFCONTEXT = 0x000;
|
||||
var WINEVENT_SKIPOWNPROCESS = 0x0002;
|
||||
var CREATE_NEW_PROCESS_GROUP = 0x200;
|
||||
var EVENT_CONSOLE_UPDATE_REGION = 0x4002;
|
||||
var EVENT_CONSOLE_UPDATE_SIMPLE = 0x4003;
|
||||
var EVENT_CONSOLE_UPDATE_SCROLL = 0x4004;
|
||||
var EVENT_CONSOLE_LAYOUT = 0x4005;
|
||||
var EVENT_CONSOLE_START_APPLICATION = 0x4006;
|
||||
var KEY_EVENT = 0x1;
|
||||
var MAPVK_VK_TO_VSC = 0;
|
||||
var WM_QUIT = 0x12;
|
||||
|
||||
var GM = require('_GenericMarshal');
|
||||
var si = GM.CreateVariable(GM.PointerSize == 4 ? 68 : 104);
|
||||
var pi = GM.CreateVariable(GM.PointerSize == 4 ? 16 : 24);
|
||||
|
||||
si.Deref(0, 4).toBuffer().writeUInt32LE(GM.PointerSize == 4 ? 68 : 104); // si.cb
|
||||
si.Deref(GM.PointerSize == 4 ? 48 : 64, 2).toBuffer().writeUInt16LE(SW_HIDE | SW_MINIMIZE); // si.wShowWindow
|
||||
si.Deref(GM.PointerSize == 4 ? 44 : 60, 4).toBuffer().writeUInt32LE(STARTF_USESHOWWINDOW); // si.dwFlags;
|
||||
|
||||
var MSG = GM.CreateVariable(GM.PointerSize == 4 ? 28 : 48);
|
||||
|
||||
function windows_terminal()
|
||||
{
|
||||
this._ObjectID = 'windows_terminal';
|
||||
this._user32 = GM.CreateNativeProxy('User32.dll');
|
||||
this._user32.CreateMethod('DispatchMessageA');
|
||||
this._user32.CreateMethod('GetMessageA');
|
||||
this._user32.CreateMethod('MapVirtualKeyA');
|
||||
this._user32.CreateMethod('PostThreadMessageA');
|
||||
this._user32.CreateMethod('SetWinEventHook');
|
||||
this._user32.CreateMethod('ShowWindow');
|
||||
this._user32.CreateMethod('TranslateMessage');
|
||||
this._user32.CreateMethod('UnhookWinEvent');
|
||||
this._user32.CreateMethod('VkKeyScanA');
|
||||
this._user32.terminal = this;
|
||||
|
||||
this._kernel32 = GM.CreateNativeProxy('Kernel32.dll');
|
||||
this._kernel32.CreateMethod('AllocConsole');
|
||||
this._kernel32.CreateMethod('CreateProcessA');
|
||||
this._kernel32.CreateMethod('CloseHandle');
|
||||
this._kernel32.CreateMethod('FillConsoleOutputAttribute');
|
||||
this._kernel32.CreateMethod('FillConsoleOutputCharacterA');
|
||||
this._kernel32.CreateMethod('GetConsoleScreenBufferInfo');
|
||||
this._kernel32.CreateMethod('GetConsoleWindow');
|
||||
this._kernel32.CreateMethod('GetLastError');
|
||||
this._kernel32.CreateMethod('GetStdHandle');
|
||||
this._kernel32.CreateMethod('GetThreadId');
|
||||
this._kernel32.CreateMethod('ReadConsoleOutputA');
|
||||
this._kernel32.CreateMethod('SetConsoleCursorPosition');
|
||||
this._kernel32.CreateMethod('SetConsoleScreenBufferSize');
|
||||
this._kernel32.CreateMethod('SetConsoleWindowInfo');
|
||||
this._kernel32.CreateMethod('TerminateProcess');
|
||||
this._kernel32.CreateMethod('WaitForSingleObject');
|
||||
this._kernel32.CreateMethod('WriteConsoleInputA');
|
||||
|
||||
var currentX = 0;
|
||||
var currentY = 0;
|
||||
|
||||
this._scrx = 0;
|
||||
this._scry = 0;
|
||||
|
||||
this.SendCursorUpdate = function()
|
||||
{
|
||||
var newCsbi = GM.CreateVariable(22);
|
||||
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
|
||||
if (newCsbi.Deref(4,2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6,2).toBuffer().readUInt16LE() != this.currentY)
|
||||
{
|
||||
//wchar_t mywbuf[512];
|
||||
//swprintf(mywbuf, 512, TEXT("csbi.dwCursorPosition.X = %d, csbi.dwCursorPosition.Y = %d, newCsbi.dwCursorPosition.X = %d, newCsbi.dwCursorPosition.Y = %d\r\n"), csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, newCsbi.dwCursorPosition.X, newCsbi.dwCursorPosition.Y);
|
||||
//OutputDebugString(mywbuf);
|
||||
|
||||
//m_viewOffset = newCsbi.srWindow.Top;
|
||||
//WriteMoveCursor((SerialAgent *)this->sa, (char)(newCsbi.dwCursorPosition.Y - m_viewOffset), (char)(newCsbi.dwCursorPosition.X - m_viewOffset));
|
||||
//LowStackSendData((SerialAgent *)(this->sa), "", 0);
|
||||
|
||||
this.currentX = newCsbi.Deref(4,2).toBuffer().readUInt16LE();
|
||||
this.currentY = newCsbi.Deref(6,2).toBuffer().readUInt16LE();
|
||||
}
|
||||
}
|
||||
this.ClearScreen = function()
|
||||
{
|
||||
var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
|
||||
|
||||
var coordScreen = GM.CreateVariable(4);
|
||||
var dwConSize = CONSOLE_SCREEN_BUFFER_INFO.Deref(0,2).toBuffer().readUInt16LE(0) * CONSOLE_SCREEN_BUFFER_INFO.Deref(2,2).toBuffer().readUInt16LE(0);
|
||||
var cCharsWritten = GM.CreateVariable(4);
|
||||
|
||||
// Fill the entire screen with blanks.
|
||||
if (this._kernel32.FillConsoleOutputCharacterA(this._stdoutput, 32, dwConSize, coordScreen.Deref(0,4).toBuffer().readUInt32LE(), cCharsWritten).Val == 0) { return; }
|
||||
|
||||
// Get the current text attribute.
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
|
||||
|
||||
// Set the buffer's attributes accordingly.
|
||||
if (this._kernel32.FillConsoleOutputAttribute(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO.Deref(8, 2).toBuffer().readUInt16LE(0), dwConSize, coordScreen.Deref(0, 4).toBuffer().readUInt32LE(), cCharsWritten).Val == 0) { return; }
|
||||
|
||||
// Put the cursor at its home coordinates.
|
||||
this._kernel32.SetConsoleCursorPosition(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE());
|
||||
|
||||
// Put the window to top-left.
|
||||
var rect = GM.CreateVariable(8);
|
||||
var srWindow = CONSOLE_SCREEN_BUFFER_INFO.Deref(10,8).toBuffer();
|
||||
rect.Deref(4,2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(4) - srWindow.readUInt16LE(0));
|
||||
rect.Deref(6,2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(6) - srWindow.readUInt16LE(2));
|
||||
|
||||
this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect);
|
||||
}
|
||||
|
||||
this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
|
||||
{
|
||||
if(this._kernel32.GetConsoleWindow().Val == 0)
|
||||
{
|
||||
if(this._kernel32.AllocConsole().Val == 0)
|
||||
{
|
||||
throw ('AllocConsole failed with: ' + this._kernel32.GetLastError().Val);
|
||||
}
|
||||
}
|
||||
|
||||
this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE);
|
||||
this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
this._connected = false;
|
||||
var coordScreen = GM.CreateVariable(4);
|
||||
coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH);
|
||||
coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT);
|
||||
|
||||
var rect = GM.CreateVariable(8);
|
||||
rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1);
|
||||
rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1);
|
||||
|
||||
if(this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0)
|
||||
{
|
||||
throw ('Failed to set Console Screen Size');
|
||||
}
|
||||
if(this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0,4).toBuffer().readUInt32LE()).Val == 0)
|
||||
{
|
||||
throw ('Failed to set Console Buffer Size');
|
||||
}
|
||||
this.ClearScreen();
|
||||
this._hookThread().then(function ()
|
||||
{
|
||||
// Hook Ready
|
||||
this.terminal.StartCommand();
|
||||
}, console.log);
|
||||
this._stream = new duplex({
|
||||
'write': function (chunk, flush)
|
||||
{
|
||||
if (!this.terminal.connected)
|
||||
{
|
||||
//console.log('_write: ' + chunk);
|
||||
if (!this._promise.chunk)
|
||||
{
|
||||
this._promise.chunk = [];
|
||||
}
|
||||
if (typeof (chunk) == 'string')
|
||||
{
|
||||
this._promise.chunk.push(chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._promise.chunk.push(Buffer.alloc(chunk.length));
|
||||
chunk.copy(this._promise.chunk.peek());
|
||||
}
|
||||
this._promise.chunk.peek().flush = flush;
|
||||
this._promise.then(function ()
|
||||
{
|
||||
var buf;
|
||||
while(this.chunk.length > 0)
|
||||
{
|
||||
buf = this.chunk.shift();
|
||||
this.terminal._WriteBuffer(buf);
|
||||
buf.flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
//console.log('writeNOW: ' + chunk);
|
||||
this.terminal._WriteBuffer(chunk);
|
||||
flush();
|
||||
}
|
||||
},
|
||||
'final': function (flush)
|
||||
{
|
||||
var p = this.terminal._stop();
|
||||
p.__flush = flush;
|
||||
p.then(function () { this.__flush(); });
|
||||
}
|
||||
});
|
||||
this._stream.terminal = this;
|
||||
this._stream._promise = new promise(function (res, rej) { this._res = res; this._rej = rej; });
|
||||
this._stream._promise.terminal = this;
|
||||
return (this._stream);
|
||||
};
|
||||
this._stop = function()
|
||||
{
|
||||
if (this.stopping) { return (this.stopping); }
|
||||
console.log('Stopping Terminal...');
|
||||
this.stopping = new promise(function (res, rej) { this._res = res; this._rej = rej; });
|
||||
|
||||
var threadID = this._kernel32.GetThreadId(this._user32.SetWinEventHook.async.thread()).Val;
|
||||
this._user32.PostThreadMessageA(threadID, WM_QUIT, 0, 0);
|
||||
return (this.stopping);
|
||||
}
|
||||
|
||||
this._hookThread = function ()
|
||||
{
|
||||
var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
|
||||
ret.terminal = this;
|
||||
this._ConsoleWinEventProc = GM.GetGenericGlobalCallback(7);
|
||||
this._ConsoleWinEventProc.terminal = this;
|
||||
var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
|
||||
p.ready = ret;
|
||||
p.terminal = this;
|
||||
p.then(function (hwinEventHook)
|
||||
{
|
||||
if (hwinEventHook.Val == 0)
|
||||
{
|
||||
this.ready._rej('Error calling SetWinEventHook');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.terminal.hwinEventHook = hwinEventHook;
|
||||
this.ready._res();
|
||||
this.terminal._GetMessage();
|
||||
}
|
||||
});
|
||||
this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime)
|
||||
{
|
||||
if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; }
|
||||
var buffer = null;
|
||||
|
||||
switch (dwEvent.Val)
|
||||
{
|
||||
case EVENT_CONSOLE_CARET:
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_REGION:
|
||||
if (!this.terminal.connected)
|
||||
{
|
||||
this.terminal.connected = true; this.terminal._stream._promise._res();
|
||||
}
|
||||
if (this.terminal._scrollTimer == null)
|
||||
{
|
||||
buffer = this.terminal._GetScreenBuffer(LOWORD(idObject.Val), HIWORD(idObject.Val), LOWORD(idChild.Val), HIWORD(idChild.Val));
|
||||
//console.log('UPDATE REGION: [Left: ' + LOWORD(idObject.Val) + ' Top: ' + HIWORD(idObject.Val) + ' Right: ' + LOWORD(idChild.Val) + ' Bottom: ' + HIWORD(idChild.Val) + ']');
|
||||
|
||||
this.terminal._SendDataBuffer(buffer);
|
||||
}
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_SIMPLE:
|
||||
//console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']');
|
||||
var simplebuffer = { data: [Buffer.alloc(1, LOWORD(idChild.Val))], attributes: [HIWORD(idChild.Val)], width: 1, height: 1, x: LOWORD(idObject.Val)+1, y: HIWORD(idObject.Val) };
|
||||
this.terminal._SendDataBuffer(simplebuffer);
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_SCROLL:
|
||||
//console.log('UPDATE SCROLL: [dx: ' + idObject.Val + ' dy: ' + idChild.Val + ']');
|
||||
this.terminal._SendScroll(idObject.Val, idChild.Val);
|
||||
break;
|
||||
case EVENT_CONSOLE_LAYOUT:
|
||||
//console.log('CONSOLE_LAYOUT');
|
||||
//snprintf( Buf, 512, "Event Console LAYOUT!\r\n");
|
||||
//SendLayout();
|
||||
break;
|
||||
case EVENT_CONSOLE_START_APPLICATION:
|
||||
//console.log('START APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
|
||||
//snprintf( Buf, 512, "Event Console START APPLICATION!\r\nProcess ID: %d - Child ID: %d\r\n\r\n", (int)idObject, (int)idChild);
|
||||
//SendConsoleEvent(dwEvent, idObject, idChild);
|
||||
break;
|
||||
case EVENT_CONSOLE_END_APPLICATION:
|
||||
if(idObject.Val == this.terminal._hProcessID)
|
||||
{
|
||||
//console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
|
||||
this.terminal._stop().then(function () { console.log('STOPPED'); });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//snprintf(Buf, 512, "unknown console event.\r\n");
|
||||
console.log('Unknown event: ' + dwEvent.Val);
|
||||
break;
|
||||
}
|
||||
|
||||
//mbstowcs_s(&l, wBuf, Buf, 512);
|
||||
//OutputDebugString(wBuf);
|
||||
|
||||
});
|
||||
return (ret);
|
||||
}
|
||||
|
||||
this._GetMessage = function()
|
||||
{
|
||||
if (this._user32.abort) { console.log('aborting loop'); return; }
|
||||
this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret)
|
||||
{
|
||||
//console.log('GetMessage Response');
|
||||
if(ret.Val != 0)
|
||||
{
|
||||
if (ret.Val == -1)
|
||||
{
|
||||
// handle the error and possibly exit
|
||||
}
|
||||
else
|
||||
{
|
||||
//console.log('TranslateMessage');
|
||||
this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
|
||||
{
|
||||
//console.log('DispatchMessage');
|
||||
this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
|
||||
{
|
||||
this.nativeProxy.terminal._GetMessage();
|
||||
}, console.log);
|
||||
}, console.log);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nativeProxy.UnhookWinEvent.async(this.nativeProxy.terminal._user32.SetWinEventHook.async, this.nativeProxy.terminal.hwinEventHook)
|
||||
.then(function ()
|
||||
{
|
||||
this.nativeProxy.terminal.stopping._res();
|
||||
if(this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0)
|
||||
{
|
||||
var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
|
||||
console.log('Unable to kill Terminal Process, error: ' + e);
|
||||
}
|
||||
this.nativeProxy.terminal.stopping = null;
|
||||
}, function (err)
|
||||
{
|
||||
console.log('REJECTED_UnhookWinEvent: ' + err);
|
||||
});
|
||||
}
|
||||
}, function (err)
|
||||
{
|
||||
// Get Message Failed
|
||||
console.log('REJECTED_GETMessage: ' + err);
|
||||
});
|
||||
}
|
||||
this._WriteBuffer = function(buf)
|
||||
{
|
||||
for (var i = 0; i < buf.length; ++i)
|
||||
{
|
||||
if (typeof (buf) == 'string')
|
||||
{
|
||||
this._WriteCharacter(buf.charCodeAt(i), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._WriteCharacter(buf[i], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._WriteCharacter = function(key, bControlKey)
|
||||
{
|
||||
var rec = GM.CreateVariable(20);
|
||||
rec.Deref(0,2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
|
||||
rec.Deref(4,4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
|
||||
rec.Deref(16, 4).toBuffer().writeUInt32LE(bControlKey); // rec.Event.KeyEvent.dwControlKeyState
|
||||
rec.Deref(14, 1).toBuffer()[0] = key; // rec.Event.KeyEvent.uChar.AsciiChar
|
||||
rec.Deref(8, 2).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.wRepeatCount
|
||||
rec.Deref(10, 2).toBuffer().writeUInt16LE(this._user32.VkKeyScanA(key).Val); // rec.Event.KeyEvent.wVirtualKeyCode
|
||||
rec.Deref(12, 2).toBuffer().writeUInt16LE(this._user32.MapVirtualKeyA(this._user32.VkKeyScanA(key).Val, MAPVK_VK_TO_VSC).Val);
|
||||
|
||||
var dwWritten = GM.CreateVariable(4);
|
||||
if(this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val == 0) { return(false); }
|
||||
|
||||
rec.Deref(4,4).toBuffer().writeUInt16LE(0); // rec.Event.KeyEvent.bKeyDown
|
||||
return(this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val != 0);
|
||||
}
|
||||
|
||||
this._GetScreenBuffer = function(sx, sy, ex, ey)
|
||||
{
|
||||
// get the current visible screen buffer
|
||||
|
||||
var info = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw('Error getting screen buffer info'); }
|
||||
|
||||
var nWidth = info.Deref(14,2).toBuffer().readUInt16LE() - info.Deref(10,2).toBuffer().readUInt16LE() + 1;
|
||||
var nHeight = info.Deref(16,2).toBuffer().readUInt16LE() - info.Deref(12,2).toBuffer().readUInt16LE() + 1;
|
||||
|
||||
if (arguments[3] == null)
|
||||
{
|
||||
// Use Default Parameters
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
ex = nWidth-1;
|
||||
ey = nHeight-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this._scrx != 0)
|
||||
{
|
||||
sx += this._scrx;
|
||||
ex += this._scrx;
|
||||
}
|
||||
if(this._scry != 0)
|
||||
{
|
||||
sy += this._scry;
|
||||
ey += this._scry;
|
||||
}
|
||||
this._scrx = this._scry = 0;
|
||||
}
|
||||
|
||||
|
||||
var nBuffer = GM.CreateVariable((ex-sx+1) * (ey-sy+1) * 4);
|
||||
var size = GM.CreateVariable(4);
|
||||
size.Deref(0,2).toBuffer().writeUInt16LE(ex-sx+1, 0);
|
||||
size.Deref(2, 2).toBuffer().writeUInt16LE(ey-sy+1, 0);
|
||||
|
||||
var startCoord = GM.CreateVariable(4);
|
||||
startCoord.Deref(0, 2).toBuffer().writeUInt16LE(0, 0);
|
||||
startCoord.Deref(2, 2).toBuffer().writeUInt16LE(0, 0);
|
||||
|
||||
var region = GM.CreateVariable(8);
|
||||
region.buffer = region.toBuffer();
|
||||
region.buffer.writeUInt16LE(sx, 0);
|
||||
region.buffer.writeUInt16LE(sy, 2);
|
||||
region.buffer.writeUInt16LE(ex, 4);
|
||||
region.buffer.writeUInt16LE(ey, 6);
|
||||
|
||||
if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0)
|
||||
{
|
||||
throw('Unable to read Console Output');
|
||||
}
|
||||
|
||||
// Lets convert the buffer into something simpler
|
||||
//var retVal = { data: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), attributes: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), width: dw - dx + 1, height: dh - dy + 1, x: dx, y: dy };
|
||||
|
||||
var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy };
|
||||
var x, y, line, ifo;
|
||||
var tmp;
|
||||
var lineWidth = ex - sx + 1;
|
||||
|
||||
for (y = 0; y <= (ey - sy) ; ++y)
|
||||
{
|
||||
retVal.data.push(Buffer.alloc(lineWidth));
|
||||
retVal.attributes.push(Buffer.alloc(lineWidth));
|
||||
|
||||
line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer();
|
||||
for(x = 0; x < lineWidth; ++x)
|
||||
{
|
||||
retVal.data.peek()[x] = line[x * 4];
|
||||
retVal.attributes.peek()[x] = line[2 + (x * 4)];
|
||||
}
|
||||
}
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
this._SendDataBuffer = function(data)
|
||||
{
|
||||
// { data, attributes, width, height, x, y }
|
||||
|
||||
var dy, line, attr;
|
||||
for(dy = 0; dy < data.height; ++dy)
|
||||
{
|
||||
line = data.data[dy];
|
||||
attr = data.attributes[dy];
|
||||
line.s = line.toString();
|
||||
//line = data.data.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
//attr = data.attributes.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
this._stream.push(TranslateLine(data.x, data.y + dy, line, attr));
|
||||
}
|
||||
}
|
||||
this._SendScroll = function _SendScroll(dx, dy)
|
||||
{
|
||||
if (this._scrollTimer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var info = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
|
||||
|
||||
var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
|
||||
var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
|
||||
|
||||
this._stream.push(GetEsc('H', nHeight-1, 0));
|
||||
for (var i = 0; i > nHeight; ++i)
|
||||
{
|
||||
this._stream.push(Buffer.from('\r\n'));
|
||||
}
|
||||
|
||||
var buffer = this._GetScreenBuffer(0, 0, nWidth - 1, nHeight - 1);
|
||||
this._SendDataBuffer(buffer);
|
||||
|
||||
this._scrollTimer = setTimeout(function (self, nw, nh)
|
||||
{
|
||||
var buffer = self._GetScreenBuffer(0, 0, nw - 1, nh - 1);
|
||||
self._SendDataBuffer(buffer);
|
||||
self._scrollTimer = null;
|
||||
}, 250, this, nWidth, nHeight);
|
||||
}
|
||||
|
||||
this.StartCommand = function StartCommand()
|
||||
{
|
||||
if(this._kernel32.CreateProcessA(GM.CreateVariable(process.env['windir'] + '\\system32\\cmd.exe'), 0, 0, 0, 1, CREATE_NEW_PROCESS_GROUP, 0, 0, si, pi).Val == 0)
|
||||
{
|
||||
console.log('Error Spawning CMD');
|
||||
return;
|
||||
}
|
||||
|
||||
this._kernel32.CloseHandle(pi.Deref(GM.PointerSize, GM.PointerSize).Deref()); // pi.hThread
|
||||
this._hProcess = pi.Deref(0, GM.PointerSize).Deref(); // pi.hProcess
|
||||
this._hProcessID = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE(); // pi.dwProcessId
|
||||
//console.log('Ready => hProcess: ' + this._hProcess._ptr + ' PID: ' + this._hProcessID);
|
||||
}
|
||||
}
|
||||
|
||||
function LOWORD(val)
|
||||
{
|
||||
return (val & 0xFFFF);
|
||||
}
|
||||
function HIWORD(val)
|
||||
{
|
||||
return ((val >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
function GetEsc(CodeCharStr, arg1, arg2)
|
||||
{
|
||||
return (Buffer.from('\x1B[' + arg1 + ';' + arg2 + CodeCharStr));
|
||||
//return (Buffer.from('*[' + arg1 + ';' + arg2 + CodeCharStr));
|
||||
}
|
||||
|
||||
function TranslateLine(x, y, data, attributes)
|
||||
{
|
||||
return (Buffer.concat([GetEsc('H', y, x), data]));
|
||||
}
|
||||
module.exports = new windows_terminal();
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.2.4-g",
|
||||
"version": "0.2.4-h",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
Loading…
Reference in New Issue
Block a user