Click here to Skip to main content
Licence 
First Posted 20 Feb 2006
Views 32,377
Downloads 401
Bookmarked 36 times

Using hook and web service to make other programs do things they were not designed to do

By | 20 Feb 2006 | Article
Projects demonstrating how to install and use a global hook and how to call a web service within the hook procedure

Introduction

The Windows Operating System allows you to use hooks to modify the behaviors of other applications. Here is how it works: You write a DLL that exports a procedure (a global hook) to handle certain Windows events such as mouse clicks, etc. Then you use the SetWindowsHookEx API to install the hook procedure. The operating system will detect that you installed the global hook and execute the procedure code within other applications when the targeted events occur. There are some good articles on Code Project that deal with the topics of writing and using Windows hooks. You can also find complete information about Windows hooks on MSDN.

In this article, I will introduce a generic hook utility I wrote that can be reused to do some interesting or dangerous things. The demo application is a special hook that provides encode/decode capability for XML and HTML texts. Here are the 4 projects included in the download zip file:

  1. HookUtility.dll: This is a reusable library for installing your own hooks. It exports a procedure InstallGlobalHook . If you have your hook procedures built in various DLLs, you can call InstallGlobalHook to install them.
  2. Webencoder: This is an ASP.NET web service that can encode/decode XML and HTML texts.
  3. HookModule.dll: This library contains a special hook procedure. When installed, the hook procedure will subclass Windows in the applications you choose to make them call the above web service. It can be easily modified to do other things.
  4. WebencoderClient.exe: This program installs and uninstalls the special hook procedure implemented in HookModule.dll. It can be modified to work with your own hook procedures.

There are many things to watch out for when working with Windows hooks. First of all, your global hook procedure can easily slow down the whole system if you are not careful. Secondly, it can break and/or crash other programs. Thirdly, it may become a security hole for you or your users. I assume anyone who reads this article already knows the consequences and is willing to take life in his/her own hands.

The Demo Application

Here is how to install the demo application.

  1. First, you need to install Microsoft SOAP Toolkit 3.0 on your computer. This is needed to call a web service from the hook procedure
  2. Unzip all files into a local folder on your computer
  3. Run the script file install.vbs in the Webencoder subfolder to install the web service
  4. Register the com component XYSoapClient.dll in subfolder WebEncoderHook

To start the demo, run application WebencoderClient.exe in the subfolder WebEncoderHook. This application will be minimized when started. The special hook procedure implemented in HookModule.dll will function only when this application is running.

Now you can start notepad.exe, type in some text or open an existing file. Then highlight some text and right click the mouse "while holding down the left shift key", you will see a new context menu with 6 command items: XML Encode, XML Decode, HTML Encode, HTML Decode, URL Encode, URL Decode.

Please note that you have to press down the left shift key in order for the new context menu to appear, otherwise, you will only see the normal context menu (with commands like copy, paste, etc.) when you right click the mouse. Secondly, if you don't highlight any text, you won't see the new context menu either.

The special hook procedure in HookModule.dll will be uninstalled when you exit the WebenconderClient application and the new context menu will no longer appear after that.

What do the commands in the new context menu do? For example, if you highlighted the following text and select the XML Encode command:

<text>Hello, world</text>

the highlighted text will be replaced by the following new text:

&lt;text&gt;Hello, world&lt;/text&gt;

If you select the XML Decode command, then the changed text will be restored back to the original text.

What happens behind the scenes is that when you select one of the new commands, the hook procedure will retrieve the highlighted text from the current window and send it as input to the Webencoder service. The Webencoder service will convert the text and send it back to the hook procedure. The hook procedure will then replace the highlighted text with the output from the Webencoder service.

Why do I need to use a web service in this demo? It is certainly possible to write a hook procedure that does the same things without calling any web service, however the hook procedure is written as a low level C++ DLL, it is not easy to call other advanced libraries and components. Plus, having a web service makes it easier to enhance the application to do other more complicated stuff. Another advantage is that you can install the web service on a remote computer to serve multiple client programs/machines.

HookModule.ini

To use the web service remotely, all you have to do is modify the WebEncoderURL setting in the HookModule.ini file. The HookModule.ini file must be located in the same folder as the HookModule.dll file. Here is an example of the HookModule.ini file.

You may notice that notepad.exe and wordpad.exe are listed in the HookModule.ini file: the special hook procedure will only work with programs listed in this file. To make it work with another program, you will have to add its name into the file. To add more programs, you simply add new settings [Program2], [Program3], ..., and set Name= MyNewProgramName.exe in these new settings.

The global hook procedure in HookModule.dll will interact with all programs running on the same desktop as the WebencoderClient application. If a program is not listed in the HookModule.ini file, the hook procedure will detect that and won't do anything significant. Therefore it won't slow down the whole system.

Limitations

