#pragma once
#include <windows.h>
#include "protocol.h"
#include <cstring>
#include <vector>
namespace easy::kernel {
struct ReadResult {
DWORD transport_error{};
int32_t status{};
std::vector<unsigned char> data;
bool complete(size_t requested) const {
return !transport_error && status == 0 && data.size() == requested;
}
};
// Synchronous only. process must be a real caller-owned PROCESS_VM_READ handle.
inline ReadResult read(HANDLE device, HANDLE process, uint64_t address, uint32_t bytes) {
ReadResult result;
if (!bytes || bytes > EASY_KERNEL_READ_MAX) {
result.transport_error = ERROR_INVALID_PARAMETER;
return result;
}
EasyKernelRead request{sizeof(EasyKernelRead), EASY_KERNEL_READ_VERSION,
uint64_t(reinterpret_cast<uintptr_t>(process)), address, bytes, 0};
std::vector<unsigned char> output(sizeof(EasyKernelReadReply) + bytes);
DWORD returned = 0;
if (!DeviceIoControl(device, EASY_KERNEL_READ, &request, sizeof(request),
output.data(), static_cast<DWORD>(output.size()), &returned, nullptr)) {
result.transport_error = GetLastError();
return result;
}
EasyKernelReadReply reply{};
if (returned < sizeof(reply) || returned > output.size()) {
result.transport_error = ERROR_INVALID_DATA;
return result;
}
std::memcpy(&reply, output.data(), sizeof(reply));
if (reply.size != sizeof(reply) || reply.version != EASY_KERNEL_READ_VERSION ||
reply.bytes_read > bytes || returned != sizeof(reply) + reply.bytes_read ||
(reply.status == 0 && reply.bytes_read != bytes)) {
result.transport_error = ERROR_INVALID_DATA;
return result;
}
result.status = reply.status;
result.data.assign(output.begin() + sizeof(reply), output.begin() + returned);
return result;
}
}
Easy Universal / Примеры и шаблоны