HookCode IFileDialog::GetResult problem HELP ME !!

c++ / delphi package - dll injection and api hooking
Post Reply
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

I hooked GetResult method to get the dialog's result. (The dialog is created by IFileOpenDialog.- COM Object)

First, I hooked CoCreateInstance using HookAPI and got the address of IFileOpenDialog.
Then, I hooked GetResult method using HookCode.

My source code is shown below.

Code: Select all

PVOID GetInterfaceMethod64(PVOID intf, DWORD methodIndex)
{
	return *(PVOID*)(*(ULONG_PTR*)intf + methodIndex * sizeof(PVOID));
}
PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
	return *(PVOID*)(*(DWORD*)intf + methodIndex * 4);
}

// ~Next method definitions
HRESULT(WINAPI *GetResultNext)(IFileOpenDialog * This, IShellItem **ppsi);
HRESULT(WINAPI *GetResultsNext)(IFileOpenDialog * This, IShellItemArray **ppenum);
HRESULT(WINAPI *CoCreateInstanceNext)(REFCLSID  rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);

// ~Callback method definitions
HRESULT WINAPI GetResultCallback(IFileOpenDialog * This, IShellItem **ppsi)
{ 
	HRESULT hrResult = GetResultNext(This, ppsi);
	if (!SUCCEEDED(hrResult)) return hrResult;

	DWORD dwPid = GetCurrentProcessId();
	GetResultDataHandle(ppsi, dwPid);

	OutputDebugString(_T("IFileDialog::GetResult End"));
	return hrResult;
}
HRESULT WINAPI GetResultsCallback(IFileOpenDialog * This, IShellItemArray **ppenum) 
{
	HRESULT hrResult = GetResultsNext(This, ppenum);
	if (!SUCCEEDED(hrResult)) return hrResult;

	DWORD dwPid = GetCurrentProcessId();
	GetResultsDataHandle(ppenum, dwPid);

	OutputDebugString(_T("IFileOpenDialog::GetResults End"));
	return hrResult;
}
HRESULT WINAPI CoCreateInstanceCallback(
	REFCLSID  rclsid,
	LPUNKNOWN pUnkOuter,
	DWORD     dwClsContext,
	REFIID    riid, 
	LPVOID    *ppv
) {
	HRESULT hrResult = CoCreateInstanceNext(rclsid, pUnkOuter, dwClsContext, riid, ppv);
	
	if (hrResult == S_OK && rclsid == CLSID_FileOpenDialog) {
		LPVOID pGetResult;
		LPVOID pGetResults;
#ifdef WIN64
		OutputDebugString(_T("[hookofficepro] CoCreateInstance Callback Info : WIN64"));
		pGetResult = GetInterfaceMethod64(*ppv, 20);
		pGetResults = GetInterfaceMethod64(*ppv, 27);
#else
		OutputDebugString(_T("[hookofficepro] CoCreateInstance Callback Info : WIN32"));
		pGetResult = GetInterfaceMethod(*ppv, 20);
		pGetResults = GetInterfaceMethod(*ppv, 27);
#endif
		if (!GetResultNext) {
			if (!HookCode(pGetResult, GetResultCallback, (PVOID *)&GetResultNext))
				OutputDebugString(_T("IFileDilaog::GetResult Hook Fail"));
			else
				OutputDebugString(_T("IFileDilaog::GetResult Hook Success"));
		}
		else
			RenewHook((PVOID*)&GetResultNext);
			

		if (!GetResultsNext) {
			if (!HookCode(pGetResults, GetResultsCallback, (PVOID *)&GetResultsNext))
				OutputDebugString(_T("IFileOpenDilaog::GetResults Hook Fail"));
			else
				OutputDebugString(_T("IFileOpenDilaog::GetResults Hook Success"));
		}
		else
			RenewHook((PVOID*)&GetResultsNext);
	}
	return hrResult;
}

