Всем привет. Есть dll, в которой хукаются интерфейсы DirectX, и она у многих работает нормально. Не уверен на сто процентов, но видимо проблемы у тех у кого XP SP3. У них вызов функций видимо зацикливается, то есть в месте где должна вызываться оригинальная функция, вызывается хуканная. Может кто подскажет по этой проблеме?
Показываю то что заслуживает показа, так как в других частях вода, не имеющая отношения к сабжу. Так С++. Это функция ставит хук на CreateDevice. Код (Text): void HookeCreateDevice(IDirect3D9 *pD3D9) { DWORD oldProtect; DWORD vtbl; _asm { mov eax, pD3D9 mov eax, [eax] mov vtbl, eax lea edx, CreateDeviceOrg //Записываем оригинальный адрес метода mov ecx, [eax + 64] mov [edx], ecx } VirtualProtect((LPVOID)vtbl, 72, PAGE_READWRITE, &oldProtect); _asm { lea edx, CreateDeviceNew //Новый адрес mov eax, vtbl mov [eax + 64], edx } VirtualProtect((LPVOID)vtbl, 72, oldProtect, &oldProtect); } Это экспортируемая функция Direct3DCreate9, делает предварительную инициализацию и вызывает HookeCreateDevice. Сделана проверка от повторного вызова и хука. Код (Text): IDirect3D9 *WINAPI Direct3DCreate9(UINT SDKVersion) { if (!Direct3DCreate9Org) Direct3DCreate9Org = GetDirect3DCreate9(); static bool bHook = false; if (Direct3DCreate9Org) { IDirect3D9* pD3D9 = Direct3DCreate9Org(SDKVersion); if (!bHook) { HookCreateDevice(pD3D9); bHook = true; } return pD3D9; } return NULL; } А это собственно сама CreateDevice, привожу участок заслуживающий хоть какого-то внимания. Код (Text): HRESULT WINAPI CreateDeviceNew(IDirect3D9* pD3D9, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) { IDirect3DDevice9* pDevice; HRESULT hr = CreateDeviceOrg(pD3D9, Adapter, DeviceType, hFocusWindow BehaviorFlags, pPresentationParameters, &pDevice); //Тут ещё кое-что есть, но это не интересно. } У меня и у тех, у кого sp2 работает как и надо. Вызывается два раза (так делается в той проге для которой это писано) Direct3DCreate9, в первый раз вызывается HookeCreateDevice, потом нет. Затем из проги приходит один вызов CreateDeviceNew и в нём благополучно вызывается оригинальный метод - CreateDeviceOrg. Так вот нашлось два человека с sp3 (может совпадение, а может и нет), у которых это работает более чем загадочно. По логу видно, что адреса CreateDeviceOrg и CreateDeviceNew перед вызовом CreateDeviceOrg отличны и корректны (они такими были когда хукались). Но и так же видно, что после вызова CreateDeviceOrg на самом деле управление снова приходит в CreateDeviceNew, и второй раз в ней вызывается CreateDeviceOrg, и управление передаётся оригинальной, директовой функции. После того как она отработала, соответственно два раза выходим из CreateDeviceNew. Это показывают логи, и не верить им не приходится. Не понятно. Дальше ещё веселее, есть другие версии той проги для которой это писалось, так вот по логу, управление в Direct3DCreate9 не передаётся вообще, а только в саму DllMain. Хотя как уже писал, и у меня и многих всё работает как надо. Если с первой траблой ещё можно справится, контролируя повторный вход в CreateDeviceNew(хотя такое поведение более чем загадочно). То что делать когда не вызывается Direct3DCreate9, вообще не понятно. Многопоточность по логам не юзается. Может на sp3 какая хитрож.... защита есть? Советуйте, если что спрошу у тех у кого это проявляется, и проверю что необходимо.
Правка vtbl глупо, сплайсить нужно прямо direct3d*.dll У DX есть такой трабл как обнуление всего vtbl до оригинального прямо во время работы программы (влияют вызовы каких то пары-тройки методов, не помню уже каких)
keYMax Может и так, но тут обратная картина, вызов оригинального метода, не через vtbl, приводит к вызову похученой функции. То есть как бы vtbl сама сплайсит. -) Да и не хочется сплайсить, траблы с многопоточностью, хотя в данном случае этого и нет.
Посетила бредовая мысль, что CreateDevice может вызывать себя же, но только с другими параметрами. То есть я вызываю оригинальную функцию, а она вызывает себя же через vtbl со спец параметрами, и следовательно опять получает управление мой хук. Бред конечно, но другое на ум не приходит. Сегодня сделаю логирование параметров CreateDevice, и отправлю для теста людям.
Похоже мои предположения оправдались, происходит повторный вызов CreateDevice из самой себя. Вставил проверку на повторный хук vtbl и всё благополучно разрулилось. Странно в этой заплатке директ работает. keYMax Я так и не понял, откуда может взяться восстановление vtbl? Звучит странно, кто его будет восстанавливать?
Когда я писал аналог Fraps я его мучал в ольке, решил сделать не как он, а правкой vtbl. Так вот, периодически мои функции назначеные в vtbl просто переставали вызваться. Просмотр в отладчике показал что память по которой лежит вся vtbl, например, на Direct3DDevice после вызова некоторых методов просто обновляется до первоначального значения. Методом опытного тыка я попытался как-то обойти это дело, но в конечном итоге получил только гемор. поэтому проще сплайсить прямо в dll первые 5 байт нужного метода и все. Такие вот дела.