Program Listing for File DefaultDevs.cpp

Return to documentation for file (include\input\DefaultDevs\windows\DefaultDevs.cpp)

#include "DefaultDevs.hpp"
#include "NameGen.hpp"
#include "PDJE_RAII_WRAP.hpp"
#include "ipc_util.hpp"

namespace PDJE_DEFAULT_DEVICES {

bool
DefaultDevs::OpenProcess(const fs::path &pt)
{
    start_up_info    = STARTUPINFOW{};
    process_info     = PROCESS_INFORMATION{};
    start_up_info.cb = sizeof(start_up_info);
    try {
        subprocess_RAII.val = CreateJobObjectW(nullptr, nullptr);
        if (subprocess_RAII.get() == INVALID_HANDLE_VALUE) {
            throw std::runtime_error(
                "failed to run CreateJobObjectW. Errcode: " +
                std::to_string(GetLastError()));
        }
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION sub_raii_info{};
        sub_raii_info.BasicLimitInformation.LimitFlags =
            JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

        if (!SetInformationJobObject(subprocess_RAII.get(),
                                     JobObjectExtendedLimitInformation,
                                     &sub_raii_info,
                                     sizeof(sub_raii_info))) {
            throw std::runtime_error(
                "failed to run SetInformationJobObject. Errcode: " +
                std::to_string(GetLastError()));
        }
        WINRAII file_locker;
        file_locker.val =
            CreateFileW(pt.wstring().c_str(),
                        GENERIC_READ,
                        FILE_SHARE_READ,
                        nullptr,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
                        nullptr);
        if (!file_locker.get()) {
            critlog("failed to lock subprocess exe file");
            return false;
        }
        if (!PDJE_IPC::HashCompare(pt)) {
            critlog("hash not matched. maybe Under Attack.");
            return false;
        }
        WINRAII readHdl;
        readHdl.val              = pipe.Gen();
        start_up_info.dwFlags    = STARTF_USESTDHANDLES;
        start_up_info.hStdInput  = readHdl.get();
        start_up_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
        start_up_info.hStdError  = GetStdHandle(STD_ERROR_HANDLE);
        auto cmd                 = pt.wstring();
        BOOL ok                  = CreateProcessW(nullptr,
                                 cmd.data(),
                                 nullptr,
                                 nullptr,
                                 TRUE,
                                 CREATE_NO_WINDOW | CREATE_SUSPENDED,
                                 nullptr,
                                 nullptr,
                                 &start_up_info,
                                 &process_info);
        if (!ok) {
            critlog("failed to create child process. Err:");
            critlog(GetLastError());
            return false;
        }

        if (!AssignProcessToJobObject(subprocess_RAII.get(),
                                      process_info.hProcess)) {
            TerminateProcess(process_info.hProcess, 1);
            throw std::runtime_error("AssignProcessToJobObject failed: " +
                                     std::to_string(GetLastError()));
        }
        ResumeThread(process_info.hThread);
        CloseHandle(process_info.hThread);
        process_info.hThread = nullptr;

    } catch (const std::exception &e) {
        if (process_info.hProcess) {
            CloseHandle(process_info.hProcess);
        }
        if (process_info.hThread) {
            CloseHandle(process_info.hThread);
        }
        critlog("exception on creating child process. Err:");
        critlog(e.what());
        return false;
    }
    return true;
}

DefaultDevs::DefaultDevs()
{

    auto path = GetValidProcessExecutor();

    if (!OpenProcess(path)) {
        critlog("failed to open child process. Err:");
        critlog(GetLastError());
        return;
    }
    pipe.Send(meta.GenTXRX().str());
    meta.Listen();
    if (!meta.QueryHealth()) {
        critlog("Query Health Failed on MainProcess init.");
    }
}

void
DefaultDevs::InitEvents()
{
    auto namegen  = PDJE_IPC::RANDOM_GEN();
    auto loop_run = namegen.Gen("PDJE_IPC_EVENT_LOOP_RUN_");
    auto term     = namegen.Gen("PDJE_IPC_EVENT_TERMINATE_");

    events.input_loop_run_event.HostInit(loop_run);
    events.terminate_event.HostInit(term);
    meta.SendIPCSharedMemory(1, loop_run, "EVENT_input_loop_run");
    meta.SendIPCSharedMemory(1, term, "EVENT_terminate");
}

void
DefaultDevs::Ready()
{
    PDJE_IPC::Input_Transfer_Metadata cfg;
    PDJE_IPC::RANDOM_GEN              rg;
    cfg.max_length              = 2048;
    cfg.lenname                 = rg.Gen("PDJE_INPUT_LEN_");
    cfg.bodyname                = rg.Gen("PDJE_INPUT_BODY_");
    cfg.hmacname                = rg.Gen("PDJE_INPUT_HMAC_");
    cfg.data_request_event_name = rg.Gen("PDJE_INPUT_REQ_EVENT_");
    cfg.data_stored_event_name  = rg.Gen("PDJE_INPUT_STORED_EVENT_");
    input_buffer.emplace(cfg);
    meta.SendInputTransfer(input_buffer.value());
    InitEvents();
}

bool
DefaultDevs::Config(const std::vector<DeviceData> &devs)
{
    nlohmann::json nj;
    try {

        nj["body"] = nlohmann::json::array();
        for (const auto &dev : devs) {
            std::unordered_map<std::string, std::string> kv;
            kv["id"]   = dev.device_specific_id;
            kv["name"] = dev.Name;
            switch (dev.Type) {
            case PDJE_Dev_Type::KEYBOARD:
                kv["type"] = "KEYBOARD";
                nj["body"].push_back(kv);
                break;
            case PDJE_Dev_Type::MOUSE:
                kv["type"] = "MOUSE";
                nj["body"].push_back(kv);
                break;

            default:
                break;
            }
        }
    } catch (const std::exception &e) {
        critlog("failed to make json device configure query. What: ");
        critlog(e.what());
        return false;
    }
    return meta.QueryConfig(nj.dump());
}
DefaultDevs::~DefaultDevs()
{
    if (process_info.hProcess) {
        CloseHandle(process_info.hProcess);
    }
    if (process_info.hThread) {
        CloseHandle(process_info.hThread);
    }
}
}; // namespace PDJE_DEFAULT_DEVICES