• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開心的工作
            簡(jiǎn)單、開放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            Hooking a DirectX/COM Interface

            Posted on 2010-01-13 00:33 S.l.e!ep.¢% 閱讀(764) 評(píng)論(0)  編輯 收藏 引用 所屬分類: RootKit
            Hooking a DirectX/COM Interface

            原文:http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx

            Introduction

            After all the helpful articles I read here, I am glad that I can contribute a subject which has not yet been covered.

            This article features a description on how to hook a DirectX/COM interface. I used the DirectInput interface as an example of how to hook an interfacefunction.

            For the basic Windows hook, I refer to an article by Wade Brainerd, which describes the API hooking process.

            Task

            To intercept a method of a COM interfacerequires an extended approach compared to hooking an API call. If the desired DLL is examined, only the create interfacefunction is actually exported by the DLL. So, how can you hook your desired function?

            Screenshot - dinputdll.jpg
            DInput.dll

            A COM interfaceis basically a list of virtual function pointers, which are linked together. You merely have to follow the links and modify every node till you finally reach the pointer of the function, which you would like to replace.

            Step 1

            As you can see, only the create interfaceCOM functions are visible, so you have to start your hooking chain at the DirectInputCreate function which returns a COM interface.

            Here, you have to inject your DLL into the import address table (IAT) of the calling program.

            Step 2

            If the calling program invokes a DirectInputCreate, your function is called, you receive a pointer to a pointer of a pointer to a virtual function table, which is the interfaceof direct input:

            Collapse Copy Code
            DECLARE_INTERFACE_(IDirectInputW, IUnknown)
            {
                /*** IUnknown methods ***/
                STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
                STDMETHOD_(ULONG,AddRef)(THIS) PURE;
                STDMETHOD_(ULONG,Release)(THIS) PURE;
            
                /*** IDirectInputW methods ***/
                STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICEW *,LPUNKNOWN) PURE;
                STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKW,LPVOID,DWORD) PURE;
                STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE;
                STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE;
                STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE;
            };

            Step 3

            Now you can create your device with CreateDevice. You will again receive an address to a different virtual function pointer table, which represents the Device.

            Screenshot - dinputh.jpg

            Pick the method you would like to replace and change the virtual function pointer table in the desired place to inject your function.

            Step 4

            Do the actual data manipulation.

            Implementation

            Step 1

            To hook yourself into an API function, you can simply use the Windows API call SetWindowsHookEx. Here you create a system hook to monitor starting processes and match it to your desired program. After you identified your program, you have to compare the import module names with the DLL you wish to replace. Since this hook is written for direct input, the entry we are looking for is DINPUT8.DLL. To find this entry you have to loop through the descriptors till you find your DLL.

            Collapse Copy Code
            // Iterate through each import descriptor, and redirect if appropriatewhile ( pImportDesc->FirstThunk )
              {
                PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name);
            
                if ( lstrcmpi( pszImportModuleName, Hook->Name ) == 0 )
                {
                  sprintf(dbBuffer,"Dll Found in module  %s replace it\n", Hook->Name );
                  WriteToLog(dbBuffer);
                  RedirectIAT( Hook, pImportDesc, (PVOID)hModEXE );
                }
            
                pImportDesc++;  // Advance to next import descriptor
              }

            After you found your entry, you have to remove the write protection from the IAT with...

            Collapse Copy Code
            VirtualQuery( pIAT, &mbi, sizeof(mbi) );

            ... to be able to write into the memory. After the memory is open, you have to find your entry by iterating through the IAT.

            Collapse Copy Code
            while ( pIteratingIAT->u1.Function )
              {
                void* HookFn = 0;  // Set to either the SFunctionHook or pStubs.if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) )  // import by name
                {
                  PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME,
                      pBaseLoadAddr, pINT->u1.AddressOfData );
            
                  // Iterate through the hook functions, searching for this import.
                  SFunctionHook* FHook = DLLHook->Functions;
                  while ( FHook->Name )
                  {
                    if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 )
                    {
                      sprintf(dbBuffer,"Hooked function: %s\n",(char*)pImportName->Name );
                      WriteToLog(dbBuffer);
                      // Save the old function in the SFunctionHook structure and get the new one.
                      FHook->OrigFn = (unsignedlong*)pIteratingIAT->u1.Function;
                      HookFn = FHook->HookFn;
                      break;
                     }
            
                      FHook++;
                    }
                  }

            Now, you can replace it with your own one.

            Collapse Copy Code
            // Replace the IAT function pointer if we have a hook.if ( HookFn )
              {
                // Cheez-o hack to see if what we're importing is code or data.// If it's code, we shouldn't be able to write to itif ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) )
                {
                  pIteratingIAT->u1.Function = (DWORD)HookFn;
                }
                elseif ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
                {
                  // Special hack for Win9X, which builds stubs for imported// functions in system DLLs (Loaded above 2GB).  These stubs are// writeable, so we have to explicitly check for this caseif ( pIteratingIAT->u1.Function > (DWORD)0x80000000 )
                      pIteratingIAT->u1.Function = (DWORD)HookFn;
                }
              }

            The only thing remaining is to restore the memory attributes, as nothing ever happened.

            Collapse Copy Code
            VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare);

            Step 2

            Inside of the CreateInterface method, we start hooking into the COM interfaceby injecting our own CreateDevice function pointer into the Virtual function table (Vtbl), which is returned in the ppvOut pointer of the original call.

            Collapse Copy Code
              DirectInput8Create_Type OldFn =
                 (DirectInput8Create_Type)D3DHook.Functions[D3DFN_DirectInput8Create].OrigFn;
                HRESULT hr = OldFn( hinst, dwVersion, riidltf, ppvOut, punkOuter );

            Resolve the pointer until you get the pointer to the Vtbl of the interface.

            With this address, you have to again remove the memory protection before you can inject your function into the table and save the old function pointer for later use.

            Inject your function pointer into the offset of the CreateDevice function pointer inside of the interfaceVtbl and restore the memory protection.

            As you can see, the CreateDevice is the fourth method of the DirectInput interface, which means the offset inside of the Vtbl is 0x0C (pointer(DWORD)*index 3).

            Collapse Copy Code
            typedefstruct IDirectInput *LPDIRECTINPUT;
            
            #if !defined(__cplusplus) || defined(CINTERFACE)
            #define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
            #define IDirectInput_AddRef(p) (p)->lpVtbl->AddRef(p)
            #define IDirectInput_Release(p) (p)->lpVtbl->Release(p)
            #define IDirectInput_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c)
            #define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d)
            #define IDirectInput_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a)
            #define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b)
            #define IDirectInput_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b)
            #else#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
            #define IDirectInput_AddRef(p) (p)->AddRef()
            #define IDirectInput_Release(p) (p)->Release()
            #define IDirectInput_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c)
            #define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d)
            #define IDirectInput_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a)
            #define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b)
            #define IDirectInput_Initialize(p,a,b) (p)->Initialize(a,b)
            #endif

            After we know where to inject it, we can start thinking about the implementation. When you look at the declaration of CreateDevice in the dinput.h, it does not match up with the declaration you see in the DirectX Help.

            Collapse Copy Code
            HRESULT CreateDevice(
            
                REFGUID rguid,
                LPDIRECTINPUTDEVICE *lplpDirectInputDevice,
                LPUNKNOWN pUnkOuter
            );

            As you can see in the definition inside the dinput.h, you have to add a fourth parameter, which is the interfacepointer. This ends up in the following function declaration:

            Collapse Copy Code
            HRESULT __stdcall   PASCAL MyCreateDevice(LPVOID *ppvOut,REFGUID rguid,
                LPDIRECTINPUTDEVICE *lplpDirectInputDevice,
                LPUNKNOWN pUnkOuter

            This is important. You have to make sure, to use the __stdcallcalling convention in your declaration. Refer to the MSDN.

            The __stdcallcalling convention is used to call Win32 API functions. The callee cleans the stack. __cdeclis the default calling convention for C and C++ programs. The stack has to be cleaned up by the caller, which is not the case with our function.

            When you look at the disassembly of this call, you can see the stack pointer verification function _RTC_CheckEsp is called after the call to the interfacefunction.

            Collapse Copy Code
            if (lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL)!=DI_OK)
            00401365  mov         esi,esp
            00401367  push        000401369  push        offset lpdikey (4552C8h)
            0040136E  push        offset _GUID_SysKeyboard (44643Ch)
            00401373  mov         eax,dword ptr [lpdi (4552C4h)]
            00401378  mov         ecx,dword ptr [eax]
            0040137A  mov         edx,dword ptr [lpdi (4552C4h)]
            00401380  push        edx
            00401381  mov         eax,dword ptr [ecx+0Ch]
            00401384  call        eax
            00401386  cmp         esi,esp
            00401388  call        _RTC_CheckEsp (4026A0h)
            0040138D  test        eax,eax
            0040138F  je          Game_Init+78h (401398h)
               return(0);
            00401391  xor         eax,eax
            00401393  jmp         Game_Init+107h (401427h)
            
            // set cooperation levelif (lpdikey->SetCooperativeLevel(main_window_handle,

            If you forget to declare your function with __stdcallyour function will process fine, but you will fail the esp pointer test of this function which sets the eax and test it after the function call.

            Step 3

            When you now create the device, the call is re-routed to your CreateDevice function.

            After you call the original function, you receive a new pointer in lplpDirectInputDevice, which will direct you to the Vtbl of the device.

            Collapse Copy Code
            HRESULT hr = OldCreateDev(ppvOut,rguid,lplpDirectInputDevice,pUnkOuter);

            In my sample, I replaced the GetDeviceState, since I can add additional input in the return data of the calling function. To get to the offset, you have to look at the definition inside the DInput.dll. You see that the GetDeviceState function is the tenth method inside of the device, which leads to an offset of 0x24.

            After you know the offset, we can proceed with the instructions in step 2 to remove the protection, store the old pointer, inject your own function, and restore the memory protection.

            Step 4

            When the GetDeviceState function is called by the target program, the injected function is called and you can manipulate the data as you wish.

            History

            • 8th May, 2006: Article posted

            License

            This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

            About the Author

            Martin Mueller


            Member
            My first PC program was written on MS DOS in Assembler, after I got
            Peter Norton's Assembler book where the Edlin and DOS Debugger supported
            me in exploring my and code of others. I went from there over
            IDE/Debugger like Borland Turbo Debugger over several microcontroller
            H8, ST16, 8051, SLE66, SLE88 to my favorite MS Visual Studio 6. Now I
            mainly program in C++ and Java, where I prefer C++ since your abilities
            to interfere with the system are an easier task, which is still my
            favorite, than implementing some natives in Java to enhance the
            functionality. I am working since 18 years as a programmer and still
            love every day of it. My experience include ever level of programming
            from Hardware programming, where you have to take care of nano seconds
            in your assembler program over real time operating system programming,
            to VM programming, system services, applications, game programming, web
            server to high level web script programming.
            Occupation: Web Developer
            Location: Germany Germany

            伊人丁香狠狠色综合久久| 久久精品99久久香蕉国产色戒| 久久精品人人做人人妻人人玩| 97精品伊人久久久大香线蕉| 五月丁香综合激情六月久久| 久久综合久久综合九色| 亚洲国产视频久久| 久久99精品国产麻豆宅宅| 亚洲国产精品久久久久婷婷软件| 91精品日韩人妻无码久久不卡 | 精品久久久久一区二区三区| 久久国产精品视频| 久久精品成人免费观看97| 久久久久久久免费视频| 久久成人精品视频| 久久99久久99精品免视看动漫| 国内精品久久久久久久coent| 超级97碰碰碰碰久久久久最新| 好久久免费视频高清| yy6080久久| 久久伊人中文无码| 国产免费久久精品99久久| 99久久免费只有精品国产| 一本色综合网久久| 日本加勒比久久精品| 国产成人无码精品久久久免费 | 国产精品美女久久久免费| 久久久亚洲裙底偷窥综合| 91亚洲国产成人久久精品网址| 久久久婷婷五月亚洲97号色| 色妞色综合久久夜夜| 久久99精品九九九久久婷婷| 蜜桃麻豆www久久| 国产亚洲精品自在久久| 91精品国产综合久久婷婷| 国产精品久久久久久搜索| 亚洲欧美成人综合久久久| 国产A级毛片久久久精品毛片| 精品无码久久久久国产动漫3d| 亚洲午夜无码AV毛片久久| 亚洲国产另类久久久精品|