Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: COM/DCOM/ActiveX/ATL/CORBA > [Help] Подмена данных GPU при помощи MS Detours 3


Автор: SuprSonic 15.11.2017, 19:36
Привет всем,
Пытаюсь подменить информацию о видеокарте, но столкнулся с проблемой. Данные о видеокарте (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;
}


Inject:
Код

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, но ничего не перехватывается.  smile  Хотя по идее это все должно было выглядить так, что при перехвате CreateInstanceEnum у меня бы появлялся MessageBox.

Где я напортачил? Знающие, помогите плз...

Автор: _zorn_ 15.11.2017, 20:00
ХОЧУ МАЙНИТЬ БАБЛА, но помогите бесплатно.

Как это знакомо даже не в разрезе "майнить"...

Автор: SuprSonic 15.11.2017, 20:02
Цитата(_zorn_ @ 15.11.2017,  20:00)
ХОЧУ МАЙНИТЬ БАБЛА, но помогите бесплатно.

Как это знакомо даже не в разрезе "майнить"...

ЧЗНХ?! Без флуда пожалуйста.
Если с головой бобо - то посетите врача

Автор: xvr 16.11.2017, 10:37
Цитата(SuprSonic @  15.11.2017,  19:36 Найти цитируемый пост)
Код

typedef HRESULT(WINAPI IWbemServices::*tm_CreateInstanceEnum) (const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum);
tm_CreateInstanceEnum True_CreateInstanceEnum = &IWbemServices::CreateInstanceEnum;

Это C++ member pointer, а DetourAttach ожидает обычный указатель на функцию. Это две совершенно разных сущности. Более того, IWbemServices::CreateInstanceEnum вообще не существует в виде какого либо указателя - это просто индекс в таблице виртуальных методов. Еще более того - на момент загрузки вашей dll реализации IWbemServices::CreateInstanceEnum в памяти еще нет - она грузится динамически COM подсистемой в момент вызова первого CoCreateInstance.

Вам надо перехватывать CoCreateInstance и ждать, пока не попытаются создать IWbemLocator, а потом патчить таблицы виртуальных методов возвращаемых объектов по цепочке, пока не дойдете до вашего IWbemServices::CreateInstanceEnum

Может проще будет вмешаться в WMI и подменить провайдер, который выдает Win32_VideoController?

Добавлено через 3 минуты и 39 секунд
А если учесть, что ваши Win32_VideoController вообще могут запросить через IWbemServices::ExecQuery ("Select * from Win32_VideoController"), то затея с перехватом вообще становится практически неосуществимой

Автор: SuprSonic 16.11.2017, 17:21
Цитата

А если учесть, что ваши Win32_VideoController вообще могут запросить через IWbemServices::ExecQuery ("Select * from Win32_VideoController"), то затея с перехватом вообще становится практически неосуществимой


Спасибо за ответ. Мне подсказали вешать хук на метод 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 = 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;
}


Я тестирую получившуюся DLL прикрепляя ее к dxdiag.exe с помощью withdll.exe. Но мне походу запуска dxdiag.exe выбрасывается вот такое -
https://i.imgur.com/jwy8Ffr.png

https://i.imgur.com/AoiMxZY.png

https://i.imgur.com/M9FLgqL.png

 smile 

Я уже даже не знаю что делать. Хотя если в функции Hooked_Get прописать например MessageBox, то он появится, а это уже хорошо. Значит что-то в итоге перехватывается, но всеравно ошибка..

Автор: SuprSonic 16.11.2017, 18:08
Цитата

Может проще будет вмешаться в WMI и подменить провайдер, который выдает Win32_VideoController?


А можно поподробнее?)

Автор: xvr 17.11.2017, 10:48
Функция Get - это метод класса, так что у нее есть еще 1 параметр - this

Цитата(SuprSonic @  16.11.2017,  18:08 Найти цитируемый пост)
А можно поподробнее?) 

В двух словах это не объяснить, читайте в MSDN описание архитектуры https://msdn.microsoft.com/library/windows/desktop/aa384642(v=vs.85).aspx

Автор: SuprSonic 17.11.2017, 12:58
Впихнул первый параметр под this и....

Код

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


ничего, все равно не работет  smile 

Автор: xvr 17.11.2017, 15:51
Для начала поставьте в хуке печать параметров (через MessageBox) и вызов оригинальной функции. Если заработает, будем резать дальше smile

Автор: _zorn_ 17.11.2017, 18:40
Цитата(SuprSonic @  16.11.2017,  02:36 Найти цитируемый пост)
Пытаюсь подменить информацию о видеокарте, но столкнулся с проблемой

Цитата(SuprSonic @  16.11.2017,  03:02 Найти цитируемый пост)
Если с головой бобо - то посетите врача

Может стоит быть честным ?

Не могу придумать задачу, где нужно подменять что нибудь, а тем более видеокарту...

Автор: SuprSonic 17.11.2017, 20:52
Пришел к такому решению, оно наполовину рабочее... в общем вот код:
Код

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;
}


И он мне выдает вот такой списочек в консоли:

user posted image

Но есть два непонятных для меня момент -
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";


 smile 

Автор: xvr 20.11.2017, 15:44
Цитата(SuprSonic @  17.11.2017,  20:52 Найти цитируемый пост)
1). Без DisableThreadLibraryCalls(hinst) в DllMain(...) через какое-то время dxdiag.exe выбивает ошибку, 

Без этого каждый новый thread для вызова ApplyHooks будет вызывать эту точку входа вновь и вновь. В результате в системе кончится либо стек либо очередь на вызов DllMain

Цитата(SuprSonic @  17.11.2017,  20:52 Найти цитируемый пост)
Потерпел фиаско при попытке изменить какие-либо значения, в dxdiag.exe они не поменялись. 

Скорее всего это связано с тем, что dxdiag извлекает данные не через этот метод. Там очень и очень много способов эти данные извлечь.

Ну и ясности ради - возвращать BSTR так (V_BSTR(pVal) = L"NO_DATA";) нельзя - см SysAllocString

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)