// Hook Install & Uninstall
BOOL InstallAPIHook()
{
	HookAPI("Ole32.dll", "CoCreateInstance", CoCreateInstanceCallback, (PVOID*)&CoCreateInstanceNext)
	return TRUE;
}

void UninstallAPIHook() {
	UninstallHookCode(&CoCreateInstanceNext);
	return;
}
This is the definition of GetResult method in IFileOpenDialog's vtable.
I defined GetResultCallback and GetResultNext using the definition of GetResult in the vtable.
(GetResults too.)

Code: Select all

typedef struct IFileOpenDialogVtbl
    {
        BEGIN_INTERFACE

        ... ...
        
        HRESULT ( STDMETHODCALLTYPE *GetResult )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItem **ppsi);
        
        ... ...
        
        HRESULT ( STDMETHODCALLTYPE *GetResults )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItemArray **ppenum);
        
        HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItemArray **ppsai);
        
        END_INTERFACE
    } IFileOpenDialogVtbl;

Then, I tested my source code on notepad.exe application.
At first, I opened 'File Open Dialog' in notepad application. When I selected a file, I got the result successfully.
However, if I open 'File Open Dialog' again, the notepad application dies.

I debugged the code using Windbg.
The program successfully opens the file for the first time.
However, if i try opening 'File Open Dialog' after the first time,
the notepad application dies in CoCreateInstanceNext, which belong to CoCreateInstanceCallback.
=> HRESULT hrResult = CoCreateInstanceNext(rclsid, pUnkOuter, dwClsContext, riid, ppv);

GetResults method does not occur the notepad's close.
That's occurred by GetResult method.(IFileOpenDialog::QueryInterface method too.. I had tested..)

1. Are thetre any problems in my source code?
2. Did I define GetResultCallback and GetResultNext correctly?
3. If there is no problem in my source code, do I need to UnHook the methods that I hooked using HookCode?
4. Please tell me why the notepad application dies. Please QQ... :sorry: :sorry: :sorry: :sorry:



* I found additional problem
When I hook the GetResult method and GetResults method together, notepad was closed.
But When I hook the GetResult method only, It's no problem.
Why.... :cry:
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

Are you sure that the indexes are correct? It seems weird to me that you're using indexes 20 and 27, when it seems that IFileOpenDialog only has 2 methods, according to this:

https://msdn.microsoft.com/en-us/librar ... 2147217396

If IFileOpenDialog has only 2 methods, the indexes should only be 1 apart, not 7.
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

I solved that.

I hooked the Release method and used UnHookCode about the GetResult, GetResults method in the ReleaseCallback.

Release method's index was 2..
...right ? :o

I refer this
This is defined in the ShObjldl.h

