php creatobject,监视VB调用CreateObject

【文章标题】: 监视VB调用CreateObject

【文章作者】: Jiangjing

【下载地址】: 自己搜索下载

【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

--------------------------------------------------------------------------------

【详细过程】

背景:

工作中开发VB程序,不同工程中调用Dll,基本上都是动态,使用CreateObject方法,本来厂商有个调试器来监视VB程序的

CreateObject,但是在某些电脑上运行崩溃.极度郁闷.有时候Active dll被破坏了没法大致确定位置.不用在测试机器上加

一大堆源码跑起来跟踪.所以想DIY一个自己的伪监视器...

开工:

随便写个代码

'---VB Code

Private Sub Command1_Click()

On Error GoTo ErrHandler

Dim t As Object

Set t = CreateObject("pro_dll.clsdll")  '--随便写个名称

Exit Sub

ErrHandler:

MsgBox Err.Number & vbCrLf & Err.Description

End Sub

编译为EXE,执行,问题来了,怎么来监视呢?拿出经常用的工具OD,来调试跟踪一下这个EXE

发现CreateObject调用的是MSVBVM60.DLL的rtcCreateObject2

先看下MSVBVM60.DLL导出的函数接口

==================================================

函数名称 : rtcCreateObject

偏移地址 : 0x735192b7

相对偏移地址 : 0x000d92b7

顺序数 : 625 (0x271)

文件名 : msvbvm60.dll

类型 : 导出函数

==================================================

==================================================

函数名称 : rtcCreateObject2

偏移地址 : 0x735193c0

相对偏移地址 : 0x000d93c0

顺序数 : 716 (0x2cc)

文件名 : msvbvm60.dll

类型 : 导出函数

==================================================

以下是EXE汇编

00402084   .  53            push    ebx

00402085   .  68 04194000   push    00401904                         ;  pro_dll.clsdll

0040208A   .  8D45 B0       lea     eax, dword ptr [ebp-50]

0040208D   .  50            push    eax

0040208E   .  FF15 78104000 call    dword ptr []     ;  MSVBVM60.rtcCreateObject2

于是我们跟踪进去,调试一下,CreateObject成功的时候与失败的时候应该有区分的.....[暂时忽略on error resume next]

dll空间

735193C0 >  55              push    ebp                              ; rtcCreateObject2 //入口

735193C1    8BEC            mov     ebp, esp

735193C3    83EC 78         sub     esp, 78

735193C6    8B45 0C         mov     eax, dword ptr [ebp+C]

往下走...省略一大堆代码

73519636    5F              pop     edi

73519637    5E              pop     esi

73519638    5B              pop     ebx

73519639    C9              leave

7351963A    C2 0C00         retn    0C

7351963D    8B45 8C         mov     eax, dword ptr [ebp-74]

73519640    50              push    eax

73519641    8B08            mov     ecx, dword ptr [eax]

73519643    FF51 08         call    dword ptr [ecx+8]

73519646    8B45 98         mov     eax, dword ptr [ebp-68]

73519649    66:C745 E8 0900 mov     word ptr [ebp-18], 9

7351964F  ^ EB D6           jmp     short 73519627

73519651    8D45 D8         lea     eax, dword ptr [ebp-28]

73519654    50              push    eax

73519655    FF75 0C         push    dword ptr [ebp+C]    //[ebp+C]里面存放的就是CreateObject的参数,需要这东西,才知道调用了什么组件

73519658    FF15 30ED5473   call    dword ptr [7354ED30]             ; ole32.CLSIDFromProgIDEx

7351965E    3BC6            cmp     eax, esi            //如果创建Active dll 成功,eax=0,否则eax不等于0

73519660    0F8C A7000000   jl      7351970D            //我们修要修改这个跳转,来调用一下自己的代码

73519666    56              push    esi

73519667    56              push    esi

73519668    FF15 041A4473   call    dword ptr []     ; OLEAUT32.SetErrorInfo

注意分析

7351965E    3BC6            cmp     eax, esi  //关键点在这

--找一段空白的空间[7353C3D6],先跳转到7353C3D6,处理完之后,在返回73519663,这样就不影响原有功能

73519654 . 50 push eax

73519655 . FF75 0C push dword ptr [ebp+C]

73519658 . FF15 30ED5473 call dword ptr [7354ED30]

7351965E . E9 732D0200 jmp 7353C3D6                     //修改汇编

73519663 90 nop

73519664 90 nop

73519665 90 nop

73519666 > 56 push esi

73519667 . 56 push esi

--7353C3D6

7353C3D3 00 db 00

7353C3D4 00 db 00

7353C3D5 00 db 00

7353C3D6 > 83F8 00 cmp eax, 0                  //根据eax值来判断CreateObject成功失败!!!

7353C3D9 . 75 04 jnz short 7353C3DF

7353C3DB . 6A 01 push 1                        //参数1

7353C3DD . EB 02 jmp short 7353C3E1

7353C3DF > 6A 00 push 0                        //参数1

7353C3E1 > FF75 0C push dword ptr [ebp+C]      //参数2  备注:[ebp+c]是CrateObject的第一个参数

7353C3E4 . E8 8CFFFFFF call 7353C375           //我的[函数A]

7353C3E9 . 83C4 08 add esp, 8                  //注意,,,这里传了2个参数进去.需要处理一下

7353C3EC . 90 nop

7353C3ED . 90 nop

7353C3EE . 3BC6 cmp eax, esi                  //调用添加的[函数A]后还原原有逻辑

7353C3F0 .^ 0F8C 17D3FDF>jl 7351970D          //xxx

