|
|
|
#include "server.h"
|
|
|
|
|
|
|
|
#define BUFSIZE 4096
|
|
|
|
#define DEFAULT_BUFLEN 512
|
|
|
|
|
|
|
|
typedef struct PipeThreadInfo_t {
|
|
|
|
HANDLE Pipe;
|
|
|
|
SOCKET ClientSocket;
|
|
|
|
} PipeThreadInfo;
|
|
|
|
|
|
|
|
HANDLE CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr);
|
|
|
|
DWORD WINAPI WorkWithClient(LPVOID lpParam);
|
|
|
|
DWORD WINAPI WriteToPipe(LPVOID lpParam);
|
|
|
|
DWORD WINAPI ReadFromPipe(LPVOID lpParam);
|
|
|
|
|
|
|
|
void StartShellServer() {
|
|
|
|
printf("\n->Start of shell server execution.\n");
|
|
|
|
|
|
|
|
WSADATA wsaData;
|
|
|
|
struct addrinfo* result = NULL, * ptr = NULL, hints;
|
|
|
|
int iResult;
|
|
|
|
|
|
|
|
SOCKET ClientSocket = INVALID_SOCKET;
|
|
|
|
SOCKET ListenSocket = INVALID_SOCKET;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize listening socket
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Initialize Winsock
|
|
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (iResult != 0) {
|
|
|
|
printf("WSAStartup failed: %d\n", iResult);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creating socket
|
|
|
|
ZeroMemory(&hints, sizeof(hints));
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
|
|
|
|
// Resolve the local address and port to be used by the server
|
|
|
|
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
|
|
|
|
if (iResult != 0) {
|
|
|
|
printf("getaddrinfo failed: %d\n", iResult);
|
|
|
|
WSACleanup();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
|
|
|
|
|
|
|
if (ListenSocket == INVALID_SOCKET) {
|
|
|
|
printf("Error at socket(): %ld\n", WSAGetLastError());
|
|
|
|
freeaddrinfo(result);
|
|
|
|
WSACleanup();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Binding socket
|
|
|
|
// Setup the TCP listening socket
|
|
|
|
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
|
|
|
|
if (iResult == SOCKET_ERROR) {
|
|
|
|
printf("bind failed with error: %d\n", WSAGetLastError());
|
|
|
|
freeaddrinfo(result);
|
|
|
|
closesocket(ListenSocket);
|
|
|
|
WSACleanup();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// No longer needed
|
|
|
|
freeaddrinfo(result);
|
|
|
|
|
|
|
|
// Listening socket
|
|
|
|
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
|
|
|
|
printf("Listen failed with error: %ld\n", WSAGetLastError());
|
|
|
|
closesocket(ListenSocket);
|
|
|
|
WSACleanup();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process client connection
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
// Accepting a client connection
|
|
|
|
ClientSocket = INVALID_SOCKET;
|
|
|
|
|
|
|
|
ClientSocket = accept(ListenSocket, NULL, NULL);
|
|
|
|
if (ClientSocket == INVALID_SOCKET) {
|
|
|
|
printf("accept failed: %d\n", WSAGetLastError());
|
|
|
|
//break;
|
|
|
|
}
|
|
|
|
printf("Client connected\n");
|
|
|
|
// Create separate thread to process client connection
|
|
|
|
CreateThread(NULL, 0, WorkWithClient, ClientSocket, 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finalization
|
|
|
|
*/
|
|
|
|
closesocket(ListenSocket);
|
|
|
|
WSACleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI WorkWithClient(LPVOID lpParam) {
|
|
|
|
/*
|
|
|
|
* Client variables
|
|
|
|
*/
|
|
|
|
// Pipe handles for child STDIN/STDOUT
|
|
|
|
HANDLE g_hChildStd_IN_Rd = NULL;
|
|
|
|
HANDLE g_hChildStd_IN_Wr = NULL;
|
|
|
|
HANDLE g_hChildStd_OUT_Rd = NULL;
|
|
|
|
HANDLE g_hChildStd_OUT_Wr = NULL;
|
|
|
|
|
|
|
|
SECURITY_ATTRIBUTES saAttr;
|
|
|
|
HANDLE PipeThreads[3];
|
|
|
|
|
|
|
|
SOCKET ClientSocket = (SOCKET)lpParam;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize pipes
|
|
|
|
*/
|
|
|
|
// Set the bInheritHandle flag so pipe handles are inherited.
|
|
|
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
|
|
saAttr.bInheritHandle = TRUE;
|
|
|
|
saAttr.lpSecurityDescriptor = NULL;
|
|
|
|
|
|
|
|
// Create a pipe for the child process's STDOUT.
|
|
|
|
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
|
|
|
|
printf("StdoutRd CreatePipe\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
|
|
|
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
|
|
|
|
printf("Stdout SetHandleInformation\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a pipe for the child process's STDIN.
|
|
|
|
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) {
|
|
|
|
printf("Stdin CreatePipe\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the write handle to the pipe for STDIN is not inherited.
|
|
|
|
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) {
|
|
|
|
printf("Stdin SetHandleInformation\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create child process cmd.exe
|
|
|
|
*/
|
|
|
|
PipeThreads[0] = CreateChildProcess(g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr);
|
|
|
|
if (!PipeThreads[0]) {
|
|
|
|
printf("Failed to create child process\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create threads for STDIN/STDOUT
|
|
|
|
PipeThreadInfo WriteThreadInfo = { g_hChildStd_IN_Wr, ClientSocket };
|
|
|
|
PipeThreadInfo ReadThreadInfo = { g_hChildStd_OUT_Rd, ClientSocket };
|
|
|
|
PipeThreads[1] = CreateThread(NULL, 0, WriteToPipe, &WriteThreadInfo, 0, NULL);
|
|
|
|
PipeThreads[2] = CreateThread(NULL, 0, ReadFromPipe, &ReadThreadInfo, 0, NULL);
|
|
|
|
|
|
|
|
if (!(PipeThreads[1] && PipeThreads[2])) {
|
|
|
|
printf("Failed to create pipe threads\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
WaitForMultipleObjects(3, PipeThreads, FALSE, INFINITE);
|
|
|
|
|
|
|
|
for (int i = 1; i < 3; TerminateThread(PipeThreads[i++], 0));
|
|
|
|
TerminateProcess(PipeThreads[0], 0);
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; CloseHandle(PipeThreads[i++]));
|
|
|
|
|
|
|
|
closesocket(ClientSocket);
|
|
|
|
printf("\n->Client disconnected.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr)
|
|
|
|
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
|
|
|
|
{
|
|
|
|
TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe");
|
|
|
|
PROCESS_INFORMATION piProcInfo;
|
|
|
|
STARTUPINFO siStartInfo;
|
|
|
|
BOOL bSuccess = FALSE;
|
|
|
|
|
|
|
|
// Set up members of the PROCESS_INFORMATION structure.
|
|
|
|
|
|
|
|
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
|
|
|
|
|
|
|
|
// Set up members of the STARTUPINFO structure.
|
|
|
|
// This structure specifies the STDIN and STDOUT handles for redirection.
|
|
|
|
|
|
|
|
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
|
|
|
siStartInfo.cb = sizeof(STARTUPINFO);
|
|
|
|
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
|
|
|
|
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
|
|
|
|
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
|
|
|
|
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
|
|
|
|
|
// Create the child process.
|
|
|
|
|
|
|
|
bSuccess = CreateProcess(NULL,
|
|
|
|
szCmdline, // command line
|
|
|
|
NULL, // process security attributes
|
|
|
|
NULL, // primary thread security attributes
|
|
|
|
TRUE, // handles are inherited
|
|
|
|
0, // creation flags
|
|
|
|
NULL, // use parent's environment
|
|
|
|
NULL, // use parent's current directory
|
|
|
|
&siStartInfo, // STARTUPINFO pointer
|
|
|
|
&piProcInfo); // receives PROCESS_INFORMATION
|
|
|
|
|
|
|
|
// If an error occurs, exit the application.
|
|
|
|
if (!bSuccess) {
|
|
|
|
printf("CreateProcess\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Close handles to the child process and its primary thread.
|
|
|
|
// Some applications might keep these handles to monitor the status
|
|
|
|
// of the child process, for example.
|
|
|
|
|
|
|
|
//CloseHandle(piProcInfo.hProcess);
|
|
|
|
CloseHandle(piProcInfo.hThread);
|
|
|
|
|
|
|
|
// Close handles to the stdin and stdout pipes no longer needed by the child process.
|
|
|
|
// If they are not explicitly closed, there is no way to recognize that the child process has ended.
|
|
|
|
|
|
|
|
CloseHandle(g_hChildStd_OUT_Wr);
|
|
|
|
CloseHandle(g_hChildStd_IN_Rd);
|
|
|
|
}
|
|
|
|
return piProcInfo.hProcess;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI WriteToPipe(LPVOID lpParam)
|
|
|
|
{
|
|
|
|
DWORD dwRead, dwWritten;
|
|
|
|
BOOL bSuccess = FALSE;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket;
|
|
|
|
HANDLE g_hChildStd_IN_Wr = ((PipeThreadInfo*)lpParam)->Pipe;
|
|
|
|
|
|
|
|
char recvbuf[DEFAULT_BUFLEN];
|
|
|
|
int iResult, iSendResult;
|
|
|
|
int recvbuflen = DEFAULT_BUFLEN;
|
|
|
|
|
|
|
|
// Change codepage to UTF-8
|
|
|
|
//CHAR chcpCommand[] = "chcp 65001\n";
|
|
|
|
//bSuccess = WriteFile(g_hChildStd_IN_Wr, chcpCommand, strlen(chcpCommand), &dwWritten, NULL);
|
|
|
|
//if (!bSuccess) goto WriteToPipe_end;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
|
|
|
|
if (iResult > 0) {
|
|
|
|
bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL);
|
|
|
|
if (!bSuccess) break;
|
|
|
|
}
|
|
|
|
else if (iResult == 0)
|
|
|
|
printf("Connection closing...\n");
|
|
|
|
else {
|
|
|
|
printf("recv failed: %d\n", WSAGetLastError());
|
|
|
|
closesocket(ClientSocket);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} while (iResult > 0);
|
|
|
|
|
|
|
|
WriteToPipe_end:
|
|
|
|
if (!CloseHandle(g_hChildStd_IN_Wr)) {
|
|
|
|
printf("StdInWr CloseHandle\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI ReadFromPipe(LPVOID lpParam)
|
|
|
|
{
|
|
|
|
DWORD dwRead;
|
|
|
|
CHAR chBuf[BUFSIZE + 1];
|
|
|
|
|
|
|
|
BOOL bSuccess = FALSE;
|
|
|
|
SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket;
|
|
|
|
HANDLE g_hChildStd_OUT_Rd = ((PipeThreadInfo*)lpParam)->Pipe;
|
|
|
|
|
|
|
|
int iSendResult;
|
|
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
|
|
|
|
if (!bSuccess || dwRead == 0) break;
|
|
|
|
chBuf[dwRead] = '\0';
|
|
|
|
|
|
|
|
iSendResult = send(ClientSocket, chBuf, dwRead, 0);
|
|
|
|
if (iSendResult == SOCKET_ERROR) {
|
|
|
|
printf("send failed: %d\n", WSAGetLastError());
|
|
|
|
closesocket(ClientSocket);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!bSuccess) break;
|
|
|
|
}
|
|
|
|
}
|