Code: Select all

 typedef struct IFileOpenDialogVtbl
    {
        BEGIN_INTERFACE
        
        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in REFIID riid,
            /* [annotation][iid_is][out] */ 
            _COM_Outptr_  void **ppvObject);
        
        ULONG ( STDMETHODCALLTYPE *AddRef )( 
            __RPC__in IFileOpenDialog * This);
        
        ULONG ( STDMETHODCALLTYPE *Release )( 
            __RPC__in IFileOpenDialog * This);
        
        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( 
            IFileOpenDialog * This,
            /* [annotation][unique][in] */ 
            _In_opt_  HWND hwndOwner);
        
        HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ UINT cFileTypes,
            /* [size_is][in] */ __RPC__in_ecount_full(cFileTypes) const COMDLG_FILTERSPEC *rgFilterSpec);
        
        HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ UINT iFileType);
        
        HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__out UINT *piFileType);
        
        HRESULT ( STDMETHODCALLTYPE *Advise )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in_opt IFileDialogEvents *pfde,
            /* [out] */ __RPC__out DWORD *pdwCookie);
        
        HRESULT ( STDMETHODCALLTYPE *Unadvise )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ DWORD dwCookie);
        
        HRESULT ( STDMETHODCALLTYPE *SetOptions )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ FILEOPENDIALOGOPTIONS fos);
        
        HRESULT ( STDMETHODCALLTYPE *GetOptions )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__out FILEOPENDIALOGOPTIONS *pfos);
        
        HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in_opt IShellItem *psi);
        
        HRESULT ( STDMETHODCALLTYPE *SetFolder )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in_opt IShellItem *psi);
        
        HRESULT ( STDMETHODCALLTYPE *GetFolder )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItem **ppsi);
        
        HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItem **ppsi);
        
        HRESULT ( STDMETHODCALLTYPE *SetFileName )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][in] */ __RPC__in_string LPCWSTR pszName);
        
        HRESULT ( STDMETHODCALLTYPE *GetFileName )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *pszName);
        
        HRESULT ( STDMETHODCALLTYPE *SetTitle )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][in] */ __RPC__in_string LPCWSTR pszTitle);
        
        HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][in] */ __RPC__in_string LPCWSTR pszText);
        
        HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][in] */ __RPC__in_string LPCWSTR pszLabel);
        
        HRESULT ( STDMETHODCALLTYPE *GetResult )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItem **ppsi);
        
        HRESULT ( STDMETHODCALLTYPE *AddPlace )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in_opt IShellItem *psi,
            /* [in] */ FDAP fdap);
        
        HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( 
            __RPC__in IFileOpenDialog * This,
            /* [string][in] */ __RPC__in_string LPCWSTR pszDefaultExtension);
        
        HRESULT ( STDMETHODCALLTYPE *Close )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ HRESULT hr);
        
        HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in REFGUID guid);
        
        HRESULT ( STDMETHODCALLTYPE *ClearClientData )( 
            __RPC__in IFileOpenDialog * This);
        
        HRESULT ( STDMETHODCALLTYPE *SetFilter )( 
            __RPC__in IFileOpenDialog * This,
            /* [in] */ __RPC__in_opt IShellItemFilter *pFilter);
        
        HRESULT ( STDMETHODCALLTYPE *GetResults )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItemArray **ppenum);
        
        HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( 
            __RPC__in IFileOpenDialog * This,
            /* [out] */ __RPC__deref_out_opt IShellItemArray **ppsai);
        
        END_INTERFACE
    } IFileOpenDialogVtbl;
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

Oh, you're right about the indexes, my fault.

So are all problems solved now? To be honest, I'm not sure why you would need to unhook in the release method. It shouldn't be necessary.

Have you tried using an "empty" (passthrough) callback function for GetResult(s)? Does that change anything? Also you could try using "PVOID This, PVOID param1" for the parameters of GetResultCallback/Next and GetResultsCallback/Next, just as a test to see if that changes anything. Maybe the compiler does some hidden weird things if you use official interface types.
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

I tested the empty Callback. But It got a same problem. ...
I don't know.. :cry:
and this issue makes me crazy

did i right? am i wrong? :sorry:
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

Have you tried using PVOID as the parameter type?
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

PVOID?
Like this?

Code: Select all

HRESULT WINAPI GetResultCallback(PVOID This, IShellItem **ppsi)
{ 
   HRESULT hrResult = GetResultNext(This, ppsi);
   if (!SUCCEEDED(hrResult)) return hrResult;

   DWORD dwPid = GetCurrentProcessId();
   GetResultDataHandle(ppsi, dwPid);

   OutputDebugString(_T("IFileDialog::GetResult End"));
   return hrResult;
}
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

Something like this:

Code: Select all

HRESULT(WINAPI *GetResultNext)(PVOID This, PVOID ppsi);

HRESULT WINAPI GetResultCallback(PVOID This, PVOID ppsi)
{ 
   return GetResultNext(This, ppsi);
}
Same with GetResultsCallback/Next. Does the issue still occur then?
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

This Code is fine

Code: Select all

HRESULT(WINAPI *GetResultNext)(PVOID This, PVOID ppsi);
HRESULT(WINAPI *GetResultsNext)(PVOID This, PVOID ppenum);