7353C3F6 .^ E9 6BD2FDFF jmp 73519663          //跳回,继续顺序执行

--7353C375

7353C374    90              nop

7353C375    90              nop     //

7353C376    90              nop

7353C377    90              nop

7353C378    56              push    esi

7353C379    68 30CC5373     push    7353CC30                         //注意1

7353C37E    FF15 F0114473   call    dword ptr [; kernel32.LoadLibraryA   //找到这个API

7353C384    8BF0            mov     esi, eax

7353C386    85F6            test    esi, esi

7353C388    74 23           je      short 7353C3AD

7353C38A    68 20CC5373     push    7353CC20                         //注意2

7353C38F    56              push    esi

7353C390    FF15 F4114473   call    dword ptr [; kernel32.GetProcAddress   //找到这个API,

7353C396    85C0            test    eax, eax

7353C398    74 0C           je      short 7353C3A6

7353C39A    8B4C24 0C       mov     ecx, dword ptr [esp+C]

7353C39E    8B5424 08       mov     edx, dword ptr [esp+8]

7353C3A2    51              push    ecx

7353C3A3    52              push    edx

7353C3A4    FFD0            call    eax

7353C3A6    56              push    esi

7353C3A7    FF15 60104473   call    dword ptr [; kernel32.FreeLibrary

7353C3AD    5E              pop     esi

7353C3AE    C3              retn

//这里需要注意4个地方

1:这段代码对于不是很熟悉汇编的不好理解,

可以用VC写段调用dll的代码,2个参数值,然后用OD调试一下,把汇编代码粘贴进来

2:kernel32.LoadLibraryA,kernel32.GetProcAddress,kernel32.FreeLibrary 这3个API函数的地址怎么确定,

可以在OD里面bpx hmemcpy 查找原有程序调用该API地址,复制过来即可

3:[注意1],有个push,这个是LoadLibraryA的参数,一猜就知道,那就是这段汇编要调用我们自己定义的一个xxx.dll文件名

4:[注意2],也有个push,是kernel32.GetProcAddress的参数,就是xxx.dll导出的函数接口YYY

剩下的就是我们编写xxx.dll中的YYY函数,

函数原型应该能猜解出来

void GetString(char *p,int iFlag)     参数iflag是先入栈的,然后依次向左...

接下来dll应该改什么呢?把每次调用的CrateObject的第一个参数[ebp+c]插入数据库(最近一直搞数据库,脑袋都僵硬了),

实时刷新.这样好像不太好,应该FindWindow,然后SendMessage,把里面的2个值发送到我们自己的监视程序界面上去,才显

的直观,如果有更好的意见或建议,欢迎拍板砖

以下是xxx.dll里面YYY函数

发送格式[参数1]:进程ID号|pro_dll.clsdll,[参数2:] 0或1

void WINAPI ReadParam(char *p,int iFlag)

{

HWND hWnd=::FindWindow(NULL,"GetMessage");   //监视程序EXE名GetMessage

if (!hWnd)

{

//MessageBox(NULL,"GetMessage没有运行!","警告",MB_OK|MB_ICONSTOP);

return;

}

char tmp[200];

memset(tmp,0,200);

int i=0,j=0;

char t1=0,t2=0;

//先获取PID号

sprintf(tmp,"%u|",GetCurrentProcessId());    //为了避免任何一个调用该dll的文件发送消息,监视程序通过这个来判断

j=strlen(tmp);

//*p的内容为Unicode ,手动抓取参数值

while (1==1 && j<200)

{

t1=*p;

t2=*p++;

if (t1=='\0' && t2=='\0')   //如果有2个连续的的\0,结束,VB的编码默认是Unicode

{

goto EndHandler;

}

if (t1!='\0')   //只发现一个\0跳过去

{

tmp[j]=t1;

j++;

}

p++;

}

EndHandler:

COPYDATASTRUCT cda;

cda.dwData=(unsigned long)iFlag;

cda.cbData=strlen(tmp);

cda.lpData=(void*)tmp;

::SendMessage(hWnd,WM_COPYDATA,NULL,(LPARAM)&cda);                //传给监视程序!

return ;

}

GetMessage程序,添加一个消息COPYDATA来接受数据的时候,根据接受的进程号来区分是哪个进程,不然混淆了...

BOOL CGetMessageDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)

{

// TODO: Add your message handler code here and/or call default

CString tmp;

CString m_GetPID;

UpdateData();

tmp.Format("%s",(char *)pCopyDataStruct->lpData);

tmp=tmp.Left(pCopyDataStruct->cbData);

m_GetPID.Format("%d",theApp.dwPID);

if(m_GetPID!=tmp.Left(tmp.Find('|',1)))   //保持从dll格式一致,分离|左右2边的数据

{

//进程PID校验,避免数据混乱

goto ContinueHandler;

}

m_GetPID.Format("%d",iIndex);

m_List.InsertItem(0,m_GetPID);

tmp=tmp.Right(tmp.GetLength()-tmp.Find('|',1)-1);

m_Str=tmp;

m_List.SetItemText(0,1,tmp);

if (pCopyDataStruct->dwData==0)

m_List.SetItemText(0,2,"X失败X");

else

m_List.SetItemText(0,2,"--");

iIndex++;

ContinueHandler:

tmp.ReleaseBuffer();

m_GetPID.ReleaseBuffer();

UpdateData(false);

return CDialog::OnCopyData(pWnd, pCopyDataStruct);

}

//代码写的比较乱,欢迎各位扔砖头.

c655c3d3023b15a35a62a5e893441678.png

--------------------------------------------------------------------------------

【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

2010年10月16日 5:41:14

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值