19 install_entry_vec entries;
28 return "DTTR_ERR_INVALID_ARGUMENT";
30 return "DTTR_ERR_NOT_FOUND";
32 return "DTTR_ERR_UNSUPPORTED";
34 return "DTTR_ERR_ALREADY_INSTALLED";
36 return "DTTR_ERR_NOT_INSTALLED";
38 return "DTTR_ERR_MEMORY_PROTECTION";
40 return "DTTR_ERR_RUNTIME_UNAVAILABLE";
42 return "DTTR_ERR_ABI_MISMATCH";
44 return "DTTR_ERR_OUT_OF_MEMORY";
46 return "DTTR_ERR_HOOK_CHAIN_UNSUPPORTED";
48 return "DTTR_ERR_MISSING_SYMBOL";
50 return "DTTR_ERR_UNRESOLVED";
52 return "DTTR_ERR_NOT_CALLABLE";
54 return "DTTR_ERR_READ_FAILED";
56 return "DTTR_ERR_WRITE_FAILED";
58 return "DTTR_ERR_POLICY_MISMATCH";
60 return "DTTR_ERR_UNSUPPORTED_LAYOUT";
62 return "DTTR_ERR_UNSUPPORTED_CONTRACT";
64 return "DTTR_ERR_PROVENANCE_UNSAFE";
66 return "DTTR_ERR_UNKNOWN";
83 return ctx &&
ctx->game_module &&
ctx->api;
87 if (ch >=
'0' && ch <=
'9') {
91 if (ch >=
'a' && ch <=
'f') {
95 if (ch >=
'A' && ch <=
'F') {
115 if (!aob || !out_sig || !out_mask) {
122 size_t cap = strlen(aob) / 2u + 2u;
123 char *sig = (
char *)calloc(cap, 1u);
124 char *mask = (
char *)calloc(cap, 1u);
131 "failed to allocate AOB buffers"
139 while (*p && isspace((
unsigned char)*p)) {
147 if (
count + 1u >= cap) {
152 "AOB pattern is malformed"
172 if (hi < 0 || lo < 0) {
177 "AOB pattern contains a non-hex byte"
181 sig[
count] = (char)((hi << 4) | lo);
186 if (*p && !isspace((
unsigned char)*p)) {
191 "AOB bytes must be separated by spaces"
201 "AOB pattern is empty"
226 const uintptr_t addr =
sigscan(mod, sig, mask);
262 "runtime sigscan is unavailable"
278 "invalid signature find arguments"
288 "runtime sigscan is unavailable"
292 uintptr_t addr = runtime->
sigscan(
ctx->game_module, sig, mask);
305 const uint8_t *bytes,
322 "runtime byte patcher is unavailable"
351 "invalid function hook arguments"
360 "runtime function hooker is unavailable"
365 *hook = runtime->
hook_function(address, prologue_size, detour, out_original);
402 (uintptr_t)((intptr_t)match + offset),
411 const int64_t rel = (int64_t)(intptr_t)detour - (int64_t)(site + 5u);
413 if (rel < INT32_MIN || rel > INT32_MAX) {
417 *out_rel = (int32_t)rel;
435 uint8_t jmp[5] = {0xE9};
442 memcpy(jmp + 1, &rel,
sizeof(rel));
466 (uintptr_t)((intptr_t)match + offset),
486 "invalid pointer hook arguments"
495 "runtime pointer hooker is unavailable"
533 if (kv_size(group->entries) < kv_max(group->entries)) {
537 const size_t new_cap = kv_max(group->entries) ? kv_max(group->entries) * 2u : 4u;
539 if (new_cap < kv_max(group->entries)
545 realloc(group->entries.a, new_cap *
sizeof(*entries));
551 group->entries.a = entries;
552 group->entries.m = new_cap;
576 if (runtime && runtime->
unhook) {
589 while (kv_size(group->entries) > keep_count) {
590 install_entry entry = kv_A(group->entries, kv_size(group->entries) - 1u);
594 "failed to restore one or more patch group entries"
598 kv_pop(group->entries);
618 "invalid patch group arguments"
629 kv_init(group->entries);
652 kv_destroy(group->entries);
658 if (!group || !*group) {
673 return group ? &group->ctx :
NULL;
688 group->entries.a[group->entries.n++] = (
install_entry){hook, out_original};
700 const uint8_t *bytes,
819 return target->out_original;
834 if (!group || (!targets && target_count)) {
837 "invalid patch group target arguments"
843 const size_t keep_count = kv_size(group->entries);
845 for (
size_t i = 0; i < target_count; i++) {
930 uintptr_t *out_address
940 *out_address =
target->address;
951 *out_address = (uintptr_t)((intptr_t)match +
target->offset);
962 uintptr_t address = 0;
966 return address_result;
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD count
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
DTTR_Graphics_COM_DirectDrawSurface7 DWORD DWORD void void DWORD flags DTTR_Graphics_COM_DirectDrawSurface7 void void *cb void * target
static DTTR_Result dttr_core_result(DTTR_Status status, const char *message)
DTTR_Result dttr_core_hook_last_error()
DTTR_Core_Hook DTTR_Core_Patch
@ DTTR_TARGET_ADDRESS_REL32_JMP
@ DTTR_TARGET_ADDRESS_HOOK
@ DTTR_TARGET_POINTER_HOOK
@ DTTR_TARGET_ADDRESS_PATCH
@ DTTR_TARGET_AOB_REL32_JMP
struct DTTR_Core_PatchGroup DTTR_Core_PatchGroup
@ DTTR_ERR_HOOK_CHAIN_UNSUPPORTED
@ DTTR_ERR_RUNTIME_UNAVAILABLE
@ DTTR_ERR_INVALID_ARGUMENT
@ DTTR_ERR_UNSUPPORTED_LAYOUT
@ DTTR_ERR_UNSUPPORTED_CONTRACT
@ DTTR_ERR_PROVENANCE_UNSAFE
@ DTTR_ERR_MEMORY_PROTECTION
@ DTTR_ERR_MISSING_SYMBOL
@ DTTR_ERR_POLICY_MISMATCH
@ DTTR_ERR_ALREADY_INSTALLED
uintptr_t(* DTTR_Core_SigscanFn)(HMODULE mod, const char *sig, const char *mask)
uintptr_t DTTR_Core_HookSigscan(HMODULE mod, const char *sig, const char *mask)
bool DTTR_Core_HookDetachChecked(DTTR_Core_Hook *hook)
static bool rel32_displacement(uintptr_t site, void *detour, int32_t *out_rel)
const DTTR_Core_Context * dttr_core_patch_group_context(const DTTR_Core_PatchGroup *group)
DTTR_Result DTTR_Core_PatchGroupDestroy(DTTR_Core_PatchGroup *group)
void dttr_core_report_fail(DTTR_Core_TargetReport *report, size_t index, DTTR_Result result)
void dttr_core_report_init(DTTR_Core_TargetReport *report)
DTTR_Result DTTR_Core_HookFunction(const DTTR_Core_Context *ctx, uintptr_t address, int prologue_size, void *detour, void **out_original, DTTR_Core_Hook **out_hook)
const char * DTTR_StatusName(DTTR_Status status)
static int hex_value(char ch)
static DTTR_Result patch_group_prepare_install(DTTR_Core_PatchGroup *group)
DTTR_Result DTTR_Core_AOBFindInModule(HMODULE mod, const char *aob, uintptr_t *out_addr)
static DTTR_Result patch_group_uninstall_from(DTTR_Core_PatchGroup *group, size_t keep_count)
DTTR_Result DTTR_Core_SignatureFind(const DTTR_Core_Context *ctx, const char *sig, const char *mask, uintptr_t *out_addr)
DTTR_Result DTTR_Core_PatchRel32Jump(const DTTR_Core_Context *ctx, uintptr_t address, void *detour, DTTR_Core_Patch **out_patch)
static DTTR_Result patch_group_finish_install(DTTR_Core_PatchGroup *group, DTTR_Result result, DTTR_Core_Hook *hook, void **out_original, DTTR_Core_Hook **out_hook)
DTTR_Result DTTR_Core_PatchGroupCreate(const DTTR_Core_Context *ctx, DTTR_Core_PatchGroup **out_group)
bool DTTR_ResultOK(DTTR_Result result)
static DTTR_Result parse_aob(const char *aob, char **out_sig, char **out_mask)
DTTR_Result DTTR_Core_PatchAOBRel32Jump(const DTTR_Core_Context *ctx, const char *aob, intptr_t offset, void *detour, DTTR_Core_Patch **out_patch)
static void ** target_original_slot(const DTTR_Core_TargetSpec *target)
DTTR_Result DTTR_Core_PatchGroupPatchRel32Jump(DTTR_Core_PatchGroup *group, uintptr_t address, void *detour, DTTR_Core_Patch **out_patch)
static DTTR_Result target_address(const DTTR_Core_Context *ctx, const DTTR_Core_TargetSpec *target, uintptr_t *out_address)
DTTR_Result DTTR_Core_PatchGroupHookPointer(DTTR_Core_PatchGroup *group, uintptr_t address, void *new_value, void **out_original, DTTR_Core_Hook **out_hook)
typedef kvec_t(install_entry)
DTTR_Result DTTR_Core_PatchGroupRelease(DTTR_Core_PatchGroup **group)
DTTR_Result DTTR_Core_Unpatch(DTTR_Core_Patch *patch)
DTTR_Result DTTR_Core_HookAOB(const DTTR_Core_Context *ctx, const char *aob, intptr_t offset, int prologue_size, void *detour, void **out_original, DTTR_Core_Hook **out_hook)
static DTTR_Result parse_aob_fail(char *sig, char *mask, DTTR_Status status, const char *message)
bool DTTR_StatusOK(DTTR_Status status)
bool DTTR_StatusFailed(DTTR_Status status)
DTTR_Result DTTR_Core_PatchGroupUninstall(DTTR_Core_PatchGroup *group)
DTTR_Result DTTR_Core_AOBFind(const DTTR_Core_Context *ctx, const char *aob, uintptr_t *out_addr)
DTTR_Result DTTR_Core_PatchBytes(const DTTR_Core_Context *ctx, uintptr_t address, const uint8_t *bytes, size_t size, DTTR_Core_Patch **out_patch)
DTTR_Result DTTR_Core_HookPointer(const DTTR_Core_Context *ctx, uintptr_t address, void *new_value, void **out_original, DTTR_Core_Hook **out_hook)
DTTR_Result DTTR_Core_PatchGroupHookFunction(DTTR_Core_PatchGroup *group, uintptr_t address, int prologue_size, void *detour, void **out_original, DTTR_Core_Hook **out_hook)
static DTTR_Result aob_scan_with(HMODULE mod, DTTR_Core_SigscanFn sigscan, const char *aob, uintptr_t *out_addr)
static DTTR_Result patch_group_reserve(DTTR_Core_PatchGroup *group)
static DTTR_Result install_one_target(const DTTR_Core_Context *ctx, const DTTR_Core_TargetSpec *target, DTTR_Core_Hook **out_handle)
static bool patch_group_detach_checked(const DTTR_Core_PatchGroup *group, DTTR_Core_Hook *hook)
DTTR_Result DTTR_Core_Unhook(DTTR_Core_Hook *hook)
DTTR_Result DTTR_Core_PatchGroupInstallTargets(DTTR_Core_PatchGroup *group, const DTTR_Core_TargetSpec *targets, size_t target_count, DTTR_Core_TargetReport *out_report)
static bool runtime_context_valid(const DTTR_Core_Context *ctx)
DTTR_Result DTTR_Core_PatchGroupPatchBytes(DTTR_Core_PatchGroup *group, uintptr_t address, const uint8_t *bytes, size_t size, DTTR_Core_Patch **out_patch)
static uintptr_t sigscan(HMODULE mod, const char *sig, const char *mask)
DTTR_Core_UnhookCheckedFn unhook_checked
DTTR_Core_HookFunctionFn hook_function
DTTR_Core_UnhookFn unhook
DTTR_Core_HookPointerFn hook_pointer
DTTR_Core_SigscanFn sigscan
DTTR_Core_PatchBytesFn patch_bytes
const char * message
Optional static diagnostic text. May be NULL when status is enough.