HRESULT WINAPI GetResultCallback(PVOID This, PVOID ppsi)
{ 
	HRESULT hrResult = GetResultNext(This, ppsi);
	if (!SUCCEEDED(hrResult)) return hrResult;
	
	return hrResult;        
}
HRESULT WINAPI GetResultsCallback(PVOID This, PVOID ppenum)
{
	HRESULT hrResult = GetResultsNext(This, ppenum);
	if (!SUCCEEDED(hrResult)) return hrResult;
	
	return hrResult;
}
But This code occur the process's close.(same with previous problem. after the first try)

Code: Select all

HRESULT(WINAPI *GetResultNext)(PVOID This, PVOID ppsi);
HRESULT(WINAPI *GetResultsNext)(PVOID This, PVOID ppenum);

HRESULT WINAPI GetResultCallback(PVOID This, PVOID ppsi)
{ 
	HRESULT hrResult = GetResultNext(This, ppsi);
	if (!SUCCEEDED(hrResult)) return hrResult;

        DWORD dwAddr = reinterpret_cast<DWORD>(This);
	CString strAddr; strAddr.Format(_T("%X"), dwAddr);
	OutputDebugString(_T("GetResult Callback : Address = ") + strAddr);		

	return hrResult;        
}
HRESULT WINAPI GetResultsCallback(PVOID This, PVOID ppenum)
{
	HRESULT hrResult = GetResultsNext(This, ppenum);
	if (!SUCCEEDED(hrResult)) return hrResult;

        DWORD dwAddr = reinterpret_cast<DWORD>(This);
	CString strAddr; strAddr.Format(_T("%X"), dwAddr);
	OutputDebugString(_T("GetResult Callback : Address = ") + strAddr);	

	return hrResult;
}
Between GetResult(s)Next and return, any codes..


In case, There are two IFileOpenDialog Objects A and B. (Both A and B are created by same process.)
Can I hook the object B's GetResult method after hooking object A's ?
(I fialed about this..)

HookCode use address of the object's method.
well, UnHookCode never use address of the specific object's method. right??

then, How do I uninstall the hook of the specific object's method?
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

DohyunShin wrote:This Code is fine

[...]

But This code occur the process's close.(same with previous problem. after the first try)

[...]
Ah, interesting. So there must be some problem with the CString and/or OutputDebugString() stuff. I don't know what's wrong with that. You could try avoiding CString and use straight APIs instead. E.g. "sprintf_s". Try calling OutputDebugString with a constant string to see if that causes any trouble.
DohyunShin wrote:In case, There are two IFileOpenDialog Objects A and B. (Both A and B are created by same process.)
Can I hook the object B's GetResult method after hooking object A's ?
(I fialed about this..)

HookCode use address of the object's method.
well, UnHookCode never use address of the specific object's method. right??

then, How do I uninstall the hook of the specific object's method?
You're hooking code, not objects, so your hooks will very likely affect all objects. If you only want to hook one specific object, I can see 2 options for that:

1) You could store the "This" pointer somewhere and in your hook callback functions check if it's the right one. It will be a different one for Objects A and B.

2) Or you could try modifying the object's function table directly instead of calling HookCode(). I'm not sure if this would limit the hooks to one object. Maybe. I've never tried this approach yet. Don't have any code for it, either.
DohyunShin
Posts: 8
Joined: Thu Oct 20, 2016 2:30 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by DohyunShin »

I tried as mentioned.

This is modified codes.
This code is successful in the notepad. Thank u ! :D

Code: Select all

//Next Methods 
HRESULT(WINAPI *GetResultNext)(PVOID This, PVOID ppsi);
HRESULT(WINAPI *GetResultsNext)(PVOID This, PVOID ppsi);
HRESULT(WINAPI *CoCreateInstanceNext)(REFCLSID  rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);

