d3d9-offsets.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <d3d9.h>
  5. #include "get-graphics-offsets.h"
  6. typedef HRESULT (WINAPI *d3d9createex_t)(UINT, IDirect3D9Ex**);
  7. struct d3d9_info {
  8. HMODULE module;
  9. HWND hwnd;
  10. IDirect3D9Ex *d3d9ex;
  11. IDirect3DDevice9Ex *device;
  12. IDirect3DSwapChain9 *swap;
  13. };
  14. static inline bool d3d9_init(d3d9_info &info)
  15. {
  16. d3d9createex_t create;
  17. HRESULT hr;
  18. info.hwnd = CreateWindowExA(0, DUMMY_WNDCLASS, "d3d9 get-offset window",
  19. WS_POPUP, 0, 0, 1, 1, nullptr, nullptr,
  20. GetModuleHandleA(nullptr), nullptr);
  21. if (!info.hwnd) {
  22. return false;
  23. }
  24. info.module = LoadLibraryA("d3d9.dll");
  25. if (!info.module) {
  26. return false;
  27. }
  28. create = (d3d9createex_t)GetProcAddress(info.module,
  29. "Direct3DCreate9Ex");
  30. if (!create) {
  31. return false;
  32. }
  33. hr = create(D3D_SDK_VERSION, &info.d3d9ex);
  34. if (FAILED(hr)) {
  35. return false;
  36. }
  37. D3DPRESENT_PARAMETERS pp = {};
  38. pp.Windowed = true;
  39. pp.SwapEffect = D3DSWAPEFFECT_FLIP;
  40. pp.BackBufferFormat = D3DFMT_A8R8G8B8;
  41. pp.BackBufferWidth = 2;
  42. pp.BackBufferHeight = 2;
  43. pp.BackBufferCount = 1;
  44. pp.hDeviceWindow = info.hwnd;
  45. pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  46. hr = info.d3d9ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
  47. info.hwnd,
  48. D3DCREATE_HARDWARE_VERTEXPROCESSING |
  49. D3DCREATE_NOWINDOWCHANGES, &pp, nullptr, &info.device);
  50. if (FAILED(hr)) {
  51. return false;
  52. }
  53. hr = info.device->GetSwapChain(0, &info.swap);
  54. if (FAILED(hr)) {
  55. return false;
  56. }
  57. return true;
  58. }
  59. static inline void d3d9_free(d3d9_info &info)
  60. {
  61. if (info.swap)
  62. info.swap->Release();
  63. if (info.device)
  64. info.device->Release();
  65. if (info.d3d9ex)
  66. info.d3d9ex->Release();
  67. if (info.hwnd)
  68. DestroyWindow(info.hwnd);
  69. }
  70. #ifdef _WIN64
  71. #define CMP_SIZE 21
  72. static const uint8_t mask[CMP_SIZE] =
  73. {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
  74. 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
  75. 0xFF, 0x00,
  76. 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00};
  77. static const uint8_t mask_cmp[CMP_SIZE] =
  78. {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00,
  79. 0x39, 0x80, 0x00, 0x00, 0x00, 0x00,
  80. 0x75, 0x00,
  81. 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00};
  82. #else
  83. #define CMP_SIZE 19
  84. static const uint8_t mask[CMP_SIZE] =
  85. {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
  86. 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
  87. 0xFF, 0x00,
  88. 0xFF, 0x00, 0x00, 0x00, 0x00};
  89. static const uint8_t mask_cmp[CMP_SIZE] =
  90. {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00,
  91. 0x39, 0x80, 0x00, 0x00, 0x00, 0x00,
  92. 0x75, 0x00,
  93. 0x68, 0x00, 0x00, 0x00, 0x00};
  94. #endif
  95. #define MAX_FUNC_SCAN_BYTES 200
  96. static inline bool pattern_matches(uint8_t *byte)
  97. {
  98. for (size_t i = 0; i < CMP_SIZE; i++) {
  99. if ((byte[i] & mask[i]) != mask_cmp[i])
  100. return false;
  101. }
  102. return true;
  103. }
  104. void get_d3d9_offsets(struct d3d9_offsets *offsets)
  105. {
  106. d3d9_info info = {};
  107. bool success = d3d9_init(info);
  108. if (success) {
  109. uint8_t **vt = *(uint8_t***)info.device;
  110. uint8_t *crr = vt[125];
  111. offsets->present = vtable_offset(info.module, info.device, 17);
  112. offsets->present_ex = vtable_offset(info.module, info.device,
  113. 121);
  114. offsets->present_swap = vtable_offset(info.module, info.swap,
  115. 3);
  116. for (size_t i = 0; i < MAX_FUNC_SCAN_BYTES; i++) {
  117. if (pattern_matches(&crr[i])) {
  118. #define get_offset(x) *(uint32_t*)&crr[i + x]
  119. #ifdef _WIN64
  120. uint32_t off1 = get_offset(3);
  121. uint32_t off2 = get_offset(9);
  122. #else
  123. uint32_t off1 = get_offset(2);
  124. uint32_t off2 = get_offset(8);
  125. #endif
  126. /* check to make sure offsets are within
  127. * expected values */
  128. if (off1 > 0xFFFF || off2 > 0xFFFF)
  129. break;
  130. /* check to make sure offsets actually point
  131. * toward expected data */
  132. #ifdef _MSC_VER
  133. __try {
  134. uint8_t *ptr = (uint8_t*)(info.device);
  135. uint8_t *d3d9_ptr =
  136. *(uint8_t**)(ptr + off1);
  137. if (d3d9_ptr != (uint8_t*)info.d3d9ex)
  138. break;
  139. BOOL &is_d3d9ex =
  140. *(BOOL*)(d3d9_ptr + off2);
  141. if (is_d3d9ex != TRUE)
  142. break;
  143. } __except(EXCEPTION_EXECUTE_HANDLER) {
  144. break;
  145. }
  146. #endif
  147. offsets->d3d9_clsoff = off1;
  148. offsets->is_d3d9ex_clsoff = off2;
  149. break;
  150. }
  151. }
  152. }
  153. d3d9_free(info);
  154. }