Didier Stevens

Wednesday 19 March 2008

bpmtk: Spying on IE

Filed under: Hacking,My Software — Didier Stevens @ 11:07

I was asked if it’s possible to intercept IE’s HTTPS requests. It is, it’s not difficult, and you don’t need admin rights to do it on your own processes. In other words, a malware doesn’t even need admin rights to spy on your IE process, if said malware is also running under your user account.

We need to hook the API calls to WinINet functions, like HTTPOpenRequest. We can do this by patching the Delayed Import Address Table of executables calling WinINet functions. In our case, to spy on IE, we need to patch the DIAT of urlmon.dll. One simple way to hook these API calls, is to develop a DLL that will patch the DIAT, diverting the calls to our own functions. Our functions will just call the original functions while intercepting the data.

Here is an example for HTTPOpenRequest:


HookHTTPOpenRequestA is our hook function for HTTPOpenRequest. It will just output the flags, verb and objectname parameters to the debugger, and then call the original HTTPOpenRequest function with unmodified arguments (which we saved in variable OriginalHTTPOpenRequestA). BTW, if the declaration and use of OriginalHTTPOpenRequestA looks confusing to you, read the explanation of function pointers in C.

Patching the DIAT is easy, use the PatchDIAT function that I provide with my Basic Process Manipulation Tool Kit (it’s in iat.c).


PatchDIAT needs the name of the executable we want to patch (urlmon.dll), the name of the API to patch (wininet.dll), the name of the function to patch (HttpOpenRequestA), the address of our hooking function (HookHttpOpenRequestA) and a variable to store the address of the original function (OriginalHttpOpenRequestA). PatchDIAT returns S_OK when patching was successful.

We package everything in a DLL, while hooking some other functions, like InternetReadFile (to intercept actual data), and then inject this DLL in IE with my toolkit:



I’ve stored a test file on my server: https://DidierStevens.com/files/temp/test.txt. When you browse to this test file with the patched IE, you’ll see this in Sysinternal’s DebugView:


Lines 0 to 4 indicate the patching IE was successful.

Line 5 shows IE opening a connection to didierstevens.com on port 443 (that’s 1BB in hexadecimal).

Line 6 shows the preparation of an HTTPS GET request to file /files/temp/test.txt. Flags 00C00000 indicate HTTPS and keep-alive.

Line 7 shows that the call to InternetReadFile was successful and read 25 bytes (0x19).

Line 8 shows the actual data retrieved by IE: This is just a text file.

The next lines indicate we unloaded our DLL with success (thus undoing the patch).

As you can see, we can intercept data before it is encrypted by the HTTPS connection (/files/temp/test.txt) and after it is decrypted (This is just a text file.). This works because we patch the executable before it calls API functions that handle the encryption/decryption, so we get access to the unencrypted data.

I kept my demo DLL very simple to show you the basic principles. A complete spying program would have to hook more functions and tie all the data together to present it in a user friendly way.

