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],0Now 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,ediThat 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
