Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[54.224.52.210] |
|
Сообщ.
#1
,
|
|
|
Всем привет,
Пытаюсь подменить информацию о видеокарте, но столкнулся с проблемой. Так данные о видеокарте (GPU) в большинстве случаев тянутся посредством Win32_VideoController, то выглядит это все как-то так: IWbemServices* services = NULL; ... IEnumWbemClassObject* instanceEnum = NULL; services->CreateInstanceEnum( _bstr_t("Win32_VideoController"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &instanceEnum); Т.е. создается объект класса IWbemServices (допустим *services), а далее вызывается метод services->CreateInstanceEnum("Win32_VideoController"..., &instanceEnum); и данные записываются в заранее созданный объект IEnumWbemClassObject (в данном случаем это instanceEnum). Используя MS Detours 3.0 пробовал перехватить IEnumWbemClassObject::CreateInstanceEnum следующим образом: Попытка получить указатель: typedef HRESULT(WINAPI IWbemServices::*tm_CreateInstanceEnum) (const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum); tm_CreateInstanceEnum True_CreateInstanceEnum = &IWbemServices::CreateInstanceEnum; Моя функция: __declspec(dllexport) HRESULT WINAPI Hooked_CreateInstanceEnum(const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum) { MessageBox(0, L" Hooked!!!", L"Oh yeah, you did it !", MB_OK); //return True_CreateInstanceEnum(strClass, lFlags, pCtx, ppEnum); // я честно хз почему так, но это не верно return 0; } Впихон: BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { if (dwReason == DLL_PROCESS_ATTACH) { DetourRestoreAfterWith(); DetourTransactionBegin(); DetourAttach((PVOID*)&True_CreateInstanceEnum, Hooked_CreateInstanceEnum); DetourTransactionCommit(); } else if (dwReason == DLL_PROCESS_DETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach((PVOID*)&True_CreateInstanceEnum, Hooked_CreateInstanceEnum); DetourTransactionCommit(); } { Все это прекрасно компилируется в DLL, но ничего не перехватывается. Хотя по идее это все должно было работать так, что при хуке CreateInstanceEnum у меня бы появлялся MessageBox. Но, увы сия чуда не происходит Как правильно перехватить? |
Сообщ.
#2
,
|
|
|
Подсказали мне значит вешать хук на метод Get. Получился такой код:
#include "stdafx.h" #pragma comment (lib, "detours.lib") typedef HRESULT (WINAPI * True_GetFn)(LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor); True_GetFn p_Get = nullptr; __declspec(dllexport) HRESULT WINAPI Hooked_Get(LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor) { if (wcsstr(wszName, L"VideoProcessor") != NULL || wcsstr(wszName, L"Name") != NULL || wcsstr(wszName, L"AdapterCompatibility") != NULL || wcsstr(wszName, L"SystemName") != NULL) { pVal->vt = VT_BSTR; V_BSTR(pVal) = L"NO_DATA"; } else if (wcsstr(wszName, L"AdapterRAM") != NULL) { pVal->vt = VT_UI4; V_BSTR(pVal) = L"0"; } return p_Get(wszName, lFlags, pVal, pvtType, plFlavor); } PVOID SetDetour(PVOID* ppTarget, PVOID pHandler) { if (DetourTransactionBegin() != NO_ERROR) return FALSE; if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) { DetourTransactionCommit(); return NULL; } PDETOUR_TRAMPOLINE pTrampoline = NULL; if (DetourAttachEx(ppTarget, pHandler, &pTrampoline, NULL, NULL) != NO_ERROR) { DetourTransactionCommit(); return NULL; } if (DetourTransactionCommit() != NO_ERROR) { DetourTransactionAbort(); return NULL; } return pTrampoline; } BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { HMODULE hLib = LoadLibraryA("fastprox.dll"); if (hLib) { p_Get = (True_GetFn)GetProcAddress(hLib, "?Get@CWbemObject@@UAGJPBGJPAUtagVARIANT@@PAJ2@Z"); if (p_Get) { if (dwReason == DLL_PROCESS_ATTACH) { SetDetour((PVOID*)&p_Get, Hooked_Get); } else if (dwReason == DLL_PROCESS_DETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach((PVOID*)&p_Get, Hooked_Get); DetourTransactionCommit(); } } } return TRUE; } Однако, когда с помощью withdll.exe запускаю dxdiag.exe совместно с моей DLL, то получаю ошибку: Первое окошко: Прикреплённая картинка
Второе - ошибка: Прикреплённая картинка
Кто знает в чем проблема? |
Сообщ.
#3
,
|
|
|
Такое ощущение, что тут нет знатоков
В общем имею такой код: Хедер и определение указателя: #include "stdafx.h" #pragma comment (lib, "detours.lib") typedef HRESULT (WINAPI * True_GetFn)(LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor); True_GetFn p_Get = nullptr; Моя функция: __declspec(dllexport) HRESULT WINAPI Hooked_Get(LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor) { if (wcsstr(wszName, L"VideoProcessor") != NULL || wcsstr(wszName, L"Name") != NULL || wcsstr(wszName, L"AdapterCompatibility") != NULL || wcsstr(wszName, L"SystemName") != NULL) { pVal->vt = VT_BSTR; V_BSTR(pVal) = L"NO_DATA"; } else if (wcsstr(wszName, L"AdapterRAM") != NULL) { pVal->vt = VT_UI4; V_BSTR(pVal) = L"0"; } return p_Get(wszName, lFlags, pVal, pvtType, plFlavor); } Функция SetDetour: PVOID SetDetour(PVOID* ppTarget, PVOID pHandler) // Thank you, IChooseYou. { if (DetourTransactionBegin() != NO_ERROR) return FALSE; if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) { DetourTransactionCommit(); return NULL; } PDETOUR_TRAMPOLINE pTrampoline = NULL; if (DetourAttachEx(ppTarget, pHandler, &pTrampoline, NULL, NULL) != NO_ERROR) { DetourTransactionCommit(); return NULL; } if (DetourTransactionCommit() != NO_ERROR) { DetourTransactionAbort(); return NULL; } return pTrampoline; } DllMain: BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { HMODULE hLib = GetModuleHandle(L"fastprox.dll"); if (hLib) { p_Get = (True_GetFn)GetProcAddress(hLib, "?Get@CWbemObject@@UAGJPBGJPAUtagVARIANT@@PAJ2@Z"); if (p_Get) { SetDetour(&(PVOID&)p_Get, Hooked_Get); } } return TRUE; } Но он все равно не работает. Запускаемое приложение dxdiag.exe выдает ошибку. Прикреплённая картинка
Прикреплённая картинка
Прикреплённая картинка
Выдвиньте хотя бы какую-то свою версию почему так происходит. |
Сообщ.
#4
,
|
|
|
Ну вы хоть опосля SetDetour проверьте: всё ли там норм произошло; а то вдруг NULL вертухается, а вы забиваете на сие, а?..
|
Сообщ.
#5
,
|
|
|
Цитата Славян @ Ну вы хоть опосля SetDetour проверьте: всё ли там норм произошло; а то вдруг NULL вертухается, а вы забиваете на сие, а?.. Так вроде проверял, все четко. Ткните плз я не вижу этот изъян |
Сообщ.
#6
,
|
|
|
Да мож и нет никакого изъяна. Просто в вашей SetDetour происходят же вызовы с проверками, так что вдруг какой и завершается ошибкой, но в DllMain на это код забивает.
|
Сообщ.
#7
,
|
|
|
Цитата Mr.Newbie @ Выдвиньте хотя бы какую-то свою версию почему так происходит. Вот версия: Как я понял, ты пытаешься перехватить функцию класса. У таких функций есть дополнительный параметр - this. Он автоматически добавляется компилятором. Фактически, протопип функции не такой, как ты используешь. ----- Совершенно очевидно, что надо делать. Надо пытаться трассировать твои опусы отладчиком уровня ядра. |
Сообщ.
#8
,
|
|
|
Цитата ЫукпШ @ У таких функций есть дополнительный параметр - this. Он автоматически добавляется компилятором. Фактически, протопип функции не такой, как ты используешь. Почему не такой ? И откуда доп.параметр this ? Вот что написано на cppreference.com: Цитата Pointers to member functions A pointer to non-static member function f which is a member of class C can be initialized with the expression &C::f exactly. Expressions such as &(C::f) or &f inside C's member function do not form pointers to member functions. Such pointer may be used as the right-hand operand of the pointer-to-member access operators operator.* and operator->*. The resulting expression can be used only as the left-hand operand of a function-call operator: struct C { void f(int n) { std::cout << n << '\n'; } }; int main() { void (C::* p)(int) = &C::f; // pointer to member function f of class C C c; (c.*p)(1); // prints 1 C* cp = &c; (cp->*p)(2); // prints 2 } И тут нет никакого доп.параметра. |
Сообщ.
#9
,
|
|
|
Цитата Mr.Newbie @ Почему не такой ? И откуда доп.параметр this ? Каждая функция используется для всех экземпляров класса. Поэтому, чтобы отличить один экземпляр класса от другого, не статической функции передаётся указатель на структуру данных класса. Лекция |
Сообщ.
#10
,
|
|
|
Цитата Mr.Newbie @ И тут нет никакого доп.параметра "Ты суслика видишь? И я не вижу. А он есть" (С) В любую не статическую функцию класса первым неявным аргументом передается параметр this - указатель на экземпляр\объект класса, для которого вызывается функция. Т.е. для объекта С *с запись c->f(i) это лишь синтаксическая условность ("сахар"), за которой в действительности скрывается вызов функции C::f(c,i) |
Сообщ.
#11
,
|
|
|
Так, окей. Убедили что суслик есть.
Добавил первым параметром, но ведь... typedef HRESULT (WINAPI * True_GetFn)(void*, LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor); .... __declspec(dllexport) HRESULT WINAPI Hooked_Get(void* suslik,LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor) { .... всеравно не работает |
Сообщ.
#12
,
|
|
|
Цитата Mr.Newbie @ Так, окей. Убедили что суслик есть. Добавил первым параметром, но ведь... Доказательство как бы намекает, что суслик может быть не один. Выход один - надо отлаживаться. --- Есть ли уверенность, что "Calling Conventions" твоих процедур и вызываемой - совпадают ? |
Сообщ.
#13
,
|
|
|
Calling Conventions - совпадают. У меня такое предчувствие, что я как-то неправильно использую DetourAttachEx/DetourAttach. Перерыл буржнет и нашел посты, правда датированные лохматыми годами и используется там версия detour 1.5, так вот там почти все как у меня только вместо DetourAttachEx/DetourAttach - прописана функция DetourFunction и результат его работы присваивается (в данном случаем у меня) к p_Get
|
Сообщ.
#14
,
|
|
|
Цитата Mr.Newbie @ Это не имеет значения. this может передаваться в регистре. Calling Conventions - совпадают. |
Сообщ.
#15
,
|
|
|
Пришел к такому решению, оно наполовину рабочее... в общем вот код:
typedef HRESULT(__stdcall *IWbemClassObject_Get)(void *__this, LPCWSTR, LONG, VARIANT*, CIMTYPE*, LONG*); IWbemClassObject_Get True_Get; __declspec(dllexport) HRESULT __stdcall Hooked_Get(void *__this, LPCWSTR wszName, LONG lFlags, VARIANT *pVal, CIMTYPE *pvtType, LONG *plFlavor) { printf("wszName: %S\n", wszName); std::cout << "lFlags:" << lFlags << std::endl; std::cout << "pVal:" << pVal << std::endl; std::cout << "pvtType:" << pvtType << std::endl; std::cout << "plFlavor:" << plFlavor << std::endl; return True_Get(__this, wszName, lFlags, pVal, pvtType, plFlavor); } template<typename T> void HookFunction(const char *module, char *signature, T &fn_real, PVOID fn_mine) { HookFunction<T>(DetourFindFunction(module, signature), fn_real, fn_mine); } template<typename T> void HookFunction(DWORD address, T &fn_real, PVOID fn_mine) { HookFunction<T>(reinterpret_cast<PVOID>(address), fn_real, fn_mine); } template<typename T> void HookFunction(PVOID target, T &fn_real, PVOID fn_mine) { fn_real = reinterpret_cast<T>(target); HookFunction<T>(fn_real, fn_mine); } template<typename T> void HookFunction(T &fn_real, PVOID fn_mine) { DetourAttach(&(PVOID&)fn_real, fn_mine); } void ApplyHooks(LPVOID address) //Function address 0x6FD9B723 { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); HookFunction<IWbemClassObject_Get>((FARPROC)address, True_Get, Hooked_Get); DetourTransactionCommit(); } BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { AllocConsole(); freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); HMODULE hLib = GetModuleHandle(L"fastprox.dll"); if (hLib) { FARPROC hAdd = GetProcAddress(hLib, "?Get@CWbemObject@@UAGJPBGJPAUtagVARIANT@@PAJ2@Z"); if (hAdd) { if (dwReason == DLL_THREAD_ATTACH) { std::cout << "DLL_THREAD_ATTACH" << std::endl; DisableThreadLibraryCalls(hinst); // Почему-то если его убрать, то через какой-то время dxdiag.exe выбрасывает ошибку CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ApplyHooks, hAdd, 0, 0); } } } return TRUE; } И он мне выдает вот такой списочек в консоли: Прикреплённая картинка
Но есть два непонятных для меня момент - 1). Без DisableThreadLibraryCalls(hinst) в DllMain(...) через какое-то время dxdiag.exe выбивает ошибку, хотя какие-то данные в консоли отобразились. 2). Потерпел фиаско при попытке изменить какие-либо значения, в dxdiag.exe они не поменялись. Предполагаю, что это как-то связано с DisableThreadLibraryCalls... но см.п.1 Пример кода того как пытался поменять значения у строковых переменных. Причем если после изменения вывести в консоль pVal, то оно будет изменено на "NO_DATA", а в dxdiag.exe изменениями и не пахнет. pVal->vt = VT_BSTR; V_BSTR(pVal) = L"NO_DATA"; |
Сообщ.
#16
,
|
|
|
Цитата Qraizer @ Цитата Mr.Newbie @ Это не имеет значения. this может передаваться в регистре.Calling Conventions - совпадают. Если это проблема оптимизации, её можно прекратить. Как-то делал так: // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #pragma warning (push) #pragma warning (disable:4700) #pragma optimize ("", off) // .......................................................................... BOOL WINAPI ... (...) { ... } // .......................................................................... #pragma optimize ("", on) #pragma warning (pop) Добавлено Цитата Mr.Newbie @ Пришел к такому решению, оно наполовину рабочее... Значение "this" тоже проверь. Это просто указатель на объект. Например: pObject->SomeRoutine(...); -> pObject это и есть "this". |
Сообщ.
#17
,
|
|
|
Цитата Qraizer @ Цитата Mr.Newbie @ Calling Conventions - совпадают. Это не имеет значения. this может передаваться в регистре. Не надо чересчур обобщать, т.к. в данном случае речь идет о COM-интерфейсе WinAPI, поэтому параметр this передается не как-то особо\вычурно, а "на общих основаниях" в соответствии с конвенцией WINAPI (точнее говоря, safecall, что в данном случае не имеет значения, т.к. сам прототип функции соответствует этой конвенции). |
Сообщ.
#18
,
|
|
|
COM-интерфейс может по-разному быть реализован в соответствие с safecall, без оного или ещё каким причинам. Маршалинг никто не отменял. Это во-первых. А во-вторых, не вижу препятствий к тому, чтобы указатель на функцию заменить обратно на указатель на метод, как было в первом посту.
|
Сообщ.
#19
,
|
|
|
Цитата ЫукпШ @ Доказательство как бы намекает, что суслик может быть не один Второй суслик наверняка прячется в вольном обращении с V_BSTR(pVal) = L"NO_DATA"; Это же out-параметр COM-интерфейса, который должен подчиняться установленным правилам, а именно BSTR в pVal должна выделяться\очищаться системными функциями SysAllocString\SysFreeString (и т.п.). Если же ты просто присваиваешь значению pVal->bstrVal указатель на "неизвестно что", то впоследствии где-то возникает ошибка при попытке очистки этой строки через SysFreeString или VariantClear. PS: Поэтому и "наполовину рабочее" решение #15 не выдает ошибки, т.к. ты не изменяешь своим топорным методом pVal->bstrVal Цитата Mr.Newbie @ Пример кода того как пытался поменять значения у строковых переменных. Причем если после изменения вывести в консоль pVal, то оно будет изменено на "NO_DATA", а в dxdiag.exe изменениями и не пахнет. С чего им "пахнуть", если судя по #2 и #3 ты изменяешь pVal до вызова оригинальной функции Get, а не после нее. Это же out-параметр этой функции, соотв-но несмотря на переданное ей значение (судя по "списочку в консоли" туда всегда передается пустая строка), она всегда его переписывает своим значением. Добавлено Qraizer Ты опять обобщаешь и пытаешься найти суслика там, где его действительно нет Автор же привел в #15 "наполовину рабочее решение" (без манипуляций с pVal), которое работает без ошибок. Значит конвенция вызова на уровне ABI реализована верно, и соотв-но великий и всемогущий маршалинг (в данном случае) "тихо курит в сторонке" |
Сообщ.
#20
,
|
|
|
До следующего креативного обновления? Ну ок.
|
Сообщ.
#21
,
|
|
|
Цитата Это же out-параметр COM-интерфейса, который должен подчиняться установленным правилам, а именно BSTR в pVal должна выделяться\очищаться системными функциями SysAllocString\SysFreeString (и т.п.). Через SysAllocString\SysFreeString делал, толку ноль. Цитата С чего им "пахнуть", если судя по #2 и #3 ты изменяешь pVal до вызова оригинальной функции Get, а не после нее. Это же out-параметр этой функции, соотв-но несмотря на переданное ей значение (судя по "списочку в консоли" туда всегда передается пустая строка), она всегда его переписывает своим значением. Я думал вызов происходит не до и не после, а во время и вместо оригинальной Get подсовывается моя ф-я с измененным значением out-параметра. Так мне что искать еще сусликов или не ?) |
Сообщ.
#22
,
|
|
|
Цитата Qraizer @ До следующего креативного обновления? Ну ок. Ты что предлагаешь? Цитата Qraizer @ указатель на функцию заменить обратно на указатель на метод, как было в первом посту. Развей дальше эту идею. Или ты не знаешь, что указатель на метод (member function) - это в общем случае не просто указатель на функцию (о чём регулярно вопят в разделе "чистого С++"), и что внутреннее представление этих указателей является implementation specific и соотв-но может быть разным в разных компиляторах? Ты уверен, что во всех компиляторах указатель на виртуальный метод (какими являются все методы COM-интерфейса) должен быть именно указателем на саму функцию, а к примеру, не комбинацией указателя на vtable и смещения на указатель соответствующего метода в этой таблице? Мы же получаем этот указатель не для "внутреннего использования", а чтобы передать его в DetourAttach, которая принимает только обычные указатели и ес-но "ругается" на указатели на методы. А тайпкастить указатель на метод к void* - это либо верх наивности\глупости, либо "тайное" знание того, что в данном конкретном случае это прокатит и не приведет к AV или другим ошибкам. Спрашивается, чем это тайное знание лучше документированного (или полу-документированного) знания о том, что первым параметром в методы COM-интерфейса передается указатель на сам интерфейсный объект? Если можно реализовать COM-интерфейс с помощью абстрактного класса со стандартной конвенцией вызова в любом С++ компиляторе, то это означает, что параметр this должен передаваться также "стандартно" наравне с другими параметрами, а не как-то особо (через какой-то особый регистр - иначе это должно было было быть как-то особо документировано в WinAPI). Добавлено Цитата Mr.Newbie @ Я думал вызов происходит не до и не после, а во время и вместо оригинальной Get подсовывается моя ф-я с измененным значением out-параметра Сам понял, что сказал? Да, вместо оригинальной Get "подсовывается" твоя. Но ты же конце своей Get вызываешь оригинальную True_Get, которая изменят значение pVal, затирая все твои "художества". Соотв-но твоя Get возвращает наружу то, что выдала в pVal True_Get. Нужно либо вызывать True_Get по условию if ... else, либо изменять pVal не до, а после вызова True_Get. Цитата Mr.Newbie @ Через SysAllocString\SysFreeString делал, толку ноль. Может ты это до первого this-суслика делал? Покажи реальный код |
Сообщ.
#23
,
|
|
|
Цитата Развей дальше эту идею. Или ты не знаешь, что указатель на метод (member function) - это в общем случае не просто указатель на функцию (о чём регулярно вопят в разделе "чистого С++"), и что внутреннее представление этих указателей является implementation specific и соотв-но может быть разным в разных компиляторах? Ты уверен, что во всех компиляторах указатель на виртуальный метод (какими являются все методы COM-интерфейса) должен быть именно указателем на саму функцию, а к примеру, не комбинацией указателя на vtable и смещения на указатель соответствующего метода в этой таблице? Мы же получаем этот указатель не для "внутреннего использования", а чтобы передать его в DetourAttach, которая принимает только обычные указатели и ес-но "ругается" на указатели на методы. А тайпкастить указатель на метод к void* - это либо верх наивности\глупости, либо "тайное" знание того, что в данном конкретном случае это прокатит и не приведет к AV или другим ошибкам. Спрашивается, чем это тайное знание лучше документированного (или полу-документированного) знания о том, что первым параметром в методы COM-интерфейса передается указатель на сам интерфейсный объект? Если можно реализовать COM-интерфейс с помощью абстрактного класса со стандартной конвенцией вызова в любом С++ компиляторе, то это означает, что параметр this должен передаваться также "стандартно" наравне с другими параметрами, а не как-то особо (через какой-то особый регистр - иначе это должно было было быть как-то особо документировано в WinAPI). Цитата Нужно либо вызывать True_Get по условию if ... else, либо изменять pVal не до, а после вызова True_Get. После вызова True_Get ?! Это как ?! Цитата Автор же привел в #15 "наполовину рабочее решение" (без манипуляций с pVal), которое работает без ошибок. Не совсем.. если убрать DisableThreadLibraryCalls и влепить ApplyHooks напрямую без CreateThread, то через какое-то время dxdiag валится, при этом в консоле видно как перед этим он сотню раз раз обращается к Get. Добавлено И еще один странный момент, вывел в консоль &fn_real ф-и HookFunction и заметил как кое где проскакивают пустые значения. Такое возможно? и может ли это быть причиной вылета с ошибкой ? |
Сообщ.
#24
,
|
|
|
leo, давай ты не будешь мне читать лекции по Плюсам, ок? Если ты не понял, я именно поэтому и встрял в эту высокоэлитную беседу. Вместо демонстрации собственных навыков логического мышления, в наличии которых нет ничего плохого, когда они к месту, я первый пост читал.
|
Сообщ.
#25
,
|
|
|
Цитата Mr.Newbie @ После вызова True_Get ?! Это как ?! Ты прикидываешься или издеваешься? HRESULT res = True_Get(...); if (...) { //проверка res, wszName и pVal ... //если нужно, меняем pVal и\или res } return res; Цитата Mr.Newbie @ Не совсем.. если убрать DisableThreadLibraryCalls и влепить ApplyHooks напрямую без CreateThread, то через какое-то время dxdiag валится Потому, что у тебя суслик на суслике сидит и сусликом погоняет. В #2 у тебя было правильно - хук\перехват устанавливался только один раз при DLL_PROCESS_ATTACH, но из-за ошибок с this и pVal ничего не работало. Затем, начиная с #3 ты зачем-то убрал условие DLL_PROCESS_ATTACH, и соотв-но твой код перехвата стал срабатывать множество раз при создании (а в #3 и при завершении) потоков приложения. Поэтому тебе пришлось добавить DisableThreadLibraryCalls, чтобы запретить повторные срабатывания кроме первого. Резюме: нужно исправить свои собственные баги (с неучетом this, с неправильной установкой pVal и т.п.) и вернуться к стандартной схеме установки хука\перехвата функции с помощью Detours (с учетом многопоточности приложения). Как правильно устанавливать этот перехват - это отдельный вопрос, который наверняка можно найти в документации и\или примерах использования Detours. |
Сообщ.
#26
,
|
|
|
Цитата Qraizer @ leo, давай ты не будешь мне читать лекции по Плюсам, ок? 1) И не думал этого делать. В Плюсах я "не в зуб ногой", о чем уже сотню раз говорил. Поэтому в ваши "чистые С++" дела принципиально не лезу. 2) В данном случае речь идет не о Плюсах, а о низкоуровневом перехвате функций с помощью DetoursAttach. Чем тут могут помочь ("высокоуровневые" implementation specific) указатели на методы, я искренне не понимаю. Если ты знаешь - поделись. 3) Какое отношение к Плюсам имеет способ передачи указателя this в технологии COM, я тоже не понимаю. COM это универсальная технология, которую можно использовать в разных ЯП. Если я вижу\знаю как передается this при вызове метода COM-интерфейса в своем "родном" дельфи\паскале, то почему он должен или может передаваться иначе в MSVC (managed code ЯП не в счет)? Да, маршаллинг никто не отменял, но для системных WinAPI интерфейсов этот маршаллинг (если он используется) должен быть зашит в самих системных dll, которые представляют эти интерфейсы. Т.е. dll должна представлять пользователям стандартный ABI интерфейс вызова методов, а то, куда она его дальше транслирует и как-то маршаллит, это уже её личное\приватное дело. Или я не прав? |
Сообщ.
#27
,
|
|
|
Цитата leo @ Поэтому в ваши "чистые С++" дела принципиально не лезу. Вступай в нашу банду, leo. - Ловля сусликов с любой шкуркой. - Самые брутальные дискуссии, плавно переходящие "в зуб ногой". - Широкие возможности влезать в "чиста С++". и множество других бонусов и удовольствий, не доступных в Дельфи ! |
Сообщ.
#28
,
|
|
|
Цитата Ты прикидываешься или издеваешься? Мозг отказал Цитата В #2 у тебя было правильно - хук\перехват устанавливался только один раз при DLL_PROCESS_ATTACH, но из-за ошибок с this и pVal ничего не работало. Затем, начиная с #3 ты зачем-то убрал условие DLL_PROCESS_ATTACH, и соотв-но твой код перехвата стал срабатывать множество раз при создании (а в #3 и при завершении) потоков приложения. Поэтому тебе пришлось добавить DisableThreadLibraryCalls, чтобы запретить повторные срабатывания кроме первого. Если ставлю DLL_PROCESS_ATTACH, то отрабатывает один раз и все. |
Сообщ.
#29
,
|
|
|
Цитата Mr.Newbie @ Если ставлю DLL_PROCESS_ATTACH, то отрабатывает один раз и все Это может означать то, что приложение грузит dll динамически и выгружает ее после использования. Поэтому и твой однократный хук перестает работать, и "кое где проскакивают пустые значения" fn_real, если ты пытаешься ставить перехват в момент, когда dll не загружена. Выход из этой ситуации - обеспечить загрузку этой dll самому. Можно либо создать ссылку на соответствующий интерфейсный объект и хранить ее в глоб.\стат. переменной до выгрузки dll, либо просто вызвать LoadLibrary. То и другое лучше делать в отдельном потоке ApplyHooks, т.к. грузить либы в DllMain не рекомендуется. Кстати, в этом же потоке можно организовать периодическую проверку загрузки dll и установки хука по таймеру на случай, если он по какой-то (очередной непонятной) причине слетит. |
Сообщ.
#30
,
|
|
|
Цитата leo @ т.к. грузить либы в DllMain не рекомендуется В DllMain вообще ничего делать не рекомендуется, кроме получения статуса загрузки/выгрузки и выделения/освобождения динамической локальной памяти |