| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- #include <stdio.h>
- #include <windows.h>
- #include <d3d9.h>
- #include "get-graphics-offsets.h"
- typedef HRESULT(WINAPI *d3d9createex_t)(UINT, IDirect3D9Ex **);
- struct d3d9_info {
- HMODULE module;
- HWND hwnd;
- IDirect3D9Ex *d3d9ex;
- IDirect3DDevice9Ex *device;
- IDirect3DSwapChain9 *swap;
- };
- static inline bool d3d9_init(d3d9_info &info)
- {
- d3d9createex_t create;
- HRESULT hr;
- info.hwnd = CreateWindowExA(0, DUMMY_WNDCLASS, "d3d9 get-offset window",
- WS_POPUP, 0, 0, 1, 1, nullptr, nullptr,
- GetModuleHandleA(nullptr), nullptr);
- if (!info.hwnd) {
- return false;
- }
- info.module = LoadLibraryA("d3d9.dll");
- if (!info.module) {
- return false;
- }
- create = (d3d9createex_t)GetProcAddress(info.module,
- "Direct3DCreate9Ex");
- if (!create) {
- return false;
- }
- hr = create(D3D_SDK_VERSION, &info.d3d9ex);
- if (FAILED(hr)) {
- return false;
- }
- D3DPRESENT_PARAMETERS pp = {};
- pp.Windowed = true;
- pp.SwapEffect = D3DSWAPEFFECT_FLIP;
- pp.BackBufferFormat = D3DFMT_A8R8G8B8;
- pp.BackBufferWidth = 2;
- pp.BackBufferHeight = 2;
- pp.BackBufferCount = 1;
- pp.hDeviceWindow = info.hwnd;
- pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
- hr = info.d3d9ex->CreateDeviceEx(
- D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, info.hwnd,
- D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES,
- &pp, nullptr, &info.device);
- if (FAILED(hr)) {
- return false;
- }
- hr = info.device->GetSwapChain(0, &info.swap);
- if (FAILED(hr)) {
- return false;
- }
- return true;
- }
- static inline void d3d9_free(d3d9_info &info)
- {
- if (info.swap)
- info.swap->Release();
- if (info.device)
- info.device->Release();
- if (info.d3d9ex)
- info.d3d9ex->Release();
- if (info.hwnd)
- DestroyWindow(info.hwnd);
- }
- #ifdef _WIN64
- #define MAX_CMP_SIZE 22
- static const uint8_t mask[][MAX_CMP_SIZE] = {
- {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00},
- {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00},
- {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
- };
- static const uint8_t mask_cmp[][MAX_CMP_SIZE] = {
- /*
- * Windows 7
- * 48 8B 83 B8 3D 00 00 mov rax, [rbx+3DB8h]
- * 44 39 B8 68 50 00 00 cmp [rax+5068h], r15d
- * 75 12 jnz short loc_7FF7AA90530
- * 41 B8 F9 19 00 00 mov r8d, 19F9h
- */
- {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x44, 0x39, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x75, 0x00, 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00},
- /*
- * Windows ???+
- * 49 8B 87 78 41 00 00 mov rax, [r15+4178h]
- * 39 98 E0 51 00 00 cmp [rax+51E0h], ebx
- * 75 12 jnz short loc_1800AEC9C
- * 41 B9 C3 1A 00 00 mov r9d, 1AC3h
- */
- {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x75, 0x00, 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00},
- /*
- * Windows 10 April 2018
- * 49 8B 87 58 40 00 00 mov rax, [r15+4058h]
- * 39 98 C0 53 00 00 cmp [rax+53C0h], ebx
- * 75 12 jnz short loc_1800A7FEC
- * 48 8D 15 7F B6 09 00 lea rdx, addrErrorMsg
- *
- * Note: different instructions, last byte skipped due to MAX_CMP_SIZE
- */
- {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x75, 0x00, 0x48, 0x8D, 0x00, 0x00, 0x00, 0x00}};
- // Offset into the code for the numbers we're interested in
- static const uint32_t code_offsets[][2] = {
- {3, 10},
- {3, 9},
- {3, 9},
- };
- #else
- #define MAX_CMP_SIZE 20
- static const uint8_t mask[][MAX_CMP_SIZE] = {
- {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00},
- {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00},
- {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00},
- };
- static const uint8_t mask_cmp[][MAX_CMP_SIZE] = {
- /*
- * Windows 7+
- * 8B 83 E8 29 00 00 mov eax, [ebx+29E8h]
- * 39 B0 80 4B 00 00 cmp [eax+4B80h], esi
- * 75 14 jnz short loc_754CD9E1
- * 68 F9 19 00 00 push 19F9h
- */
- {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x75, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00},
- /* Windows 10 Creator's Update+
- * 8B 86 F8 2B 00 00 mov eax, [esi+2BF8h]
- * 83 B8 00 4D 00 00 00 cmp dword ptr [eax+4D00h], 0
- * 75 0F jnz short loc_100D793C
- * 68 C3 1A 00 00 push 1AC3h
- */
- {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x83, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x75, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00},
- /*
- * Windows 10 April 2018 Update
- * 8B 86 68 2B 00 00 mov eax, [esi+2B68h]
- * 83 B8 F4 4D 00 00 00 cmp dword ptr [eax+4DF4h], 0
- * 75 0F jnz short loc_100D9A9C
- * BA 08 71 01 10 mov edx, offset errMsg
- */
- {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x83, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x75, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00}};
- // Offset into the code for the numbers we're interested in
- static const uint32_t code_offsets[][2] = {
- {2, 8},
- {2, 8},
- {2, 8},
- };
- #endif
- #define MAX_FUNC_SCAN_BYTES 200
- static inline bool pattern_matches(uint8_t *byte, uint32_t *offset1,
- uint32_t *offset2)
- {
- for (size_t j = 0; j < sizeof(mask) / sizeof(mask[0]); j++) {
- for (size_t i = 0; i < MAX_CMP_SIZE; i++) {
- if ((byte[i] & mask[j][i]) != mask_cmp[j][i])
- goto next_signature;
- }
- *offset1 = code_offsets[j][0];
- *offset2 = code_offsets[j][1];
- return true;
- next_signature:;
- }
- return false;
- }
- void get_d3d9_offsets(struct d3d9_offsets *offsets)
- {
- d3d9_info info = {};
- bool success = d3d9_init(info);
- if (success) {
- uint8_t **vt = *(uint8_t ***)info.device;
- uint8_t *crr = vt[125];
- offsets->present = vtable_offset(info.module, info.device, 17);
- offsets->present_ex =
- vtable_offset(info.module, info.device, 121);
- offsets->present_swap =
- vtable_offset(info.module, info.swap, 3);
- uint32_t offset1, offset2;
- for (size_t i = 0; i < MAX_FUNC_SCAN_BYTES; i++) {
- if (pattern_matches(&crr[i], &offset1, &offset2)) {
- #define get_offset(x) *(uint32_t *)&crr[i + x]
- uint32_t off1 = get_offset(offset1);
- uint32_t off2 = get_offset(offset2);
- /* check to make sure offsets are within
- * expected values */
- if (off1 > 0xFFFF || off2 > 0xFFFF)
- break;
- /* check to make sure offsets actually point
- * toward expected data */
- #ifdef _MSC_VER
- __try {
- uint8_t *ptr = (uint8_t *)(info.device);
- uint8_t *d3d9_ptr =
- *(uint8_t **)(ptr + off1);
- if (d3d9_ptr != (uint8_t *)info.d3d9ex)
- break;
- BOOL &is_d3d9ex =
- *(BOOL *)(d3d9_ptr + off2);
- if (is_d3d9ex != TRUE)
- break;
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- break;
- }
- #endif
- offsets->d3d9_clsoff = off1;
- offsets->is_d3d9ex_clsoff = off2;
- break;
- }
- }
- }
- d3d9_free(info);
- }
|