//Callback Methods
HRESULT WINAPI GetResultCallback(PVOID This, PVOID ppsi)
{ 
	HRESULT hrResult = GetResultNext(This, ppsi);
	if (!SUCCEEDED(hrResult)) return hrResult;
	
	DWORD dwAddr = reinterpret_cast<DWORD>(This);
	DWORD dwPid = GetCurrentProcessId();
	
	return hrResult;
}
HRESULT WINAPI GetResultsCallback(PVOID This,  PVOID ppenum)
{
	HRESULT hrResult = GetResultsNext(This, ppenum);
	if (!SUCCEEDED(hrResult)) return hrResult;
	
	DWORD dwAddr = reinterpret_cast<DWORD>(This);
	DWORD dwPid = GetCurrentProcessId();

	return hrResult;
}
HRESULT WINAPI CoCreateInstanceCallback(
	REFCLSID  rclsid,
	LPUNKNOWN pUnkOuter,
	DWORD     dwClsContext,
	REFIID    riid, 
	LPVOID    *ppv
) {
	HRESULT hrResult = CoCreateInstanceNext(rclsid, pUnkOuter, dwClsContext, riid, ppv);
	
	if (hrResult == S_OK && rclsid == CLSID_FileOpenDialog) {
		DWORD dwAddr = reinterpret_cast<DWORD>(*(&(*ppv)));
	
		LPVOID pGetResult;
		LPVOID pGetResults;
		
#ifdef WIN64
		pGetResult = GetInterfaceMethod64(*ppv, 20);
		pGetResults = GetInterfaceMethod64(*ppv, 27);
#else
		pGetResult = GetInterfaceMethod(*ppv, 20);
		pGetResults = GetInterfaceMethod(*ppv, 27);
#endif
		HookCode(pGetResult, GetResultCallback, (PVOID *)&GetResultNext);
		HookCode(pGetResults, GetResultsCallback, (PVOID *)&GetResultsNext);
	}
	return hrResult;
}

//Hook Install & Uninstall
BOOL InstallAPIHook()
{
	if (!HookAPI("Comdlg32.dll", "GetOpenFileNameW", GetOpenFileNameWCallback, (PVOID*)&GetOpenFileNameWNext))
		OutputDebugString(_T("[hookofficepro] GetOpenFileNameW Hook Fail"));
	else
		OutputDebugString(_T("[hookofficepro] GetOpenFileNameW Hook Success"));
	
	if (!HookAPI("Ole32.dll", "CoCreateInstance", CoCreateInstanceCallback, (PVOID*)&CoCreateInstanceNext))
		OutputDebugString(_T("[hookofficepro] CoCreateInstance Hook Fail"));
	else
		OutputDebugString(_T("[hookofficepro] CoCreateInstance Hook Success"));
	
	return TRUE;
}

void UninstallAPIHook() {
	UninstallHookCode(&GetOpenFileNameWNext);
	UninstallHookCode(&CoCreateInstanceNext);
	OutputDebugString(_T("[hookofficepro] UninstallHookCode"));
	return;
}
I need to hook all process besides the notepad.
So I tested this code in other messenger program.
But I got a same problem... Is there problem in the messenger programme?

if the messenger has protection, it must be failed if i hooked Realese method, but it succeeded.
So I guess. This is problem of the messenger's internecine structure.

If I unhook the GetResult(s)Next methods in the ReleaseCallback, does it cause fatal problem?
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by madshi »

I'm not aware of any specific messenger related problem.

Unhooking GetResult(s) in the ReleaseCallback might not be ideal, but I suppose it should work.
iconic
Site Admin
Posts: 994
Joined: Wed Jun 08, 2005 5:08 am

Re: HookCode IFileDialog::GetResult problem HELP ME !!

Post by iconic »

I'd give modifying the vtable a go. You already know the indexes, if I indeed read correctly. See here about vtable http://bbs.csdn.net/topics/391065069

P.S: The example code does exactly what you're in need of, just use GetResult instead of GetResult"s"

P.P.S: See here too http://add2paper.github.io/2015/06/24/H ... -Functions

--Iconic
Post Reply