It’s also simple to adapt my IE spying DLL to tamper with the data. For example, it could redirect IE to another web site by changing the lpszServerName argument before it calls the original InternetConnect function.


  1. […] To Add: Nice post here describing the basic principals of DLL hooking (one of the techniques used in Signpost), and how it […]

    Pingback by The First Rule of Programming: It’s Always Your Fault | Mike Andrews — Saturday 22 March 2008 @ 18:36

  2. very interesting Didier… could something similar be possible for FFox?

    Comment by donald — Monday 7 April 2008 @ 6:50

  3. FF doesn’t use wininet, but a similar approach must be possible. Somewhere in the FF code, calls need to be made to functions to use TLS. If these functions reside in a DLL, you can use the same technique (IAT patching). But if these functions are in the FF executable, you’ll need another technique to intercept the calls (like a trampoline).

    Comment by Didier Stevens — Monday 7 April 2008 @ 19:18

  4. Very interesting post. I’m about to try it out. Do you know if this should work for IE7 as well? Thank you

    Comment by Tim — Thursday 26 June 2008 @ 18:50

  5. I did a quick test and it doesn’t work with IE7. A quick disassembly shows that urlmon.dll imports HttpOpenRequestW (delayed import) from wininet.dll, and not HttpOpenRequestA. So I suppose that for IE7, you have to hook the wide-byte version of HttpOpenRequest.

    Comment by Didier Stevens — Thursday 26 June 2008 @ 19:40

  6. Would you mind posting your complete source? It would be much appreciated.


    Comment by Tim — Friday 27 June 2008 @ 16:40

  7. Also, I appreciate your feedback. I hadn’t noticed your reply when I last commented.

    Comment by Tim — Friday 27 June 2008 @ 17:26

  8. I have one more question. I was able to compile your code correctly, but I am unable to get it packaged into a dll. I’m a beginner with c/c++. I’m using cygwin on windows and have all the necessary packages. Do you use a specific command to package your code into a dll? I attempted to load it into Visual Studio Express 2008, but it didn’t recognize the function pointer syntax, and was giving me errors. I would really like to try out your example. I appreciate your time.


    Comment by Tim — Friday 27 June 2008 @ 21:34

  9. I seem to have deleted the source code by mistake, I’ll have to search through some backups or write it again.

    It gets compiled along with my bpmtk. So first of all, try to compile the bpmtk with it’s make file bpmtk.mak
    I have some instructions in the make file:

    # Developed with Borland’s free C++ compiler: http://cc.codegear.com/Free.aspx?id=24778
    # You need to install the MS Platform SDK for BCC: http://sourceforge.net/projects/bccsdk/
    # I decompress it in the BORLAND\bccsdk_0_0_7_1 directory, next to BORLAND\BCC55

    Comment by Didier Stevens — Saturday 28 June 2008 @ 7:58

  10. Hi!
    I am trying to hook in IE7 but i am unable to do so.
    I have implemented a hooking mechanism similar to the one in your BPMTK (great code!). But i have included a scan to check all the modules loaded.

    As far as I can see in the debug (I am not an expert in this area), URLMON is linking to:

    [3376] msvcrt.dll
    [3376] ntdll.dll
    [3376] ole32.dll
    [3376] OLEAUT32.dll
    [3376] RPCRT4.dll
    [3376] SHLWAPI.dll
    [3376] USER32.dll
    [3376] ADVAPI32.dll
    [3376] KERNEL32.dll
    [3376] iertutil.dll

    So the hook for HttpOpenRequestW (or HttpOpenRequestA) does not suceed with that DLL and I cannot get any traffic capture.

    Do you have an idea of how IE7 handles the SSL?, maybe I am doing something wrong…
    Thanks for your help (this blog was very helpful to me!)

    (sorry for my bad english)

    Comment by Pablo — Wednesday 17 December 2008 @ 20:06

  11. I’ll try to take a look at it during the holiday.

    Comment by Didier Stevens — Sunday 21 December 2008 @ 15:09

  12. Hi Didier
    First of all many thanks for writing great program.
    Can you find any idea about or solution about IE7? I need it badly actually. For IE6 its working fine. But for IE7 it shows “HookHttpOpenRequestA failed” and “HookInternetConnectA failed”.

    Hope to get your response in this issue.


    Comment by Smith — Saturday 17 January 2009 @ 3:30

  13. Still on my todo list.

    Comment by Didier Stevens — Saturday 17 January 2009 @ 15:28

  14. Hi Didier
    Thanks for your reply. Hope you will do it soon 🙂 as you are a great programmer. Infact many of us(not only me) need it badly because now everywhere is IE7.

    Good luck Didier.

    Comment by Smith — Saturday 17 January 2009 @ 15:35

  15. I managed to run the hook on the functions you pointed above by using the EasyHook library (but I noticed IE7 has a different cache mechanism and cached data will not be retrieved by using that functions), so probably the problem is not with the libraries but with the hook method.

    Comment by Pablo — Monday 19 January 2009 @ 19:04

  16. Pablo,
    can you hook IE7 using easyhook?

    Comment by Smith — Friday 23 January 2009 @ 5:46

  17. Can you resend the sample code? Thank you very much.

    Comment by max — Tuesday 27 January 2009 @ 13:31

  18. Hi
    Thanks for this nice tool. I have tested and runs well. But very unfortunately we need IE7. So please please publish a version for IE7.

    Thanks once again!

    Comment by Lucy — Thursday 29 January 2009 @ 10:32

  19. @Lucy Why do you need this? I’m wondering why I’m getting all these requests for IE7?

    Comment by Didier Stevens — Friday 30 January 2009 @ 13:47

  20. Hi Didier
    I don’t know why Lucy want this. But I can tell you why I need it badly. Infact everywhere now there is IE7. You know IE6 is obsolete.
    I am researching for a large software development which will work on Firefox, IE and opera. In that case the most problem we face about IE7. We found almost way. But your article shows us some way. This is really great article. Many thanks again.
    I hope you will find a method for IE7 as well as you are really great.

    Comment by Smith — Friday 30 January 2009 @ 17:23

  21. Hi
    Whenever you publish about IE7 please inform in this thread. This is because I don’t want to miss it!

    Comment by Lucy — Sunday 1 February 2009 @ 8:09

  22. A problem, the hook really works the first time httpopenrequest is called.
    It seems it does not work on all the following requests. Could you tell me why.
    Tested on IE7 and xp sp3. I have modified your code to hook httpopenrequestw.

    Comment by max — Sunday 1 February 2009 @ 15:04

  23. And when I hook Internetreadfile, it made the ie7 crash.

    Comment by max — Sunday 1 February 2009 @ 16:34

  24. Internetreadfile hooks OK now, but still works on the first request. Can you tell why and how to solve this problem? Thank you very much.

    Comment by max — Monday 2 February 2009 @ 3:40

  25. Very Interesting information. When I opened IE with blank page, and then close ie. The debugview give such information:
    [1316] Hook WinINet DLL_PROCESS_ATTACH
    [1316] WININET.dll HttpOpenRequestW (42164050) 420D102F -> 10001000
    [1316] WININET.dll InternetConnectW (42164080) 420D1002 -> 100010A0
    [1316] WININET.dll HttpSendRequestW (4216404C) 420E2566 -> 10001110
    [1316] WININET.dll InternetReadFile (42164078) 420D0E0E -> 10001170
    [1316] Unhook WinINet DLL_PROCESS_DETACH
    [1316] WININET.dll HttpOpenRequestW (42164050) 10001000 -> 420D102F
    [1316] WININET.dll InternetConnectW (42164080) 100010A0 -> 420D1002
    [1316] WININET.dll HttpSendRequestW (4216404C) 10001110 -> 420E2566
    [1316] WININET.dll InternetReadFile (42164078) 10001170 -> 420D0E0E
    It seemed that hooking and restoring the functions are both ok.

    But if I do some requests, things changed.
    [3376] Hook WinINet DLL_PROCESS_ATTACH
    [3376] WININET.dll HttpOpenRequestW (42164050) 420D102F -> 10001000
    [3376] WININET.dll InternetConnectW (42164080) 420D1002 -> 100010A0
    [3376] WININET.dll HttpSendRequestW (4216404C) 420E2566 -> 10001110
    [3376] WININET.dll InternetReadFile (42164078) 420D0E0E -> 10001170
    [3376] http://www.mobilesaid.com
    [3376] GET
    [3376] /ip.php
    [3376] Accept-Language: en-US
    [3376] UA-CPU: x86
    [3376] Accept-Encoding: gzip, deflate
    [3376] HookInternetReadFile dwNumberOfBytesToRead 00000012
    [3376] HookInternetReadFile *lpdwNumberOfBytesRead 00000012 data
    [3376] Unhook WinINet DLL_PROCESS_DETACH
    [3376] WININET.dll HttpOpenRequestW (42164050) 41FE5D52 -> 420D102F
    [3376] WININET.dll InternetConnectW (42164080) 41FE5B78 -> 420D1002
    [3376] WININET.dll HttpSendRequestW (4216404C) 420007F5 -> 420E2566
    [3376] WININET.dll InternetReadFile (42164078) 41FEABA4 -> 420D0E0E

    Look at the addresses of the hooked functions when detach. It have been changed. Who changed the addresses? But the IE7 works really ok, at the same time the hooks did not work.
    Does IE5 and IE6 have the same problem?

    Comment by max — Monday 2 February 2009 @ 4:30

  26. Hi Max
    It seems all of us are trying to hook IE7 using Didier code. I have also tried same way usig “W” instead of “A” but failed 😦
    Hopefully Didier will give us another version which will hook both IE6 & IE7. Waiting for Didier.

    Comment by Lucy — Thursday 5 February 2009 @ 4:26

  27. I have successfully hooked the functions by the way of modifying the first 5 bytes in the function code, which jmp to the hook function. Patching IAT may not work in such a situation.

    Comment by max — Saturday 7 February 2009 @ 15:06

  28. I was able to hook on IE7 by using EasyHook library, but no by using BPMTK or similar IAT patching systems.

    Comment by Pablo — Monday 9 February 2009 @ 18:17

RSS feed for comments on this post. TrackBack URI

Leave a Reply (comments are moderated)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at WordPress.com.