Checkpoint Console work.

- Add a very incomplete "telnet" server.  It doesn't recognize any telnet
   commands, so it's "telnet" only in the sense that I can connect to the
   server and type commands.  The commands are fed to a Win32 Console, but
   I don't get to see the output over the network.

 - Move AgentClient to the Shared directory and move QtEvent-specific code
   out of it.

 - Move the startShell routine into the AgentClient so I can share it
   between the different console-consuming prototypes.
This commit is contained in:
Ryan Prichard 2011-11-24 03:03:05 -08:00
parent 22b4de90b8
commit 6021840a1f
16 changed files with 325 additions and 105 deletions

2
.gitignore vendored
View File

@ -1,5 +1,6 @@
CMakeCache.txt
CMakeLists.txt.user
CMakeLists.txt.user.2.3pre1
CMakeFiles
Makefile
*.exe
@ -7,4 +8,5 @@ build.sh
Scrape.cbp
cmake_install.cmake
*.pro.user
*.pro.user.2.3pre1
*-build-desktop

View File

@ -35,7 +35,7 @@ Agent::Agent(const QString &socketServer, QObject *parent) : QObject(parent)
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
connect(m_timer, SIGNAL(timeout()), SLOT(pollTimeout()));
m_timer->start(100);
m_timer->start(500);
Trace("agent starting...");
}
@ -44,7 +44,6 @@ void Agent::socketReadyRead()
{
// TODO: This is an incomplete hack...
while (m_socket->bytesAvailable() >= sizeof(INPUT_RECORD)) {
Trace("reading a word...");
INPUT_RECORD ir;
m_socket->read((char*)&ir, sizeof(ir));
DWORD dummy;
@ -60,5 +59,6 @@ void Agent::socketClosed()
void Agent::pollTimeout()
{
//Trace("poll");
// TODO: ... scan the console and write it to the socket.
}

View File

@ -11,12 +11,12 @@ TEMPLATE = app
SOURCES += main.cc \
ConsoleWindow.cc \
AgentClient.cc \
ConsoleWindow.cc \
../Shared/AgentClient.cc \
TextWidget.cc
HEADERS += ConsoleWindow.h \
AgentClient.h \
../Shared/AgentClient.h \
TextWidget.h
FORMS += ConsoleWindow.ui

View File

@ -1,13 +1,10 @@
#include "ConsoleWindow.h"
#include "ui_ConsoleWindow.h"
#include "AgentClient.h"
#include "../Shared/AgentClient.h"
#include <QProcess>
#include <QtDebug>
#include <stdio.h>
#define WINVER 0x501
#include <windows.h>
ConsoleWindow::ConsoleWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ConsoleWindow)
@ -15,96 +12,10 @@ ConsoleWindow::ConsoleWindow(QWidget *parent) :
ui->setupUi(this);
m_agentClient = new AgentClient(this);
ui->widget->initWithAgent(m_agentClient);
startShell();
m_agentClient->startShell();
}
ConsoleWindow::~ConsoleWindow()
{
delete ui;
}
void ConsoleWindow::startShell()
{
AttachConsole(m_agentClient->agentPid());
HANDLE conout1, conout2, conin;
{
// TODO: Should the permissions be more restrictive?
// TODO: Is this code necessary or even desirable? If I
// don't change these handles, then are the old values
// invalid? If so, what happens if I create a console
// subprocess?
// The handle must be inheritable. See comment below.
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
conout1 = CreateFile(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
conout2 = CreateFile(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
conin = CreateFile(L"CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
Q_ASSERT(conin != NULL);
Q_ASSERT(conout1 != NULL);
Q_ASSERT(conout2 != NULL);
/*
BOOL success;
success = SetStdHandle(STD_OUTPUT_HANDLE, conout1);
Q_ASSERT(success);
success = SetStdHandle(STD_ERROR_HANDLE, conout2);
Q_ASSERT(success);
success = SetStdHandle(STD_INPUT_HANDLE, conin);
Q_ASSERT(success);
*/
}
{
wchar_t program[80] = L"c:\\windows\\system32\\cmd.exe";
wchar_t cmdline[80];
wcscpy(cmdline, program);
STARTUPINFO sui;
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
sui.dwFlags = STARTF_USESTDHANDLES;
sui.hStdInput = conin;
sui.hStdOutput = conout1;
sui.hStdError = conout2;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
BOOL success = CreateProcess(
program,
cmdline,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&sui,
&pi);
if (!success) {
qDebug("Could not start shell");
}
}
CloseHandle(conout1);
CloseHandle(conout2);
CloseHandle(conin);
FreeConsole();
}

View File

@ -17,9 +17,6 @@ public:
explicit ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
private:
void startShell();
private:
Ui::ConsoleWindow *ui;
AgentClient *m_agentClient;

View File

@ -1,7 +1,8 @@
#include "TextWidget.h"
#include "AgentClient.h"
#include "../Shared/AgentClient.h"
#include <QKeyEvent>
#include <QtDebug>
#include <windows.h>
TextWidget::TextWidget(QWidget *parent) :
QWidget(parent),
@ -16,10 +17,25 @@ void TextWidget::initWithAgent(AgentClient *agentClient)
void TextWidget::keyPressEvent(QKeyEvent *event)
{
m_agentClient->sendKeyPress(event);
// TODO: Flesh this out.... Also: this code is intended
// to be portable across operating systems, so using
// nativeVirtualKey is wrong.
if (event->nativeVirtualKey() != 0) {
INPUT_RECORD ir;
memset(&ir, 0, sizeof(ir));
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = TRUE;
ir.Event.KeyEvent.wVirtualKeyCode = event->nativeVirtualKey();
qDebug() << ir.Event.KeyEvent.wVirtualKeyCode;
ir.Event.KeyEvent.wVirtualScanCode = 0; // event->nativeScanCode();
ir.Event.KeyEvent.uChar.UnicodeChar =
event->text().isEmpty() ? L'\0' : event->text().at(0).unicode();
ir.Event.KeyEvent.wRepeatCount = event->count();
m_agentClient->writeInputRecord(&ir);
}
}
void TextWidget::keyReleaseEvent(QKeyEvent *event)
{
m_agentClient->sendKeyRelease(event);
//m_agentClient->sendKeyRelease(event);
}

View File

@ -1,3 +1,4 @@
#define WINVER 0x501
#include "AgentClient.h"
#include <QLocalServer>
#include <QLocalSocket>
@ -54,6 +55,7 @@ AgentClient::AgentClient(QObject *parent) :
Q_ASSERT(m_socket != NULL);
}
/*
void AgentClient::sendKeyPress(QKeyEvent *event)
{
// TODO: Flesh this out.... Also: this code is intended
@ -77,8 +79,100 @@ void AgentClient::sendKeyRelease(QKeyEvent *event)
{
}
*/
void AgentClient::writeInputRecord(INPUT_RECORD *ir)
{
m_socket->write((char*)ir, sizeof(*ir));
}
int AgentClient::agentPid()
{
return m_agentProcess->dwProcessId;
}
void AgentClient::startShell()
{
FreeConsole();
AttachConsole(agentPid());
HANDLE conout1, conout2, conin;
{
// TODO: Should the permissions be more restrictive?
// TODO: Is this code necessary or even desirable? If I
// don't change these handles, then are the old values
// invalid? If so, what happens if I create a console
// subprocess?
// The handle must be inheritable. See comment below.
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
conout1 = CreateFile(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
conout2 = CreateFile(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
conin = CreateFile(L"CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0, NULL);
Q_ASSERT(conin != NULL);
Q_ASSERT(conout1 != NULL);
Q_ASSERT(conout2 != NULL);
/*
BOOL success;
success = SetStdHandle(STD_OUTPUT_HANDLE, conout1);
Q_ASSERT(success);
success = SetStdHandle(STD_ERROR_HANDLE, conout2);
Q_ASSERT(success);
success = SetStdHandle(STD_INPUT_HANDLE, conin);
Q_ASSERT(success);
*/
}
{
wchar_t program[80] = L"c:\\windows\\system32\\cmd.exe";
wchar_t cmdline[80];
wcscpy(cmdline, program);
STARTUPINFO sui;
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
sui.dwFlags = STARTF_USESTDHANDLES;
sui.hStdInput = conin;
sui.hStdOutput = conout1;
sui.hStdError = conout2;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
BOOL success = CreateProcess(
program,
cmdline,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&sui,
&pi);
if (!success) {
qDebug("Could not start shell");
}
}
CloseHandle(conout1);
CloseHandle(conout2);
CloseHandle(conin);
FreeConsole();
}

View File

@ -2,20 +2,23 @@
#define AGENTCLIENT_H
#include <QObject>
#include <QKeyEvent>
//#include <QKeyEvent>
class QLocalServer;
class QLocalSocket;
typedef struct _PROCESS_INFORMATION PROCESS_INFORMATION;
typedef struct _INPUT_RECORD INPUT_RECORD;
class AgentClient : public QObject
{
Q_OBJECT
public:
explicit AgentClient(QObject *parent = 0);
void sendKeyPress(QKeyEvent *event);
void sendKeyRelease(QKeyEvent *event);
//void sendKeyPress(QKeyEvent *event);
//void sendKeyRelease(QKeyEvent *event);
int agentPid();
void writeInputRecord(INPUT_RECORD *ir);
void startShell();
signals:

View File

@ -0,0 +1,18 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-11-04T23:26:52
#
#-------------------------------------------------
QT += core
QT -= gui
TARGET = ShowConsoleInput
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cc

31
ShowConsoleInput/main.cc Normal file
View File

@ -0,0 +1,31 @@
#include <QtCore/QCoreApplication>
#include <windows.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
while (true) {
DWORD count;
INPUT_RECORD ir;
if (!ReadConsoleInput(hStdin, &ir, 1, &count)) {
printf("ReadConsoleInput failed\n");
return 1;
}
if (ir.EventType == KEY_EVENT) {
const KEY_EVENT_RECORD &ker = ir.Event.KeyEvent;
printf("%s", ker.bKeyDown ? "dn" : "up");
printf(" ch=");
if (isprint(ker.uChar.AsciiChar))
printf("'%c'", ker.uChar.AsciiChar);
printf("%d", ker.uChar.AsciiChar);
printf(" ctrl=%d", (int)ker.dwControlKeyState);
printf(" vk=%d", ker.wVirtualKeyCode);
printf(" scan=%d", ker.wVirtualScanCode);
printf(" repeat=%d", ker.wRepeatCount);
printf("\n");
}
}
}

19
TelnetServer/Server.cc Normal file
View File

@ -0,0 +1,19 @@
#include "Server.h"
#include "Session.h"
#include <QTcpServer>
#include <QTcpSocket>
Server::Server(QObject *parent) :
QObject(parent)
{
m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, SIGNAL(newConnection()), SLOT(newConnection()));
bool ret = m_tcpServer->listen(QHostAddress::Any, 23);
Q_ASSERT(ret);
}
void Server::newConnection()
{
QTcpSocket *socket = m_tcpServer->nextPendingConnection();
new Session(socket, this);
}

25
TelnetServer/Server.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef TELNETSERVER_H
#define TELNETSERVER_H
#include <QObject>
class QTcpServer;
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
signals:
private slots:
void newConnection();
public slots:
private:
QTcpServer *m_tcpServer;
};
#endif // TELNETSERVER_H

40
TelnetServer/Session.cc Normal file
View File

@ -0,0 +1,40 @@
#include "Session.h"
#include <QTcpSocket>
#include <QtDebug>
#include "../Shared/AgentClient.h"
#include "../Shared/DebugClient.h"
#include <windows.h>
Session::Session(QTcpSocket *socket, QObject *parent) :
QObject(parent), m_socket(socket)
{
m_agentClient = new AgentClient(this);
connect(m_socket, SIGNAL(readyRead()), SLOT(onSocketReadyRead()));
m_agentClient->startShell();
}
void Session::onSocketReadyRead()
{
QByteArray data = m_socket->readAll();
Trace("session: read %d bytes", data.length());
for (int i = 0; i < data.size(); ++i) {
Trace("input: %02x", (unsigned char)data[i]);
short vk = VkKeyScan((unsigned char)data[i]);
if (vk != -1) {
INPUT_RECORD ir;
memset(&ir, 0, sizeof(ir));
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = TRUE;
ir.Event.KeyEvent.wVirtualKeyCode = vk & 0xff;
ir.Event.KeyEvent.wVirtualScanCode = 0;
ir.Event.KeyEvent.uChar.AsciiChar = data[i];
ir.Event.KeyEvent.wRepeatCount = 1;
m_agentClient->writeInputRecord(&ir);
}
}
Trace("session: completed read", data.length());
}

27
TelnetServer/Session.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef SESSION_H
#define SESSION_H
#include <QObject>
class QTcpSocket;
class AgentClient;
class Session : public QObject
{
Q_OBJECT
public:
explicit Session(QTcpSocket *socket, QObject *parent = 0);
signals:
public slots:
private slots:
void onSocketReadyRead();
private:
QTcpSocket *m_socket;
AgentClient *m_agentClient;
};
#endif // SESSION_H

View File

@ -0,0 +1,28 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-11-03T01:45:58
#
#-------------------------------------------------
QT += core
QT -= gui
QT += network
TARGET = TelnetServer
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cc \
../Shared/AgentClient.cc \
../Shared/DebugClient.cc \
Session.cc \
Server.cc
HEADERS += \
../Shared/AgentClient.h \
../Shared/DebugClient.h \
Session.h \
Server.h

9
TelnetServer/main.cc Normal file
View File

@ -0,0 +1,9 @@
#include <QtCore/QCoreApplication>
#include "Server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server;
return a.exec();
}