COM之ActiveX逆向简单方法

3 篇文章 0 订阅

一.前言. 以下IE中ActiveX控件中对调用的属性,方法等的一些逆向分析纪录文字. 阅读此文你许要一点点的com基础知识.:) 二.认识ActiveX IE中可以调用几乎所有在HKEY_CLASSES_ROOT/CLSID键下的Object. 调用方式很简单: 这样会带来一些安全问题. 比如最近很多的 com 创建实例初始化的漏洞公告. 这里不对这些进行研究. 对于这些COM组件的属性(property)和方法(method), 我们可以通过script来调用. 比如, 对上述组件的属性,假设是test,方法(假设是methodtest),参数是BSTR类型的: 很简单. 但是也因为script的原因, 对一些复杂的变量,比如COM中的VARIANT类型变量, 就很难调用起来了. 并不是每个com都可以通过script调用. 一般说来,只有com 组件的interface继承了 IDispatch 接口才可以被 script调用(有些COM书籍上称之为动态调用). IE调用这些com的时候,如果没有被标记"safe call",那么在client浏览的时候,就会有一个提示"acticvex组建 调用是否安全"之类的对话框, 当然,这个和浏览器的安全区域设置有关系. 关于ActiveX安全可以看这里:http://msdn.microsoft.com/worksh ... ctivex/security.asp 三.认识TypeLib 现在假设我们知道有哪些com可以被我们调用了而且client端不会有提示了,比如win2k sp4 IE6 sp1中的 [+] {71650000-E8A8-11D2-9652-00C04FC30871}: 首先我们应该要知道的是它是由哪个文件提供的. 到HKEY_CLASSES_ROOT/CLSID下的{71650000-E8A8-11D2-9652-00C04FC30871}找InprocServer32键的default value: 它所对应的DLL是:G:/WINNT/system32/webvw.dll 这个时候你就可以IDA打开它进行分析了. 然后我们需要知道它的typelib是由谁提供的: HKEY_CLASSES_ROOT/CLSID/{71650000-E8A8-11D2-9652-00C04FC30871}/TypeLib: {cd603fc0-1f11-11d1-9e88-00c04fdcab92} 再转到注册表: HKEY_CLASSES_ROOT/TypeLib/{CD603FC0-1F11-11D1-9E88-00C04FDCAB92} 下就有对应版本的typelib提供者: HKEY_CLASSES_ROOT/TypeLib/{CD603FC0-1F11-11D1-9E88-00C04FDCAB92}/1.0/0/win32 default value: G:/WINNT/system32/webvw.dll 四. 获取注册类 下一步就是得到接口描述了. 用oleview打开该DLL(使用File->View TypeLib打开,也可以使用LoadTypeLib()获得一个ITypeLib指针自己获取). 得到三个coclass: [ uuid(71650000-E8A8-11D2-9652-00C04FC30871), helpstring("ThumbCtl Class") ] coclass ThumbCtl { [default] interface IThumbCtl; [default, source] dispinterface DThumbCtlEvents; }; [ uuid(BCFD624E-705A-11D2-A2AF-00C04FC30871), helpstring("WebView Class") ] coclass WebView { [default] interface IWebView; }; [ uuid(844F4806-E8A8-11D2-9652-00C04FC30871), helpstring("WebViewFolderIcon Class") ] coclass WebViewFolderIcon { [default] interface IWebViewFolderIcon2; }; 我们得到我们所需要的ThumbCtl 注册类, 它有两个接口, 注意的是,我们用script只能 调用默认的一个Interface. 我们列举一下IThumbCtl接口: [ uuid(E8ACCAE0-23E6-11D1-9E88-00C04FDCAB92), helpstring("IThumbCtl Interface"), dual ] dispinterface IThumbCtl { properties: methods: [id(0x00000001), helpstring("method displayFile")] VARIANT_BOOL displayFile(BSTR bsFileName); [id(0x00000002), helpstring("method haveThumbnail")] VARIANT_BOOL haveThumbnail(); [id(0x00000003), propget, helpstring("property freeSpace")] BSTR freeSpace(); [id(0x00000004), propget, helpstring("property usedSpace")] BSTR usedSpace(); [id(0x00000005), propget, helpstring("property totalSpace")] BSTR totalSpace(); }; 可以看到的是, IThumbCtl 接口提供两个方法(displayFile(),haveThumbnail()),两个属性: freeSpace(),usedSpace(),totalSpace(); 好,我们已经知道在script中可以调用该控件的方法和属性了. 下一步我们需要的就是将 这些函数和我们的反汇编结果联系起来, 我们需要知道哪个函数是负责处理displayFile, 哪些函数是负责其他方法和属性的. 根据com的规则,对于赋值的属性处理函数,名称默认前面都要加上get_的名称,而对于取值的属性处理函数来说, 名称默认都要加上put_的名称,也就是说,我们需要为我们的汇编代码重新指定: displayFile(),haveThumbnail(),get_freeSpace(),get_usedSpace(),get_totalSpace()函数名称. 因为 提供接口的类是继承 IDispatch 的,所以还要指定如下的名称: HRESULT _stdcall GetTypeInfoCount([out] unsigned int* pctinfo); HRESULT _stdcall GetTypeInfo( [in] unsigned int itinfo, [in] unsigned long lcid, [out] void** pptinfo); HRESULT _stdcall GetIDsOfNames( [in] GUID* riid, [in] char** rgszNames, [in] unsigned int cNames, [in] unsigned long lcid, [out] long* rgdispid); HRESULT _stdcall Invoke( [in] long dispidMember, [in] GUID* riid, [in] unsigned long lcid, [in] unsigned short wFlags, [in] DISPPARAMS* pdispparams, [out] VARIANT* pvarResult, [out] EXCEPINFO* pexcepinfo, [out] unsigned int* puArgErr); 同时,IDispatch又是继承 IUnknown 的,所以还有: HRESULT _stdcall QueryInterface([in] GUID* riid,[out] void** ppvObj); unsigned long _stdcall AddRef(); unsigned long _stdcall Release(); 计算一下,我们共有 5 + 4 + 3 = 12个函数名称需要指定. 这里有一个关键的数字 12 , 同时也意味着我们的vftable的大小也是12个. 接口取完了,剩下就是处理我们的汇编代码了. 五. 麻烦的vftable 当IE调用一个object的时候,首先要调用实现object的dll/ocx 输出的 DllGetClassObject 函数. 该函数原形如下: STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv); ppv是一个指向IClassFactory的指针. 通过调用IClassFactory::CreateInstance()来获取所需要的 类. 下面就是CreateInstance调用原形: HRESULT CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppvObject); 这次返回的ppvObject就是一个指向包含我们前面所说的12个函数的vftable的指针. 这句话比较难理解,图示如下. [ecx] ppvObject -> class -> [ecx] -> vftable1 [ecx+4] -> vftable2 [ecx+8] -> vftable3 ..... 现在我们有了这个ppvObject,那么我们怎么确定我们所要找的vftable是vftable1还是vftable2或者是vftable3呢? 我们有两个方法: (1).这个时候我们就要看汇编中返回 ppvObject 后,立即调用的是谁的 QueryInterface(). 比如,webvw.dll中: .text:658FDCC3 call ??0?$CComObject@VCThumbCtl@@@ATL@@QAE@PAX@Z ; ATL::CComObject::CComObject(void *) .text:658FDCC8 mov esi, eax .text:658FDCCA jmp short loc_658FDCCE .text:658FDCCC ; ---------------------------------------------------------------------------- .text:658FDCCC .text:658FDCCC loc_658FDCCC: ; CODE XREF: ATL::CComCreator>::CreateInstance(void *,_GUID const &,void * *)+14j .text:658FDCCC xor esi, esi .text:658FDCCE .text:658FDCCE loc_658FDCCE: ; CODE XREF: ATL::CComCreator>::CreateInstance(void *,_GUID const &,void * *)+23j .text:658FDCCE test esi, esi .text:658FDCD0 jz short loc_658FDCF7 .text:658FDCD2 push [esp+arg_8] .text:658FDCD6 mov ecx, [esi+60h] .text:658FDCD9 lea eax, [esi+60h] .text:658FDCDC push [esp+4+arg_4] .text:658FDCE0 push eax .text:658FDCE1 call dword ptr [ecx] 看到这个[esi+60h]吗? 这里的地址就是我们要找的vftable. (2). 数个数. 看看每个vftable中的个数是否相等. 这个方法比较笨. 相等就认为是我们要找的,如果刚好有多个相等,那么就 需要一一分析. 好,现在我们已经得到了我们所要的vftable,我们给他们一一更名吧. 顺便说一句, oleview返回的接口定义里面的函数名称是按顺序的,也就是说displayFile()排在haveThumbnail() 前面,那么在vtable中,displayFile函数地址同样写在haveThumbnail所在位置前面. 按顺序我们得到: VARIANT_BOOL displayFile(BSTR bsFileName); VARIANT_BOOL haveThumbnail(); BSTR get_freeSpace(); BSTR get_usedSpace(); BSTR get_totalSpace(); HRESULT _stdcall GetTypeInfoCount([out] unsigned int* pctinfo); HRESULT _stdcall GetTypeInfo( [in] unsigned int itinfo, [in] unsigned long lcid, [out] void** pptinfo); HRESULT _stdcall GetIDsOfNames( [in] GUID* riid, [in] char** rgszNames, [in] unsigned int cNames, [in] unsigned long lcid, [out] long* rgdispid); HRESULT _stdcall Invoke( [in] long dispidMember, [in] GUID* riid, [in] unsigned long lcid, [in] unsigned short wFlags, [in] DISPPARAMS* pdispparams, [out] VARIANT* pvarResult, [out] EXCEPINFO* pexcepinfo, [out] unsigned int* puArgErr); HRESULT _stdcall QueryInterface([in] GUID* riid,[out] void** ppvObj); unsigned long _stdcall AddRef(); unsigned long _stdcall Release(); 写个idc脚本来处理吧:) 六. 参考: 1. MSDN 2. O'Reilly <> 七.附件 附上一个perl自动生成idc的程序: #!/usr/bin/perl $argc=@ARGV; if($argc<1) { print "Usage:$0 /n"; exit; } $sfile = $ARGV[0]; $dfileprv = "webvw"; #idc脚本文件名前缀,可以留空 $StartAddr = 0x658F1F08; #第一个函数的地址 $EndAddr = 0x658F1F34; #最后一个函数的地址 open(FILE,"<$sfile") || die "Cannot open $sfile erorr:$!/n"; my @FileContent = ; close(FILE); my $FileLineNumber = @FileContent; my ($FunctionName,$InterFaceName,$dfilename,$i,$startline,$endline,$FunctionPrevName,$FunctionDescribe,$FunctionString); my $FunctionNumber = 0; my @FunctionNameArray; my $addr = 0; $subfunction="static MakeAddrName(ea,str)/n"; $subfunction.="{/n/t auto addr;/n/n"; $subfunction.="/t addr = Dword(ea);/n"; $subfunction.="/t if(MakeNameEx(addr,str,SN_NON_PUBLIC | SN_NOWARN) == 0)/n"; $subfunction.="/t {/n/t/t Message(/"MakeName value(0x%x):0x%x to %s Failed./",ea,addr,str);/n"; $subfunction.="/t }/n}"; for($i=0;$i<$FileLineNumber;$i++) { $tvar = $FileContent[$i]; chomp $tvar; #print "$tvar/n"; if($tvar=~/interface/s+(/w+)/i) { #interface IActiveMovie : IDispatch { $InterFaceName = $1; print "Found interface $InterFaceName/n"; $dfilename = $dfileprv."_$InterFaceName.idc"; #last; for($startline = $i+1;$startline < $FileLineNumber;$startline ++) { $svar = $FileContent[$startline]; chomp $svar; #interface描述结束符号 if($svar=~/^/s{0,}/}/s{0,}/;/) { last; } #print "$svar/n"; #$svar=" [id(0xfffffdd8)]"; if($svar=~/^/s{0,}/[(.*?)/]/s{0,}(.*)/s{0,}$/) { $FunctionDescribe = $1; my $StrAfterFunctionDescribe = $2; #print "FunctionDescribe:$FunctionDescribe,StrAfterFunctionDescribe:$StrAfterFunctionDescribe/n"; #属性函数名称分辨 if($FunctionDescribe=~/propget/) { $FunctionPrevName="get_"; } elsif($FunctionDescribe=~/propput/) { $FunctionPrevName="put_"; } else { $FunctionPrevName=""; } #看是一行就写完的吗 if($StrAfterFunctionDescribe=~//;/) #开始寻找函数名称 { $FunctionString = $StrAfterFunctionDescribe; } else { #函数名字在第二行 $startline++; #print "$FileContent[$startline]/n"; $FunctionString = $StrAfterFunctionDescribe.$FileContent[$startline]; } chomp $FunctionString; #print "FunctionString:$FunctionString/n"; if($FunctionString=~//s{0,}(/w+?)/(/) { $FunctionName = $1; $FunctionName = $FunctionPrevName.$FunctionName; push @FunctionNameArray,$FunctionName; #print "Found Function:$FunctionName/n"; $FunctionNumber++; } #print "found id:$1/n"; } #last; } } } printf "Total %d+7=%d Functions/n",$FunctionNumber,$FunctionNumber+7; #检查要修改的和得出的函数个数是否符合 $WantNamedTableCount = ($EndAddr - $StartAddr)/4 + 1; if($WantNamedTableCount != ($FunctionNumber + 7)) { print "Wanted $WantNamedTableCount functions,NOT MATCH.../n"; print "Continue...?(y/n)"; $choice = ; chomp $choice; if($choice ne "y") { exit; } } $addr = $StartAddr; #success MakeNameEx (long ea,string name,long flags); open(DFILE,">$dfilename") || die "Cannot open $dfilename For write:$!/n"; print DFILE "//By bkbll from ActiveX reverse/r/n"; print DFILE "#include /n/n"; print DFILE $subfunction; print DFILE "/n"; print DFILE "static main()/n{/n"; printf DFILE " MakeAddrName(0x%x,/"%s::QueryInterFace/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::Addref/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::Release/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::GetTypeInfoCount/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::GetTypeInfo/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::GetIDsOfNames/");/n",$addr,${InterFaceName}; $addr+=4; printf DFILE " MakeAddrName(0x%x,/"%s::Invoke/");/n",$addr,${InterFaceName}; $addr+=4; for($addr,$i= 0 ;$addr<=$EndAddr;$addr+=4,$i++) { printf DFILE " MakeAddrName(0x%x,/"%s::$FunctionNameArray[$i]/");/n",$addr,${InterFaceName}; } print DFILE "}/n"; close DFILE;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
COMComponent Object Model)和ActiveX是常用于Windows平台上的组件技术。以下是关于COM/ActiveX的一些实用技巧。 1. COM/ActiveX的理解:COM是一种面向对象的组件技术,允许不同的软件组件在不同的应用程序间进行交互。ActiveX是基于COM的技术,是一种可嵌入到网页中的交互式控件。 2. 使用COM/ActiveX控件:通过创建COM对象或引用已有的COM对象,可以在应用程序中使用COM/ActiveX控件。使用COM/ActiveX控件可以实现各种功能,如图形界面、文档编辑、数据处理等。 3. 注册和反注册COM/ActiveX控件:COM/ActiveX控件需要注册才能在系统中使用。使用命令行工具“regsvr32”可以注册或反注册COM/ActiveX控件。例如,运行“regsvr32 example.dll”可以注册名为example.dllCOM/ActiveX控件。 4. 使用COM/ActiveX控件的应注意事项:在使用COM/ActiveX控件时,需要注意以下几点: - 选择合适的控件:根据需求选择合适的COM/ActiveX控件,确保功能和性能满足需求。 - 版本和兼容性:确保应用程序与使用的COM/ActiveX控件是兼容的,避免版本冲突和不兼容的问题。 - 安全性:COM/ActiveX控件可能存在安全风险,因此需要谨慎对待。仅使用已验证和可信的控件,确保系统的安全性。 5. 调试COM/ActiveX控件:在使用COM/ActiveX控件时,可能会遇到调试问题。可以使用调试工具(如Visual Studio)进行调试,以定位和解决问题。 总之,COM/ActiveX是一种强大的组件技术,可以为Windows应用程序提供丰富的功能和交互性。正确使用和管理COM/ActiveX控件,可以提高应用程序的开发效率和功能扩展性。同时,需要注意安全性和兼容性等问题,以确保系统的稳定和安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值