На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Подмена данных о GPU с помощью MS Detours 3.0 , Не получается перехватить и подменить IEnumWbemClassObject::CreateInstanceEnum
    Всем привет,
    Пытаюсь подменить информацию о видеокарте, но столкнулся с проблемой. Так данные о видеокарте (GPU) в большинстве случаев тянутся посредством Win32_VideoController, то выглядит это все как-то так:
    ExpandedWrap disabled
      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 следующим образом:

    Попытка получить указатель:
    ExpandedWrap disabled
      typedef HRESULT(WINAPI IWbemServices::*tm_CreateInstanceEnum) (const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum);
      tm_CreateInstanceEnum True_CreateInstanceEnum = &IWbemServices::CreateInstanceEnum;


    Моя функция:
    ExpandedWrap disabled
      __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;
      }


    Впихон:
    ExpandedWrap disabled
      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. Но, увы сия чуда не происходит :oops:

    Как правильно перехватить?
      Подсказали мне значит вешать хук на метод Get. Получился такой код:
      ExpandedWrap disabled
        #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, то получаю ошибку:

      Первое окошко:
      Прикреплённая картинка
      Прикреплённая картинка


      Второе - ошибка:
      Прикреплённая картинка
      Прикреплённая картинка


      Кто знает в чем проблема? :-?
        Такое ощущение, что тут нет знатоков :blink:
        В общем имею такой код:

        Хедер и определение указателя:
        ExpandedWrap disabled
          #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;


        Моя функция:
        ExpandedWrap disabled
          __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:
        ExpandedWrap disabled
          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:
        ExpandedWrap disabled
          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 выдает ошибку.

        Прикреплённая картинка
        Прикреплённая картинка

        Прикреплённая картинка
        Прикреплённая картинка

        Прикреплённая картинка
        Прикреплённая картинка


        Выдвиньте хотя бы какую-то свою версию почему так происходит.
        Сообщение отредактировано: Mr.Newbie‎ -
          Ну вы хоть опосля SetDetour проверьте: всё ли там норм произошло; а то вдруг NULL вертухается, а вы забиваете на сие, а?.. :blush:
            Цитата Славян @
            Ну вы хоть опосля SetDetour проверьте: всё ли там норм произошло; а то вдруг NULL вертухается, а вы забиваете на сие, а?..

            Так вроде проверял, все четко. Ткните плз я не вижу этот изъян
            Сообщение отредактировано: Mr.Newbie‎ -
              Да мож и нет никакого изъяна. Просто в вашей SetDetour происходят же вызовы с проверками, так что вдруг какой и завершается ошибкой, но в DllMain на это код забивает.
                Цитата Mr.Newbie‎ @
                Выдвиньте хотя бы какую-то свою версию почему так происходит.

                Вот версия:
                Как я понял, ты пытаешься перехватить функцию класса.
                У таких функций есть дополнительный параметр - this.
                Он автоматически добавляется компилятором.
                Фактически, протопип функции не такой, как ты используешь.
                -----
                Совершенно очевидно, что надо делать.
                Надо пытаться трассировать твои опусы отладчиком уровня ядра.
                Сообщение отредактировано: ЫукпШ -
                  Цитата ЫукпШ @

                  У таких функций есть дополнительный параметр - 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:
                  ExpandedWrap disabled
                    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
                    }



                  И тут нет никакого доп.параметра.
                    Цитата Mr.Newbie‎ @
                    Почему не такой ? И откуда доп.параметр this ?

                    Каждая функция используется для всех экземпляров класса.
                    Поэтому, чтобы отличить один экземпляр класса от другого, не статической функции
                    передаётся указатель на структуру данных класса.
                    Лекция
                    Сообщение отредактировано: ЫукпШ -
                      Цитата Mr.Newbie‎ @
                      И тут нет никакого доп.параметра

                      "Ты суслика видишь? И я не вижу. А он есть" (С)
                      В любую не статическую функцию класса первым неявным аргументом передается параметр this - указатель на экземпляр\объект класса, для которого вызывается функция. Т.е. для объекта С *с запись c->f(i) это лишь синтаксическая условность ("сахар"), за которой в действительности скрывается вызов функции C::f(c,i)
                        Так, окей. Убедили что суслик есть.
                        Добавил первым параметром, но ведь...

                        ExpandedWrap disabled
                          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)
                          {
                          ....


                        всеравно не работает :-?

                        user posted image
                        Сообщение отредактировано: Mr.Newbie‎ -
                          Цитата Mr.Newbie‎ @
                          Так, окей. Убедили что суслик есть.
                          Добавил первым параметром, но ведь...

                          Доказательство как бы намекает, что суслик может быть не один.
                          Выход один - надо отлаживаться.
                          ---
                          Есть ли уверенность, что "Calling Conventions" твоих процедур и вызываемой - совпадают ?
                            Calling Conventions - совпадают. У меня такое предчувствие, что я как-то неправильно использую DetourAttachEx/DetourAttach. Перерыл буржнет и нашел посты, правда датированные лохматыми годами и используется там версия detour 1.5, так вот там почти все как у меня только вместо DetourAttachEx/DetourAttach - прописана функция DetourFunction и результат его работы присваивается (в данном случаем у меня) к p_Get :blink:
                              Цитата Mr.Newbie‎ @
                              Calling Conventions - совпадают.
                              Это не имеет значения. this может передаваться в регистре.
                                Пришел к такому решению, оно наполовину рабочее... в общем вот код:
                                ExpandedWrap disabled
                                  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 изменениями и не пахнет.
                                ExpandedWrap disabled
                                          pVal->vt = VT_BSTR;
                                          V_BSTR(pVal) = L"NO_DATA";


                                :crazy:
                                Сообщение отредактировано: Mr.Newbie‎ -
                                  Цитата Qraizer @
                                  Цитата Mr.Newbie‎ @
                                  Calling Conventions - совпадают.
                                  Это не имеет значения. this может передаваться в регистре.

                                  Если это проблема оптимизации, её можно прекратить.
                                  Как-то делал так:
                                  ExpandedWrap disabled
                                    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                    #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".
                                    Цитата Qraizer @
                                    Цитата Mr.Newbie‎ @
                                    Calling Conventions - совпадают.

                                    Это не имеет значения. this может передаваться в регистре.

                                    Не надо чересчур обобщать, т.к. в данном случае речь идет о COM-интерфейсе WinAPI, поэтому параметр this передается не как-то особо\вычурно, а "на общих основаниях" в соответствии с конвенцией WINAPI (точнее говоря, safecall, что в данном случае не имеет значения, т.к. сам прототип функции соответствует этой конвенции).
                                      COM-интерфейс может по-разному быть реализован в соответствие с safecall, без оного или ещё каким причинам. Маршалинг никто не отменял. Это во-первых. А во-вторых, не вижу препятствий к тому, чтобы указатель на функцию заменить обратно на указатель на метод, как было в первом посту.
                                        Цитата ЫукпШ @
                                        Доказательство как бы намекает, что суслик может быть не один

                                        :yes:
                                        Второй суслик наверняка прячется в вольном обращении с 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 реализована верно, и соотв-но великий и всемогущий маршалинг (в данном случае) "тихо курит в сторонке" :)
                                          До следующего креативного обновления? Ну ок.
                                            Цитата
                                            Это же out-параметр COM-интерфейса, который должен подчиняться установленным правилам, а именно BSTR в pVal должна выделяться\очищаться системными функциями SysAllocString\SysFreeString (и т.п.).


                                            Через SysAllocString\SysFreeString делал, толку ноль.

                                            Цитата
                                            С чего им "пахнуть", если судя по #2 и #3 ты изменяешь pVal до вызова оригинальной функции Get, а не после нее. Это же out-параметр этой функции, соотв-но несмотря на переданное ей значение (судя по "списочку в консоли" туда всегда передается пустая строка), она всегда его переписывает своим значением.


                                            Я думал вызов происходит не до и не после, а во время и вместо оригинальной Get подсовывается моя ф-я с измененным значением out-параметра. :scratch:

                                            Так мне что искать еще сусликов или не ?)
                                              Цитата Qraizer @
                                              До следующего креативного обновления? Ну ок.

                                              Ты что предлагаешь?
                                              Цитата Qraizer @
                                              указатель на функцию заменить обратно на указатель на метод, как было в первом посту.

                                              Развей дальше эту идею. Или ты не знаешь, что указатель на метод (member function) - это в общем случае не просто указатель на функцию (о чём регулярно вопят в разделе "чистого С++"), и что внутреннее представление этих указателей является implementation specific и соотв-но может быть разным в разных компиляторах? Ты уверен, что во всех компиляторах указатель на виртуальный метод (какими являются все методы COM-интерфейса) должен быть именно указателем на саму функцию, а к примеру, не комбинацией указателя на vtable и смещения на указатель соответствующего метода в этой таблице?
                                              Мы же получаем этот указатель не для "внутреннего использования", а чтобы передать его в DetourAttach, которая принимает только обычные указатели и ес-но "ругается" на указатели на методы. А тайпкастить указатель на метод к void* - это либо верх наивности\глупости, либо "тайное" знание того, что в данном конкретном случае это прокатит и не приведет к AV или другим ошибкам. Спрашивается, чем это тайное знание лучше документированного (или полу-документированного) знания о том, что первым параметром в методы COM-интерфейса передается указатель на сам интерфейсный объект? Если можно реализовать COM-интерфейс с помощью абстрактного класса со стандартной конвенцией вызова в любом С++ компиляторе, то это означает, что параметр this должен передаваться также "стандартно" наравне с другими параметрами, а не как-то особо (через какой-то особый регистр - иначе это должно было было быть как-то особо документировано в WinAPI).

                                              Добавлено
                                              Цитата Mr.Newbie‎ @
                                              Я думал вызов происходит не до и не после, а во время и вместо оригинальной Get подсовывается моя ф-я с измененным значением out-параметра

                                              :wacko: Сам понял, что сказал?
                                              Да, вместо оригинальной Get "подсовывается" твоя. Но ты же конце своей Get вызываешь оригинальную True_Get, которая изменят значение pVal, затирая все твои "художества". Соотв-но твоя Get возвращает наружу то, что выдала в pVal True_Get. Нужно либо вызывать True_Get по условию if ... else, либо изменять pVal не до, а после вызова True_Get.

                                              Цитата Mr.Newbie‎ @
                                              Через SysAllocString\SysFreeString делал, толку ноль.

                                              Может ты это до первого this-суслика делал? Покажи реальный код
                                              Сообщение отредактировано: leo -
                                                Цитата
                                                Развей дальше эту идею. Или ты не знаешь, что указатель на метод (member function) - это в общем случае не просто указатель на функцию (о чём регулярно вопят в разделе "чистого С++"), и что внутреннее представление этих указателей является implementation specific и соотв-но может быть разным в разных компиляторах? Ты уверен, что во всех компиляторах указатель на виртуальный метод (какими являются все методы COM-интерфейса) должен быть именно указателем на саму функцию, а к примеру, не комбинацией указателя на vtable и смещения на указатель соответствующего метода в этой таблице?
                                                Мы же получаем этот указатель не для "внутреннего использования", а чтобы передать его в DetourAttach, которая принимает только обычные указатели и ес-но "ругается" на указатели на методы. А тайпкастить указатель на метод к void* - это либо верх наивности\глупости, либо "тайное" знание того, что в данном конкретном случае это прокатит и не приведет к AV или другим ошибкам. Спрашивается, чем это тайное знание лучше документированного (или полу-документированного) знания о том, что первым параметром в методы COM-интерфейса передается указатель на сам интерфейсный объект? Если можно реализовать COM-интерфейс с помощью абстрактного класса со стандартной конвенцией вызова в любом С++ компиляторе, то это означает, что параметр this должен передаваться также "стандартно" наравне с другими параметрами, а не как-то особо (через какой-то особый регистр - иначе это должно было было быть как-то особо документировано в WinAPI).


                                                user posted image

                                                Цитата
                                                Нужно либо вызывать True_Get по условию if ... else, либо изменять pVal не до, а после вызова True_Get.

                                                После вызова True_Get ?! Это как ?! :blink:

                                                Цитата
                                                Автор же привел в #15 "наполовину рабочее решение" (без манипуляций с pVal), которое работает без ошибок.

                                                Не совсем.. если убрать DisableThreadLibraryCalls и влепить ApplyHooks напрямую без CreateThread, то через какое-то время dxdiag валится, при этом в консоле видно как перед этим он сотню раз раз обращается к Get.

                                                Добавлено
                                                И еще один странный момент, вывел в консоль &fn_real ф-и HookFunction и заметил как кое где проскакивают пустые значения. Такое возможно? и может ли это быть причиной вылета с ошибкой ?
                                                Сообщение отредактировано: Mr.Newbie‎ -
                                                  leo, давай ты не будешь мне читать лекции по Плюсам, ок? Если ты не понял, я именно поэтому и встрял в эту высокоэлитную беседу. Вместо демонстрации собственных навыков логического мышления, в наличии которых нет ничего плохого, когда они к месту, я первый пост читал.
                                                    Цитата Mr.Newbie‎ @
                                                    После вызова True_Get ?! Это как ?! :blink:

                                                    Ты прикидываешься или издеваешься? :angry:
                                                    ExpandedWrap disabled
                                                      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.
                                                      Цитата Qraizer @
                                                      leo, давай ты не будешь мне читать лекции по Плюсам, ок?

                                                      1) И не думал этого делать. В Плюсах я "не в зуб ногой", о чем уже сотню раз говорил. Поэтому в ваши "чистые С++" дела принципиально не лезу.
                                                      2) В данном случае речь идет не о Плюсах, а о низкоуровневом перехвате функций с помощью DetoursAttach. Чем тут могут помочь ("высокоуровневые" implementation specific) указатели на методы, я искренне не понимаю. Если ты знаешь - поделись.
                                                      3) Какое отношение к Плюсам имеет способ передачи указателя this в технологии COM, я тоже не понимаю. COM это универсальная технология, которую можно использовать в разных ЯП. Если я вижу\знаю как передается this при вызове метода COM-интерфейса в своем "родном" дельфи\паскале, то почему он должен или может передаваться иначе в MSVC (managed code ЯП не в счет)? Да, маршаллинг никто не отменял, но для системных WinAPI интерфейсов этот маршаллинг (если он используется) должен быть зашит в самих системных dll, которые представляют эти интерфейсы. Т.е. dll должна представлять пользователям стандартный ABI интерфейс вызова методов, а то, куда она его дальше транслирует и как-то маршаллит, это уже её личное\приватное дело. Или я не прав?
                                                        Цитата leo @
                                                        Поэтому в ваши "чистые С++" дела принципиально не лезу.

                                                        Вступай в нашу банду, leo.
                                                        - Ловля сусликов с любой шкуркой.
                                                        - Самые брутальные дискуссии, плавно переходящие "в зуб ногой".
                                                        - Широкие возможности влезать в "чиста С++".
                                                        и множество других бонусов и удовольствий, не доступных в Дельфи !
                                                        Сообщение отредактировано: ЫукпШ -
                                                          Цитата

                                                          Ты прикидываешься или издеваешься? :angry:


                                                          Мозг отказал :crazy:

                                                          Цитата

                                                          В #2 у тебя было правильно - хук\перехват устанавливался только один раз при DLL_PROCESS_ATTACH, но из-за ошибок с this и pVal ничего не работало. Затем, начиная с #3 ты зачем-то убрал условие DLL_PROCESS_ATTACH, и соотв-но твой код перехвата стал срабатывать множество раз при создании (а в #3 и при завершении) потоков приложения. Поэтому тебе пришлось добавить DisableThreadLibraryCalls, чтобы запретить повторные срабатывания кроме первого.


                                                          Если ставлю DLL_PROCESS_ATTACH, то отрабатывает один раз и все. :wall:
                                                            Цитата Mr.Newbie‎ @
                                                            Если ставлю DLL_PROCESS_ATTACH, то отрабатывает один раз и все

                                                            Это может означать то, что приложение грузит dll динамически и выгружает ее после использования. Поэтому и твой однократный хук перестает работать, и "кое где проскакивают пустые значения" fn_real, если ты пытаешься ставить перехват в момент, когда dll не загружена.
                                                            Выход из этой ситуации - обеспечить загрузку этой dll самому. Можно либо создать ссылку на соответствующий интерфейсный объект и хранить ее в глоб.\стат. переменной до выгрузки dll, либо просто вызвать LoadLibrary. То и другое лучше делать в отдельном потоке ApplyHooks, т.к. грузить либы в DllMain не рекомендуется. Кстати, в этом же потоке можно организовать периодическую проверку загрузки dll и установки хука по таймеру на случай, если он по какой-то (очередной непонятной) причине слетит.
                                                              Цитата leo @
                                                              т.к. грузить либы в DllMain не рекомендуется

                                                              В DllMain вообще ничего делать не рекомендуется, кроме получения статуса загрузки/выгрузки и выделения/освобождения динамической локальной памяти
                                                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                              0 пользователей:


                                                              Рейтинг@Mail.ru
                                                              [ Script execution time: 0,1687 ]   [ 23 queries used ]   [ Generated: 30.03.24, 01:57 GMT ]