Added workaround for 32 bit windows agent on 64 bit windows, to inject sysnative when callind readdirSync() on %windir%

Updated documentation for windows terminal.

Bryan Roe committed Oct 14, 2022 at 11:18 UTC 06ec0caec46056513c300366c215f464577d4bec
3 files changed +262 -74
agents/meshcore.js
+21
@@ -47,6 +47,27 @@ var MESHRIGHT_NODESKTOP = 65536;
47
48 var pendingSetClip = false; // This is a temporary hack to prevent multiple setclips at the same time to stop the agent from crashing.
49
50 +function __readdirSync_fix(path)
51 +{
52 + var sysnative = false;
53 + pathstr = require('fs')._fixwinpath(path);
54 + if (pathstr.split('\\*').join('').toLowerCase() == process.env['windir'].toLowerCase()) { sysnative = true; }
55 + var ret = __readdirSync_old(path);
56 + if (sysnative) { ret.push('sysnative'); }
57 + return (ret);
58 +}
59 +
60 +if (process.platform == 'win32' && require('_GenericMarshal').PointerSize == 4 && require('os').arch() == 'x64')
61 +{
62 + if(require('fs').readdirSync.version == null)
63 + {
64 + require('fs').__readdirSync_old = require('fs').readdirSync;
65 + require('fs').readdirSync = __readdirSync_fix;
66 + }
67 +}
68 +
69 +
70 +
71 function bcdOK() {
72 if (process.platform != 'win32') { return (false); }
73 if (require('os').arch() == 'x64') {
agents/modules_meshcore/win-terminal.js
+199 -56
@@ -1,5 +1,5 @@
1 /*
2 -Copyright 2018 Intel Corporation
2 +Copyright 2018-2022 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
@@ -89,21 +89,50 @@ function windows_terminal() {
89 var newCsbi = GM.CreateVariable(22);
90
91 if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
92 - if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY) {
93 - //wchar_t mywbuf[512];
94 - //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);
95 - //OutputDebugString(mywbuf);
96 -
97 - //m_viewOffset = newCsbi.srWindow.Top;
98 - //WriteMoveCursor((SerialAgent *)this->sa, (char)(newCsbi.dwCursorPosition.Y - m_viewOffset), (char)(newCsbi.dwCursorPosition.X - m_viewOffset));
99 - //LowStackSendData((SerialAgent *)(this->sa), "", 0);
100 -
92 + if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY)
93 + {
94 + //
95 + // Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
96 + // https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
97 + //
98 +
99 this.currentX = newCsbi.Deref(4, 2).toBuffer().readUInt16LE();
100 this.currentY = newCsbi.Deref(6, 2).toBuffer().readUInt16LE();
101 }
102 }
103
106 - this.ClearScreen = function () {
104 + this.ClearScreen = function ()
105 + {
106 + //
107 + // Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
108 + // https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
109 + //
110 +
111 + //
112 + // Reference for GetConsoleScreenBufferInfo can be found at:
113 + // https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
114 + //
115 +
116 + //
117 + // Reference for FillConsoleOutputCharacter can be found at:
118 + // https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter
119 + //
120 +
121 + //
122 + // Reference for FillConsoleOutputAttribute can be found at:
123 + // https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputattribute
124 + //
125 +
126 + //
127 + // Reference for SetConsoleCursorPosition can be found at:
128 + // https://learn.microsoft.com/en-us/windows/console/setconsolecursorposition
129 + //
130 +
131 + //
132 + // Reference for SetConsoleWindowInfo can be fount at:
133 + // https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
134 + //
135 +
136 var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
137 if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
138
@@ -132,6 +161,7 @@ function windows_terminal() {
161 this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect);
162 }
163
164 + // This does a rudimentary check if the platform is capable of PowerShell
165 this.PowerShellCapable = function()
166 {
167 if (require('os').arch() == 'x64')
@@ -144,6 +174,7 @@ function windows_terminal() {
174 }
175 }
176
177 + // Starts a Legacy Windows Terminal Session
178 this.StartEx = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT, terminalTarget)
179 {
180 // The older windows terminal does not support
@@ -164,7 +195,9 @@ function windows_terminal() {
195 this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE);
196 this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
197 this._connected = false;
167 - var coordScreen = GM.CreateVariable(4);
198 +
199 + // Coord structure can be found at: https://learn.microsoft.com/en-us/windows/console/coord-str
200 + var coordScreen = GM.CreateVariable(4);
201 coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH);
202 coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT);
203
@@ -172,10 +205,21 @@ function windows_terminal() {
205 rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1);
206 rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1);
207
175 - if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0) {
208 + //
209 + // Reference for SetConsoleWindowInfo can be found at:
210 + // https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
211 + //
212 + if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0)
213 + {
214 throw ('Failed to set Console Screen Size');
215 }
178 - if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0) {
216 +
217 + //
218 + // Reference for SetConsoleScreenBufferSize can be found at:
219 + // https://learn.microsoft.com/en-us/windows/console/setconsolescreenbuffersize
220 + //
221 + if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0)
222 + {
223 throw ('Failed to set Console Buffer Size');
224 }
225
@@ -278,8 +322,16 @@ function windows_terminal() {
322 return (this.stopping);
323 }
324
325 + //
326 + // This function uses the SetWinEventHook() method, so we can hook
327 + // All events between EVENT_CONSOLE_CARET and EVENT_CONSOLE_END_APPLICATION
328 + //
329 this._hookThread = function ()
330 {
331 + //
332 + // Reference for SetWinEventHook() can be found at:
333 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook
334 + //
335 var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
336 ret.userArgs = [];
337 for (var a in arguments)
@@ -292,24 +344,43 @@ function windows_terminal() {
344 var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
345 p.ready = ret;
346 p.terminal = this;
295 - p.then(function (hwinEventHook) {
296 - if (hwinEventHook.Val == 0) {
347 + p.then(function (hwinEventHook)
348 + {
349 + if (hwinEventHook.Val == 0)
350 + {
351 this.ready._rej('Error calling SetWinEventHook');
298 - } else {
352 + } else
353 + {
354 this.terminal.hwinEventHook = hwinEventHook;
355 this.ready._res();
356 this.terminal._GetMessage();
357 }
358 });
359
305 - this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime) {
360 + //
361 + // This is the WINEVENTPROC callback for the WinEventHook we set
362 + //
363 + this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime)
364 + {
365 + //
366 + // Reference for WINEVENTPROC can be found at:
367 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wineventproc
368 + //
369 if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; }
370 var buffer = null;
371
309 - switch (dwEvent.Val) {
372 + //
373 + // Reference for Console WinEvents can be found at:
374 + // https://learn.microsoft.com/en-us/windows/console/console-winevents
375 + //
376 +
377 + switch (dwEvent.Val)
378 + {
379 case EVENT_CONSOLE_CARET:
380 + // The console caret has moved
381 break;
382 case EVENT_CONSOLE_UPDATE_REGION:
383 + // More than one character has changed
384 if (!this.terminal.connected) {
385 this.terminal.connected = true;
386 this.terminal._stream._promise._res();
@@ -321,25 +392,30 @@ function windows_terminal() {
392 }
393 break;
394 case EVENT_CONSOLE_UPDATE_SIMPLE:
395 + // A single character has changed
396 //console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']');
397 var simplebuffer = { data: [ Buffer.alloc(1, LOWORD(idChild.Val)) ], attributes: [ HIWORD(idChild.Val) ], width: 1, height: 1, x: LOWORD(idObject.Val), y: HIWORD(idObject.Val) };
398 this.terminal._SendDataBuffer(simplebuffer);
399 break;
400 case EVENT_CONSOLE_UPDATE_SCROLL:
401 + // The console has scrolled
402 //console.log('UPDATE SCROLL: [dx: ' + idObject.Val + ' dy: ' + idChild.Val + ']');
403 this.terminal._SendScroll(idObject.Val, idChild.Val);
404 break;
405 case EVENT_CONSOLE_LAYOUT:
406 + // The console layout has changed.
407 //console.log('CONSOLE_LAYOUT');
408 //snprintf( Buf, 512, "Event Console LAYOUT!\r\n");
409 //SendLayout();
410 break;
411 case EVENT_CONSOLE_START_APPLICATION:
412 + // A new console process has started
413 //console.log('START APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
414 //snprintf( Buf, 512, "Event Console START APPLICATION!\r\nProcess ID: %d - Child ID: %d\r\n\r\n", (int)idObject, (int)idChild);
415 //SendConsoleEvent(dwEvent, idObject, idChild);
416 break;
417 case EVENT_CONSOLE_END_APPLICATION:
418 + // A console process has exited
419 if (idObject.Val == this.terminal._hProcessID)
420 {
421 //console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
@@ -360,18 +436,44 @@ function windows_terminal() {
436 return (ret);
437 }
438
363 - this._GetMessage = function () {
439 + // Retrieves a message from the calling thread's message queue
440 + this._GetMessage = function ()
441 + {
442 + //
443 + // Reference for GetMessage() can be found at:
444 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
445 + //
446 +
447 + //
448 + // Reference for TranslateMessage() can be found at:
449 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-translatemessage
450 + //
451 +
452 + //
453 + // Reference for DispatchMessage() can be found at:
454 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dispatchmessage
455 + //
456 +
457 if (this._user32.abort) { console.log('aborting loop'); return; }
365 - this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret) {
458 + this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret)
459 + {
460 //console.log('GetMessage Response');
367 - if (ret.Val != 0) {
368 - if (ret.Val == -1) {
461 + if (ret.Val != 0)
462 + {
463 + if (ret.Val == -1)
464 + {
465 // handle the error and possibly exit
370 - } else {
466 + }
467 + else
468 + {
469 + // Translates virtual-key messages into character messages
470 //console.log('TranslateMessage');
372 - this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
471 + this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
472 + {
473 + // Dispatches a message to a window procedure
474 //console.log('DispatchMessage');
374 - this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
475 + this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
476 + {
477 this.nativeProxy.terminal._GetMessage();
478 }, console.log);
479 }, console.log);
@@ -384,7 +486,8 @@ function windows_terminal() {
486 if (this.nativeProxy.terminal._hProcess == null) { return; }
487
488 this.nativeProxy.terminal.stopping._res();
387 - if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0) {
489 + if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0)
490 + {
491 var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
492 console.log('Unable to kill Terminal Process, error: ' + e);
493 }
@@ -394,22 +497,38 @@ function windows_terminal() {
497 console.log('REJECTED_UnhookWinEvent: ' + err);
498 });
499 }
397 - }, function (err) {
500 + }, function (err)
501 + {
502 // Get Message Failed
503 console.log('REJECTED_GETMessage: ' + err);
504 });
505 }
402 - this._WriteBuffer = function (buf) {
403 - for (var i = 0; i < buf.length; ++i) {
404 - if (typeof (buf) == 'string') {
506 +
507 + this._WriteBuffer = function (buf)
508 + {
509 + for (var i = 0; i < buf.length; ++i)
510 + {
511 + if (typeof (buf) == 'string')
512 + {
513 this._WriteCharacter(buf.charCodeAt(i), false);
406 - } else {
514 + } else
515 + {
516 this._WriteCharacter(buf[i], false);
517 }
518 }
519 }
520 this._WriteCharacter = function (key, bControlKey)
521 {
522 + //
523 + // Reference for WriteConsoleInput() can be found at:
524 + // https://learn.microsoft.com/en-us/windows/console/writeconsoleinput
525 + //
526 +
527 + //
528 + // Reference for INPUT_RECORD can be found at:
529 + // https://learn.microsoft.com/en-us/windows/console/input-record-str
530 + //
531 +
532 var rec = GM.CreateVariable(20);
533 rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
534 rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
@@ -427,62 +546,78 @@ function windows_terminal() {
546 }
547
548 // Get the current visible screen buffer
430 - this._GetScreenBuffer = function (sx, sy, ex, ey) {
549 + this._GetScreenBuffer = function (sx, sy, ex, ey)
550 + {
551 + //
552 + // Reference for GetConsoleScreenBufferInfo() can be found at:
553 + // https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
554 + //
555 +
556 + //
557 + // Reference for ReadConsoleOutput() can be found at:
558 + // https://learn.microsoft.com/en-us/windows/console/readconsoleoutput
559 + //
560 +
561 var info = GM.CreateVariable(22);
562 if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
433 -
563 +
564 var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
565 var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
436 -
437 - if (arguments[3] == null) {
566 +
567 + if (arguments[3] == null)
568 + {
569 // Use Default Parameters
570 sx = 0;
571 sy = 0;
572 ex = nWidth - 1;
573 ey = nHeight - 1;
443 - } else {
574 + } else
575 + {
576 if (this._scrx != 0) { sx += this._scrx; ex += this._scrx; }
577 if (this._scry != 0) { sy += this._scry; ey += this._scry; }
578 this._scrx = this._scry = 0;
579 }
448 -
580 +
581 var nBuffer = GM.CreateVariable((ex - sx + 1) * (ey - sy + 1) * 4);
582 var size = GM.CreateVariable(4);
583 size.Deref(0, 2).toBuffer().writeUInt16LE(ex - sx + 1, 0);
584 size.Deref(2, 2).toBuffer().writeUInt16LE(ey - sy + 1, 0);
453 -
585 +
586 var startCoord = GM.CreateVariable(4);
587 startCoord.Deref(0, 2).toBuffer().writeUInt16LE(0, 0);
588 startCoord.Deref(2, 2).toBuffer().writeUInt16LE(0, 0);
457 -
589 +
590 var region = GM.CreateVariable(8);
591 region.buffer = region.toBuffer();
592 region.buffer.writeUInt16LE(sx, 0);
593 region.buffer.writeUInt16LE(sy, 2);
594 region.buffer.writeUInt16LE(ex, 4);
595 region.buffer.writeUInt16LE(ey, 6);
464 -
465 - if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0) {
596 +
597 + if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0)
598 + {
599 throw ('Unable to read Console Output');
600 }
468 -
601 +
602 // Lets convert the buffer into something simpler
603 //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 };
471 -
604 +
605 var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy };
606 var x, y, line, ifo, tmp, lineWidth = ex - sx + 1;
474 -
475 - for (y = 0; y <= (ey - sy) ; ++y) {
607 +
608 + for (y = 0; y <= (ey - sy) ; ++y)
609 + {
610 retVal.data.push(Buffer.alloc(lineWidth));
611 retVal.attributes.push(Buffer.alloc(lineWidth));
478 -
612 +
613 line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer();
480 - for (x = 0; x < lineWidth; ++x) {
614 + for (x = 0; x < lineWidth; ++x)
615 + {
616 retVal.data.peek()[x] = line[x * 4];
617 retVal.attributes.peek()[x] = line[2 + (x * 4)];
618 }
619 }
485 -
620 +
621 return (retVal);
622 }
623
@@ -507,6 +642,11 @@ function windows_terminal() {
642
643 this._SendScroll = function _SendScroll(dx, dy)
644 {
645 + //
646 + // Reference for GetConsoleScreenBufferInfo() can be found at:
647 + // https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
648 + //
649 +
650 if (this._scrollTimer || this._stream == null) { return; }
651
652 var info = GM.CreateVariable(22);
@@ -546,12 +686,15 @@ function LOWORD(val) { return (val & 0xFFFF); }
686 function HIWORD(val) { return ((val >> 16) & 0xFFFF); }
687 function GetEsc(op, args) { return (Buffer.from('\x1B[' + args.join(';') + op)); }
688 function MeshConsole(msg) { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": JSON.stringify(msg) }); }
549 -function TranslateLine(x, y, data, attributes) {
689 +function TranslateLine(x, y, data, attributes)
690 +{
691 var i, fcolor, bcolor, rcolor, fbright, bbright, lastAttr, fc, bc, rc, fb, bb, esc = [], output = [GetEsc('H', [y, x])];
551 - if (typeof attributes == 'number') { attributes = [ attributes ]; } // If we get a single attribute, turn it into an array.
692 + if (typeof attributes == 'number') { attributes = [attributes]; } // If we get a single attribute, turn it into an array.
693
553 - for (i = 0; i < data.length; i++) {
554 - if (lastAttr != attributes[i]) { // To boost performance, if the attribute is the same as the last one, skip this entire part.
694 + for (i = 0; i < data.length; i++)
695 + {
696 + if (lastAttr != attributes[i])
697 + { // To boost performance, if the attribute is the same as the last one, skip this entire part.
698 fc = (attributes[i] & 0x0007);
699 fc = ((fc & 0x0001) << 2) + (fc & 0x0002) + ((fc & 0x0004) >> 2); // Foreground color
700 bc = (attributes[i] & 0x0070) >> 4;
@@ -559,19 +702,19 @@ function TranslateLine(x, y, data, attributes) {
702 rc = (attributes[i] & 0x4000); // Reverse color set
703 fb = (attributes[i] & 0x0008) >> 3; // Bright foreground set
704 bb = (attributes[i] & 0x0080); // Bright background set
562 -
705 +
706 if (rc != rcolor) { if (rc != 0) { esc.push(7); } else { esc.push(0); fcolor = 7; bcolor = 0; fbright = 0; bbright = 0; } rcolor = rc; } // Reverse Color
707 if (fc != fcolor) { esc.push(fc + 30); fcolor = fc; } // Set the foreground color if needed
708 if (bc != bcolor) { esc.push(bc + 40); bcolor = bc; } // Set the background color if needed
709 if (fb != fbright) { esc.push(2 - fb); fbright = fb; } // Set the bright foreground color if needed
567 - if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
710 + if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
711
712 if (esc.length > 0) { output.push(GetEsc('m', esc)); esc = []; }
713 lastAttr = attributes[i];
714 }
715 output.push(Buffer.from(String.fromCharCode(data[i])));
716 }
574 -
717 +
718 return Buffer.concat(output);
719 }
720
agents/modules_meshcore/win-virtual-terminal.js
+42 -18
@@ -47,20 +47,20 @@ function vt()
47
48 var GM = require('_GenericMarshal');
49 var k32 = GM.CreateNativeProxy('kernel32.dll');
50 - k32.CreateMethod('CancelIoEx');
51 - k32.CreateMethod('CreatePipe');
52 - k32.CreateMethod('CreateProcessW');
53 - k32.CreateMethod('CreatePseudoConsole');
54 - k32.CreateMethod('CloseHandle');
55 - k32.CreateMethod('ClosePseudoConsole');
56 - k32.CreateMethod('GetProcessHeap');
57 - k32.CreateMethod('HeapAlloc');
58 - k32.CreateMethod('InitializeProcThreadAttributeList');
59 - k32.CreateMethod('ResizePseudoConsole');
60 - k32.CreateMethod('UpdateProcThreadAttribute');
61 - k32.CreateMethod('WriteFile');
62 - k32.CreateMethod('ReadFile');
63 - k32.CreateMethod('TerminateProcess');
50 + k32.CreateMethod('CancelIoEx'); // https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func
51 + k32.CreateMethod('CreatePipe'); // https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
52 + k32.CreateMethod('CreateProcessW'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
53 + k32.CreateMethod('CreatePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/createpseudoconsole
54 + k32.CreateMethod('CloseHandle'); // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
55 + k32.CreateMethod('ClosePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/closepseudoconsole
56 + k32.CreateMethod('GetProcessHeap'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap
57 + k32.CreateMethod('HeapAlloc'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc
58 + k32.CreateMethod('InitializeProcThreadAttributeList'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist
59 + k32.CreateMethod('ResizePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/resizepseudoconsole
60 + k32.CreateMethod('UpdateProcThreadAttribute'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
61 + k32.CreateMethod('WriteFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile
62 + k32.CreateMethod('ReadFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
63 + k32.CreateMethod('TerminateProcess'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
64
65 var ret = { _h: GM.CreatePointer(), _consoleInput: GM.CreatePointer(), _consoleOutput: GM.CreatePointer(), _input: GM.CreatePointer(), _output: GM.CreatePointer(), k32: k32 };
66 var attrSize = GM.CreateVariable(8);
@@ -77,18 +77,31 @@ function vt()
77 throw ('Error calling CreatePseudoConsole()');
78 }
79
80 + //
81 + // Reference for STARTUPINFOEXW
82 + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexw
83 + //
84 +
85 + //
86 + // Reference for STARTUPINFOW
87 + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
88 + //
89 +
90 k32.InitializeProcThreadAttributeList(0, 1, 0, attrSize);
91 attrList = GM.CreateVariable(attrSize.toBuffer().readUInt32LE());
82 - var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72);
83 - startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0);
84 - attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer());
92 + var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); // Create Structure, 64 bits is 112 bytes, 32 bits is 72 bytes
93 + startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); // Write buffer size
94 + attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); // Write the reference to STARTUPINFOEX
95
96 if (k32.InitializeProcThreadAttributeList(attrList, 1, 0, attrSize).Val != 0)
97 {
98 if (k32.UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, ret._h.Deref(), GM.PointerSize, 0, 0).Val != 0)
99 {
90 - if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0)
100 + if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) // Create the process to run in the pseudoconsole
101 {
102 + //
103 + // Create a Stream Object, to be able to read/write data to the pseudoconsole
104 + //
105 ret._startupinfoex = startupinfoex;
106 ret._process = pi.Deref(0);
107 ret._pid = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE();
@@ -111,6 +124,10 @@ function vt()
124 flush();
125 }
126 });
127 +
128 + //
129 + // The ProcessInfo object is signaled when the process exits
130 + //
131 ds._obj = ret;
132 ret._waiter = require('DescriptorEvents').addDescriptor(pi.Deref(0));
133 ret._waiter.ds = ds;
@@ -151,6 +168,7 @@ function vt()
168 ds._rpbufRead = GM.CreateVariable(4);
169 ds.__read = function __read()
170 {
171 + // Asyncronously read data from the pseudoconsole
172 this._rp = this.terminal.k32.ReadFile.async(this.terminal._output.Deref(), this._rpbuf, this._rpbuf._size, this._rpbufRead, 0);
173 this._rp.then(function ()
174 {
@@ -173,6 +191,8 @@ function vt()
191 }
192 throw ('Internal Error');
193 }
194 +
195 + // This evaluates whether or not the powershell binary exists
196 this.PowerShellCapable = function ()
197 {
198 if (require('os').arch() == 'x64')
@@ -184,10 +204,14 @@ function vt()
204 return (require('fs').existsSync(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'));
205 }
206 }
207 +
208 + // Start the PseudoConsole with the Command Prompt
209 this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
210 {
211 return (this.Create(process.env['windir'] + '\\System32\\cmd.exe', CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT));
212 }
213 +
214 + // Start the PseduoConsole with PowerShell
215 this.StartPowerShell = function StartPowerShell(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
216 {
217 if (require('os').arch() == 'x64')