TippingPoint Digital Vaccine Laboratories
DID YOU KNOW... TippingPoint customers were protected against 0-day exploitation of MS07-017 two years prior to the exploit being discovered in the wild.

MindshaRE: Finding ActiveX Methods Dynamically

Today we step back into the world of COM/ActiveX to dynamically find object methods in a binary. This is probably the quickest way to identify the code handling the javascript/vbscript invocation of methods. This can then allow the researcher to audit the method for any potential vulnerabilities.

MindshaRE is our monthly look at some simple reverse engineering tips and tricks. The goal is to keep things small and discuss every day aspects of reversing. You can view previous entries here by going through our blog history.

The dynamic nature of COM poses a difficult task for the static reverse engineer. In vulnerability analysis we are normally not concerned with the internals of COM and how interfaces are queried and instantiated. Instead we want to see the method being called with our data. Here is a quick example of a call to a method via javascript.
function doAxe() {
    axe = new ActiveXObject("Internet.HHCtrl.1");
    axe.syncURL("http://dvlabs.tippingpoint.com");
}
What we are concerned with today is the location of the method being called in the dll implementing the HHCtrl interface hhctrl.ocx. We are trying to take a deeper look at how syncURL handles the incoming string parameter.

For example sake lets look at the HHCtrl interface in hhctrl.ocx with symbolic information.
const CHtmlHelpControl::`vftable'{for `IHHCtrl'}
  dd offset [thunk]:CHtmlHelpControl::QueryInterface`adjustor{164}'
  dd offset [thunk]:CHtmlHelpControl::AddRef`adjustor{164}'
  dd offset [thunk]:CHtmlHelpControl::Release`adjustor{164}'
  dd offset [thunk]:CHtmlHelpControl::GetTypeInfoCount`adjustor{192}'
  dd offset [thunk]:CHtmlHelpControl::GetTypeInfo`adjustor{192}'
  dd offset [thunk]:CHtmlHelpControl::GetIDsOfNames`adjustor{192}'
  dd offset [thunk]:CHtmlHelpControl::Invoke`adjustor{192}'
  dd offset CHtmlHelpControl::put_Image(ushort *)
  dd offset CHtmlHelpControl::get_Image(ushort * *)
  dd offset CHtmlHelpControl::HHClick(void)
  dd offset CHtmlHelpControl::HHClick(void)
  dd offset CHtmlHelpControl::Print(void)
  dd offset CHtmlHelpControl::syncURL(ushort *)
  dd offset CHtmlHelpControl::TCard(uint,long)
  dd offset CHtmlHelpControl::TextPopup(ushort *,ushort *,int,int,ulong,ulong)
As we can see the interface implements the required private methods, and it exposes the objects public attributes and methods. In a perfect world we have detailed symbolic information like this, and we can simply navigate to CHtmlHelpControl::syncURL and start auditing. However in most cases we do not have this information, and statically tracking down the constructors for these interfaces can be time consuming. So lets do it dynamically.

Before we begin lets take a quick look at how jscript.dll handles the invocation. It first creates an ActiveXObject for use when parsing javascript in an html file. It then calls JScript!VAR::InvokeByName with our method name resulting in the querying of IDispatch::GetIDsOfNames and the eventual call to IDispatch::Invoke. We can see the eventual Invoke call inside of jscript.dll!IDispatchInvoke2 below.
.text:633A8FF7 034 mov     edx, [eax+18h]  ; hhctrl!CHtmlHelpControl::Invoke
.text:633A8FFA 034 push    offset _GUID_NULL
.text:633A8FFF 038 push    ecx
.text:633A9000 03C push    ebx
.text:633A9001 040 call    edx

JScript!IDispatchInvoke2+0xe3:
633a9001 call    edx {hhctrl!CHtmlHelpControl::Invoke (7e4d680a)}
Now that we have the location of the Invoke method of the interface we can record the address, perform a cross reference, and be at the vtable of interest. But how do we know which one is truly the syncURL method? Lets continue in the debugger watching some key locations.
eax=7e4b3378 ebx=0035f288 ecx=0201c534 edx=7e4d680a esi=0035f1c8 edi=00000000
eip=7e4b9d98 esp=0201c50c ebp=0201c524 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
hhctrl!CAutomationObject::Invoke+0x32:
7e4b9d98 call    dword ptr [eax+0Ch]  7e4b3384={hhctrl!CHtmlHelpControl::GetTypeInfo (7e4d674f)}

eax=02ce3ff0 ebx=0035f288 ecx=77126c58 edx=7e4d680a esi=0035f1c8 edi=00000000
eip=7e4b9dc2 esp=0201c4fc ebp=0201c524 iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000286
hhctrl!CAutomationObject::Invoke+0x5c:
7e4b9dc2 call    dword ptr [ecx+2Ch]  77126c84={OLEAUT32!CTypeInfo2::Invoke (771360dc)}

eax=0201c4d8 ebx=0201c62c ecx=02ce3fec edx=00000005 esi=02a18fcc edi=00000000
eip=77136286 esp=0201c468 ebp=0201c4f4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!CTypeInfo2::Invoke+0x1d2:
77136286 call    OLEAUT32!CTypeInfo2::GetInvokeArgs (7713648e)

eax=00000030 ebx=0201c498 ecx=02ce02d4 edx=00000001 esi=02a18fcc edi=00000000
eip=771362e3 esp=0201c46c ebp=0201c4f4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
OLEAUT32!CTypeInfo2::Invoke+0x22f:
771362e3 call    OLEAUT32!DispCallFunc (77135c16)

eax=7ffd6000 ebx=7e4b3270 ecx=7e4d5e88 edx=02ce031a esi=0201c5d0 edi=00000000
eip=77135cd7 esp=0201c450 ebp=0201c464 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!DispCallFunc+0x168:
77135cd7 call    ecx {hhctrl!CHtmlHelpControl::syncURL (7e4d5e88)}
Finally we see our method being invoked. We can try to set a breakpoint on this call and see if it triggers properly for all methods.
0:008> bp 77135cd7
0:008> g
Breakpoint 7 hit
eax=7ffd6000 ebx=7e4b3270 ecx=7e4d5ee6 edx=00217bca esi=00217b7c edi=00000000
eip=77135cd7 esp=0201c44c ebp=0201c464 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!DispCallFunc+0x168:
77135cd7 call    ecx {hhctrl!CHtmlHelpControl::TCard (7e4d5ee6)}
0:008> g
Breakpoint 7 hit
eax=7ffd6000 ebx=7e4b3270 ecx=7e4d5f67 edx=02d072da esi=038d3168 edi=00000000
eip=77135cd7 esp=0201c43c ebp=0201c464 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!DispCallFunc+0x168:
77135cd7 call    ecx {hhctrl!CHtmlHelpControl::TextPopup (7e4d5f67)}
Or more generically we can look at the arguments to oleaut32!DispCallFunc.
0:008> bp OLEAUT32!DispCallFunc
0:008> g
Breakpoint 8 hit
eax=00000038 ebx=0201c498 ecx=02d071cc edx=00000006 esi=02429030 edi=00000000
eip=77135c16 esp=0201c468 ebp=0201c4f4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!DispCallFunc:
77135c16 55              push    ebp
0:008> u poi(poi(poi(esp+4))+(poi(esp+8)))
hhctrl!CHtmlHelpControl::TextPopup:
7e4d5f67 8bff            mov     edi,edi
7e4d5f69 55              push    ebp
7e4d5f6a 8bec            mov     ebp,esp
7e4d5f6c 83ec34          sub     esp,34h
7e4d5f6f 8b450c          mov     eax,dword ptr [ebp+0Ch]
7e4d5f72 85c0            test    eax,eax
7e4d5f74 7464            je      hhctrl!CHtmlHelpControl::TextPopup+0x73 (7e4d5fda)
7e4d5f76 8365d000        and     dword ptr [ebp-30h],0
Now that we don't have to worry about address conflicts we can turn this into a fairly decent logging bp for tracking down any method we invoke via javascript.
0:010> bp OLEAUT32!DispCallFunc "u poi(poi(poi(esp+4))+(poi(esp+8))) L1;gc"
breakpoint 8 redefined
0:010> g
hhctrl!CHtmlHelpControl::TextPopup:
7e4d5f67 8bff            mov     edi,edi
That is a little better. I hope you can find this useful when auditing ActiveX controls. Sometimes dynamic analysis is the quickest way to get started on the interested things.

-Cody
 
Tags:
Published On: 2009-06-01 12:17:44

Comments post a comment

  1. Anonymous commented on 2009-06-02 @ 08:04

    MindshaRE is our weekly look at..
    MindshaRE is our sometimes bi-weekly look at..
    MindshaRE is our monthly look at..

    Hope next time it isn't our yearly look at ;) No seriously, I really enjoyed the weekly look.

  2. Cody Pierce commented on 2009-06-03 @ 18:42

    @Anonymous:

    Hah I hope it doesn't turn into a yearly look either. Time is usually the #1 factor in my delays. Maybe I will reach out to some potential guest writers if I cant keep up the pace :)

  3. Anthony Lai commented on 2009-06-05 @ 05:00

    Thanks and carry go. Could you please advise any resources/URLs to learn fuzzing and reversing on ActiveX?

  4. Cody Pierce commented on 2009-06-05 @ 16:38

    @Anthony Lai

    I do not know of any resources for reversing ActiveX but here are a few about fuzzing ActiveX.

    http://www.cert.org/archive/pdf/dranzer.pdf
    http://www.cert.org/vuls/discovery/dranzer.html
    http://labs.idefense.com/software/fuzzing.php#more_comraider
    http://www.uninformed.org/?v=9&a=2&t=pdf
    http://www.metasploit.com/users/hdm/tools/axman/

  5. Anthony Lai, Valkyrie-X Security Research Lab commented on 2009-06-22 @ 04:09

    Thank you for your sharing, Cody ;-)

  6. Leslie Lavigne from Ahnlab Inc. commented on 2009-07-22 @ 11:52

    Thank you for sharing this tip!Very useful it is!

    you known, NOW there are many spywares/adwares which implemented as a BHO/IE-Toolbar or other IE-related way.

    I know little about how to debug this kind of spyware(BHO/IE-Toolbar)

    Would you like to share some tips about that!

    Thank you!

  7. PJ commented on 2009-08-05 @ 16:04

    Just wanted to say thank you for sharing! I always look forward to reading your posts.


Trackback