102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
pcdogs.c
Go to the documentation of this file.
1#include <dttr_test.h>
2
3#include <string.h>
4
5static const uint8_t PATCH_FAST_PATH[] = {0xE9, 0xBA, 0x00, 0x00, 0x00, 0x90};
6static const uint8_t PATCH_NOP2[] = {0x90, 0x90};
7static const uint8_t PATCH_FTOL_X[] = {0xD9, 0x1F, 0x90, 0x90, 0x90};
8static const uint8_t PATCH_NOP4[] = {0x90, 0x90, 0x90, 0x90};
9static const uint8_t PATCH_FTOL_Y[] = {0xD9, 0x5D, 0x00, 0x90, 0x90};
10static const uint8_t PATCH_NOP3[] = {0x90, 0x90, 0x90};
11static const uint8_t PATCH_RET[] = {0xC3};
12
13static const uint8_t ORIGINAL_FAST_PATH[] = {0x0F, 0x85, 0xB9, 0x00, 0x00, 0x00};
14static const uint8_t ORIGINAL_BATCH_LIMIT_A[] = {0x7D, 0x39};
15static const uint8_t ORIGINAL_BATCH_LIMIT_B[] = {0x7D, 0x59};
16static const uint8_t ORIGINAL_FTOL_CALL[] = {0xE8, 0, 0, 0, 0};
17static const uint8_t ORIGINAL_MOV_XY[] = {0x89, 0x44, 0x24, 0x30};
18static const uint8_t ORIGINAL_FSTP_X[] = {0xD9, 0x1F};
19static const uint8_t ORIGINAL_FILD_X[] = {0xDB, 0x44, 0x24, 0x30};
20static const uint8_t ORIGINAL_FSTP_Y[] = {0xD9, 0x5D, 0x00};
21static const uint8_t ORIGINAL_FILD_Y[] = {0xDB, 0x44, 0x24, 0x34};
22static const uint8_t ORIGINAL_PUSH_EBX[] = {0x53};
23
24#define SIDECAR_JMP_HOOK_TARGET(NAME, SIG, MASK, REQUIRED) \
25 {NAME, \
26 TARGET_JMP_HOOK, \
27 (const uint8_t *)(SIG), \
28 MASK, \
29 REQUIRED, \
30 0, \
31 NULL, \
32 0, \
33 NULL, \
34 NULL}
35#define SIDECAR_BYTE_PATCH_TARGET(NAME, SIG, MASK, OFFSET, PATCH, ORIGINAL, ORIGINAL_MASK) \
36 { \
37 NAME, \
38 TARGET_BYTE_PATCH, \
39 (const uint8_t *)(SIG), \
40 MASK, \
41 DTTR_TEST_PCDOGS_REQUIRED_ALL, \
42 OFFSET, \
43 PATCH, \
44 sizeof(PATCH), \
45 ORIGINAL, \
46 ORIGINAL_MASK, \
47 }
48
51 "dttr_hook_win_main",
52 "\x83\xEC\x40\x53\x8B\x5C\x24",
53 "xxxxxxx",
55 ),
57 "dttr_hook_resolve_pcdogs_path",
58 "\x51\x8D\x44\x24?\x57",
59 "xxxx?x",
61 ),
63 "dttr_inputs_hook_dinput_poll",
64 "\x56\x8B\x74\x24?\x56\x8B\x06",
65 "xxxx?xxx",
67 ),
69 "dttr_hook_precision_fast_path",
70 "\x83\xF8?\x7C?\xD9\x43?\xD8\x1D????\xDF\xE0\xF6\xC4\x41\x0F????",
71 "xx?x?xx?xx????xxxxxx????",
72 19,
75 "xxxxxx"
76 ),
78 "dttr_hook_precision_batch_limit_a",
79 "\x8B\x08\xEB?\xA1????\x8B\x0D????\x3B\xC1",
80 "xxx?x????xx????xx",
81 17,
84 "xx"
85 ),
87 "dttr_hook_precision_batch_limit_b",
88 "\x83\xC1\x14\x4E\x75?\xA1????\x8B\x0D????\x3B\xC1",
89 "xxxxx?x????xx????xx",
90 19,
93 "xx"
94 ),
96 "dttr_hook_precision_ftol_x",
97 "\xDB\x44\x24\x30\xD9\x1F",
98 "xxxxxx",
99 -15,
102 "x????"
103 ),
105 "dttr_hook_precision_mov_x",
106 "\xDB\x44\x24\x30\xD9\x1F",
107 "xxxxxx",
108 -10,
111 "xxxx"
112 ),
114 "dttr_hook_precision_fstp2_x",
115 "\x8D\xAE????\xDB\x44\x24\x30\xD9\x1F",
116 "xx????xxxxxx",
117 10,
120 "xx"
121 ),
123 "dttr_hook_precision_fild_x",
124 "\x8D\xAE????\xDB\x44\x24\x30",
125 "xx????xxxx",
126 6,
129 "xxxx"
130 ),
132 "dttr_hook_precision_ftol_y",
133 "\x8B\x54\x24\x18\x89\x44\x24\x30",
134 "xxxxxxxx",
135 -5,
138 "x????"
139 ),
141 "dttr_hook_precision_mov_y",
142 "\x8B\x54\x24\x18\x89\x44\x24\x30",
143 "xxxxxxxx",
144 4,
147 "xxxx"
148 ),
150 "dttr_hook_precision_fstp2_y",
151 "\x83\xC0\x14\x50\x55\xD9\x5D\x00",
152 "xxxxxxxx",
153 5,
156 "xxx"
157 ),
159 "dttr_hook_precision_fild_y",
160 "\x52\xDB\x44\x24\x34",
161 "xxxxx",
162 1,
165 "xxxx"
166 ),
168 "dttr_hook_render_quad_snap",
169 "\x53\x8B\x5C\x24\x14\x55\x33\xC9\x56\x57\x85\xDB",
170 "xxxxxxxxxxxx",
171 0,
172 PATCH_RET,
174 "x"
175 ),
176};
177
180 )
181 / sizeof(
183 );
184
186 "_AIL_allocate_sample_handle@4",
187 "_AIL_close_stream@4",
188 "_AIL_end_sample@4",
189 "_AIL_get_preference@4",
190 "_AIL_init_sample@4",
191 "_AIL_open_stream@12",
192 "_AIL_pause_stream@8",
193 "_AIL_release_sample_handle@4",
194 "_AIL_sample_playback_rate@4",
195 "_AIL_sample_status@4",
196 "_AIL_set_digital_master_volume@8",
197 "_AIL_set_preference@8",
198 "_AIL_set_sample_file@12",
199 "_AIL_set_sample_loop_count@8",
200 "_AIL_set_sample_pan@8",
201 "_AIL_set_sample_playback_rate@8",
202 "_AIL_set_sample_volume@8",
203 "_AIL_set_stream_loop_count@8",
204 "_AIL_set_stream_volume@8",
205 "_AIL_shutdown@0",
206 "_AIL_start_sample@4",
207 "_AIL_start_stream@4",
208 "_AIL_startup@0",
209 "_AIL_stop_sample@4",
210 "_AIL_stream_status@4",
211 "_AIL_waveOutClose@4",
212 "_AIL_waveOutOpen@16",
213};
214
218
219typedef struct {
222
223// Checks sidecar target signatures against every available PCDogs fixture.
225 size_t fixture_index,
226 const DTTR_TestBinaryFixture *fixture,
227 const char *path,
228 const DTTR_TestPEImage *image,
229 void *userdata
230) {
231 const target_filter *filter = userdata;
232
233 for (size_t target_index = 0; target_index < DTTR_TEST_PCDOGS_SIDECAR_TARGET_COUNT;
234 target_index++) {
237
238 if (target->kind != filter->kind
239 || !dttr_test_fixture_required(target->required, fixture_index)) {
240 continue;
241 }
242
244 }
245
246 return true;
247}
248
249// Runs one target-kind fixture pass.
251 target_filter filter = {.kind = kind};
253}
254
255// Verifies expected PCDogs jump-hook targets.
260
261// Verifies expected PCDogs byte-patch targets.
266
267// Checks whether an mss32.dll import is expected to be hooked.
268static bool import_hook_expected(const char *name) {
269 for (size_t i = 0; i < DTTR_TEST_PCDOGS_SIDECAR_MSS_IMPORT_HOOK_COUNT; i++) {
270 if (strcmp(name, DTTR_TEST_PCDOGS_SIDECAR_MSS_IMPORT_HOOKS[i]) == 0) {
271 return true;
272 }
273 }
274
275 return false;
276}
277
278// Verifies each fixture exposes exactly the mss32.dll imports hooked by the sidecar.
280 size_t fixture_index,
281 const DTTR_TestBinaryFixture *fixture,
282 const char *path,
283 const DTTR_TestPEImage *image,
284 void *userdata
285) {
286 DTTR_TestImportEntry imports[DTTR_TEST_PCDOGS_IMPORT_CAP] = {0};
287 const size_t import_count = pcdogs_collect_imports(
288 image,
289 imports,
291 );
292
293 size_t mss32_count = 0;
294
295 for (size_t i = 0; i < import_count; i++) {
296 const DTTR_TestImportEntry *entry = &imports[i];
297
298 if (!dttr_test_case_equal(entry->dll, "mss32.dll")) {
299 continue;
300 }
301
302 mss32_count++;
303
304 if (!import_hook_expected(entry->name)) {
305 fail_msg(
306 "unhandled MSS32 import in %s (%s): %s",
307 fixture->id,
308 fixture->filename,
309 entry->name
310 );
311 }
312
313 assert_true(entry->iat_site != 0);
314 }
315
316 assert_int_equal(mss32_count, DTTR_TEST_PCDOGS_SIDECAR_MSS_IMPORT_HOOK_COUNT);
317 return true;
318}
319
320// Verifies expected mss32.dll imports are hooked.
325
331
void dttr_test_assert_target_resolved(const DTTR_TestBinaryFixture *fixture, const DTTR_TestTargetExpectation *target, const DTTR_TestPEImage *image)
Definition binary.c:842
bool dttr_test_case_equal(const char *a, const char *b)
Definition binary.c:183
bool dttr_test_fixture_required(DTTR_TestFixtureMask required, size_t fixture_index)
Definition binary.c:187
const DTTR_BackendState * state
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 const DTTR_TestCase TEST_CASES[]
Definition core.c:17
#define DTTR_TEST_PCDOGS_REQUIRED_ALL
Definition dttr_test.h:8
#define TARGET_BYTE_PATCH
Definition dttr_test.h:28
#define DTTR_TEST_PCDOGS_IMPORT_CAP
Definition dttr_test.h:21
#define DTTR_TEST_PCDOGS_REQUIRED_EU_SC
Definition dttr_test.h:11
const size_t DTTR_TEST_PCDOGS_SIDECAR_MSS_IMPORT_HOOK_COUNT
Definition pcdogs.c:216
const char *const DTTR_TEST_PCDOGS_SIDECAR_MSS_IMPORT_HOOKS[]
Definition pcdogs.c:185
const pcdogs_target_expectation DTTR_TEST_PCDOGS_SIDECAR_TARGETS[]
Definition pcdogs.c:49
static size_t pcdogs_collect_imports(const DTTR_TestPEImage *image, DTTR_TestImportEntry *imports, size_t imports_cap)
Collect fixture imports for tests that validate recovered sidecar targets.
Definition dttr_test.h:74
DTTR_TestTargetKind E_TargetKind
Definition dttr_test.h:39
bool pcdogs_fixtures_available()
Report whether all PCDOGS binary fixtures are available for signature tests.
bool pcdogs_for_each_fixture(DTTR_TestPEFixtureVisitor visitor, void *userdata)
Visit each available PCDOGS fixture image for signature and ABI checks.
DTTR_TestTargetExpectation pcdogs_target_expectation
Definition dttr_test.h:40
#define TARGET_JMP_HOOK
Definition dttr_test.h:24
const size_t DTTR_TEST_PCDOGS_SIDECAR_TARGET_COUNT
Definition pcdogs.c:178
static void dttr_test_require_available(bool available)
#define DTTR_TEST_MAIN(TESTS)
static const uint8_t ORIGINAL_FILD_X[]
Definition pcdogs.c:19
static const uint8_t PATCH_FAST_PATH[]
Definition pcdogs.c:5
static const uint8_t ORIGINAL_FILD_Y[]
Definition pcdogs.c:21
static const uint8_t PATCH_NOP3[]
Definition pcdogs.c:10
#define SIDECAR_JMP_HOOK_TARGET(NAME, SIG, MASK, REQUIRED)
Definition pcdogs.c:24
static const uint8_t ORIGINAL_PUSH_EBX[]
Definition pcdogs.c:22
static const uint8_t ORIGINAL_BATCH_LIMIT_B[]
Definition pcdogs.c:15
static bool assert_targets_for_fixture(size_t fixture_index, const DTTR_TestBinaryFixture *fixture, const char *path, const DTTR_TestPEImage *image, void *userdata)
Definition pcdogs.c:224
static const uint8_t ORIGINAL_BATCH_LIMIT_A[]
Definition pcdogs.c:14
static const uint8_t ORIGINAL_FAST_PATH[]
Definition pcdogs.c:13
static const uint8_t PATCH_FTOL_Y[]
Definition pcdogs.c:9
static bool assert_imports_for_fixture(size_t fixture_index, const DTTR_TestBinaryFixture *fixture, const char *path, const DTTR_TestPEImage *image, void *userdata)
Definition pcdogs.c:279
static const uint8_t ORIGINAL_FSTP_Y[]
Definition pcdogs.c:20
static const uint8_t ORIGINAL_FTOL_CALL[]
Definition pcdogs.c:16
static void test_expected_pcdogs_jmp_hook_targets_resolve(void **state)
Definition pcdogs.c:256
static const uint8_t PATCH_NOP4[]
Definition pcdogs.c:8
static const uint8_t PATCH_FTOL_X[]
Definition pcdogs.c:7
static void test_expected_pcdogs_byte_patch_targets_resolve(void **state)
Definition pcdogs.c:262
static const uint8_t PATCH_RET[]
Definition pcdogs.c:11
static const uint8_t ORIGINAL_FSTP_X[]
Definition pcdogs.c:18
static const uint8_t ORIGINAL_MOV_XY[]
Definition pcdogs.c:17
static bool import_hook_expected(const char *name)
Definition pcdogs.c:268
static void test_targets_matching(E_TargetKind kind)
Definition pcdogs.c:250
static void test_expected_mss32_imports_are_hooked(void **state)
Definition pcdogs.c:321
#define SIDECAR_BYTE_PATCH_TARGET(NAME, SIG, MASK, OFFSET, PATCH, ORIGINAL, ORIGINAL_MASK)
Definition pcdogs.c:35
static const uint8_t PATCH_NOP2[]
Definition pcdogs.c:6
E_TargetKind kind
Definition pcdogs.c:220