mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-03 21:46:32 +00:00
104 lines
3.3 KiB
C++
104 lines
3.3 KiB
C++
#include "x86_com.h"
|
|
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <sys/mman.h>
|
|
#include <stdexcept>
|
|
|
|
namespace raven {
|
|
|
|
NativeX86Com::NativeX86Com(NativeProcess &process, std::span<const ComMethod> methods) : process(process), methods(methods)
|
|
{
|
|
for (const auto &method : methods)
|
|
by_name.emplace(std::string(method.interface) + "." + std::string(method.name), method.words);
|
|
}
|
|
|
|
std::vector<std::string_view> com_names(std::span<const ComMethod> methods)
|
|
{
|
|
// The strings live as long as the process.
|
|
static std::deque<std::string> storage;
|
|
std::vector<std::string_view> result;
|
|
for (const auto &method : methods) {
|
|
storage.push_back(std::string(method.interface) + "." + std::string(method.name));
|
|
result.push_back(storage.back());
|
|
}
|
|
std::sort(result.begin(), result.end());
|
|
result.erase(std::unique(result.begin(), result.end()), result.end());
|
|
return result;
|
|
}
|
|
|
|
uint32_t com_words(std::span<const ComMethod> methods, std::string_view name)
|
|
{
|
|
for (const auto &method : methods)
|
|
if (name.size() == method.interface.size() + 1 + method.name.size() && name.starts_with(method.interface) && name.ends_with(method.name))
|
|
return method.words;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t NativeX86Com::words(std::string_view name) const
|
|
{
|
|
const auto found = by_name.find(std::string(name));
|
|
return found == by_name.end() ? 0 : found->second;
|
|
}
|
|
|
|
std::pair<std::string_view, std::string_view> NativeX86Com::split(std::string_view name) const
|
|
{
|
|
const auto separator = name.find('.');
|
|
return {name.substr(0, separator), name.substr(separator + 1)};
|
|
}
|
|
|
|
void NativeX86Com::write32(uint64_t address, uint32_t value)
|
|
{
|
|
const uint8_t bytes[4] = {uint8_t(value), uint8_t(value >> 8), uint8_t(value >> 16), uint8_t(value >> 24)};
|
|
process.write_memory(address, bytes);
|
|
}
|
|
|
|
uint32_t NativeX86Com::read32(uint64_t address)
|
|
{
|
|
const auto bytes = process.read_memory(address, 4);
|
|
return uint32_t(bytes[0]) | uint32_t(bytes[1]) << 8 | uint32_t(bytes[2]) << 16 | uint32_t(bytes[3]) << 24;
|
|
}
|
|
|
|
uint64_t NativeX86Com::vtable(const std::string &interface)
|
|
{
|
|
const auto known = vtables.find(interface);
|
|
if (known != vtables.end())
|
|
return known->second;
|
|
const auto base = process.map_memory(4096, PROT_READ | PROT_WRITE);
|
|
size_t entries = 0;
|
|
for (const auto &method : methods)
|
|
if (method.interface == interface) {
|
|
const auto name = interface + "." + std::string(method.name);
|
|
const auto trap = trap_addresses.find(name);
|
|
if (trap == trap_addresses.end())
|
|
throw std::runtime_error("native COM method has no trap: " + name);
|
|
write32(base + method.index * 4ULL, uint32_t(trap->second));
|
|
++entries;
|
|
}
|
|
if (!entries)
|
|
throw std::runtime_error("native COM has no interface " + interface);
|
|
vtables[interface] = base;
|
|
return base;
|
|
}
|
|
|
|
// An object is the vtable pointer, the reference count and room for the implementation.
|
|
uint64_t NativeX86Com::make_object(const std::string &interface)
|
|
{
|
|
const auto object = process.map_memory(4096, PROT_READ | PROT_WRITE);
|
|
write32(object, uint32_t(vtable(interface)));
|
|
write32(object + 4, 1);
|
|
return object;
|
|
}
|
|
|
|
bool NativeX86Com::counted(std::string_view method, const std::vector<uint64_t> &args)
|
|
{
|
|
if (method != "AddRef" && method != "Release")
|
|
return false;
|
|
const auto count = read32(args[0] + 4) + (method == "AddRef" ? 1 : uint32_t(-1));
|
|
write32(args[0] + 4, count);
|
|
process.return_api(count);
|
|
return true;
|
|
}
|
|
|
|
}
|