However, this tool does not work with just any Windows program. For example, it won't work with Internet Explorer or Microsoft Word. This is because the special hook procedure subclasses Windows in the targeted programs and processes regular Windows messages for these Windows. The main Windows in Internet Explorer and Microsoft Word are not regular Windows (just speculation, I have no access to the source code of Internet Explorer and Microsoft Word). Another limitation is that the tool won't work with Unicode text (yet).

The Hook Utility

The HookUtility.dll basically calls the SetWindowsHookEx API to install a hook procedure. You may ask, why do I need a DLL for this? The answer is, ease of use. You can reuse it to install multiple hook procedures. Here is the signature of the InstallGlobalHook function.

extern "C" __declspec(dllexport) HHOOK InstallGlobalHook
            (int nType, char* sModulePath, char* sMethodName);

You implement your own global hook procedure in a separate DLL and call this function to install it. When calling, you need to specify the hook type (which determines what events you want your hook to process), the path of your DLL (if your DLL is in the same folder as HookUtility.dll, then you don't need to give the full path, only the name is necessary), and the name of your hook procedure. As you can see, there is no need to get module handle and procedure address, unlike calling SetWindowsHookEx directly.

The return value of this function is the handle of the installed global hook. It can be used to uninstall the hook when calling the UnhookWindowsHookEx API.

For completeness, there is also a InstallLocalHook function in the HookUtility.dll, but it is not being fully tested yet. To get a complete description about hook types and information on how to implement a hook procedure, please refer to MSDN.

Invoke Web Service From A Hook Procedure

Typically, a hook procedure is written in low level C/C++ code. Unless you are an expert in Win32 programming, it is hard to write code that does significant things within a hook procedure. The approach I take is implement import functions in a web service and let the hook procedure call the web service to get things done.

However, calling a web service within a hook procedure is not exactly easy. I wrote a COM component about three years ago that simplifies the task a little bit, see my Code Project article Invoking web methods from a C++ console application for details. This COM component uses the SOAP Client object from Microsoft SOAP Toolkit 3.0 to call a web service. The catch is, parameters and output of the web service have to be represented as VARIANTs. In order to create and use this com component, I used the C++ class XYDispDriver in my code which is described in another code project article of mine. Here is the code in HookModule.dll that calls the Webencoder service.

...
XYDispDriver oDriver;
if(oDriver.CreateObject("XYSoapClient.1",CLSCTX_INPROC_SERVER))
{
    USES_CONVERSION;
    VARIANT* pOutput = NULL;
    pOutput = oDriver.InvokeMethod("InitService",pWebEncoderURL,"","","");
    if(pOutput!=NULL&&pOutput->lVal!=0)
    {
        WCHAR* pInput = GetSelectedText(hMyWnd);
        WCHAR* pTypes[] = {L"xml",L"html",L"url"};
        int nType = (wParam-771)/2;
        WCHAR* pAction = NULL;
        if((wParam-770)%2!=0) pAction = L"Encode";
        else pAction = L"Decode";
        VARIANT vInput1;
        vInput1.vt = VT_BSTR;
        vInput1.bstrVal = ::SysAllocString(pInput);
        VARIANT vInput2;
        vInput2.vt = VT_BSTR;
        vInput2.bstrVal = ::SysAllocString(pTypes[nType]);
        VARIANT vInput3;
        vInput3.vt = VT_BSTR;
        vInput3.bstrVal = ::SysAllocString(pAction);
        VARIANT vInput4;
        vInput4.vt = VT_EMPTY;
        VARIANT vInput5;
        vInput5.vt = VT_EMPTY;
        pOutput = oDriver.InvokeMethod
      ("InvokeMethod","Process",vInput1,vInput2,vInput3,vInput4,vInput5);
...    

The DLLs in the projects are dynamically loaded. This provides some flexibility but makes it harder to debug the code. I have to write a test program that statically links to all the DLLs to debug the code. If you build the code in debug mode, then you will also get a log file HookModuleLog.txt that contains import trace information. The log file will be located in the current working directories of the programs in which the hook procedure is running.

Final Note

The Webencoder service in the article is written with Visual Studio .NET 2003. The other programs were written with Visual Studio 6.0.

Disclaimer

I am not a Win32 expert and this is the first time I write code that implements a Windows hook. Please correct me if I left out anything or misspoke about some facts. Thanks.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Xiangyang Liu 刘向阳



United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionI have a question... Pinmembermesiasrojo0:28 11 Aug '11  
Generalcould not do Pinmemberhimanshupareek21:23 6 Oct '08  
hello liu,
 
i tried with your code. It looks nice technique. But I tried to run the install.vbs, it confirms some inputs and at last it tells invalid syntax error message box.
 
If you can please help, i dont much about webservices.
thanks Cry | :((
 
Himanshu Pareek
India

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120604.1 | Last Updated 20 Feb 2006
Article Copyright 2006 by Xiangyang Liu 刘向阳
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid