mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Improved Windows Terminal
This commit is contained in:
parent
c65f417e9b
commit
d31b3336bd
17 changed files with 2733 additions and 302 deletions
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…
Add table
Reference in a new issue