博文

目前显示的是 五月, 2012的博文

Visual C++中的几种函数调用方式

(本文中所有汇编代码均采用Intel语法,即dest在左边)C++中的函数被编译成汇编代码的时候,必须遵循一定的规范,如参数怎么传递,栈指针怎么增减。Visual C++中,一共有5种情况:__cdecl__stdcall__fastcall__thiscall默认情况下,是__cdecl。__cdecl 和__stdcall的区别是:__cdecl是调用者清理栈,而__stdcall是被调用者清理栈。所以,理论来说,__cdecl生成的代码体积会更大。但是,对于varargs函数,由于被调用者并不知道参数的具体长度,所以这样的函数只能采用__cdecl。所有这四种方式,生成的函数都有固定的边界特征,__cdecl 和__stdcall以这样的模式开始:pushebp;保存ebpmovebp,esp;设置栈指针subesp,0C0h;为局部变量保留栈空间pushebx;保存在这个函数中可能用到的寄存器pushesi;保存在这个函数中可能用到的寄存器pushedi;保存在这个函数中可能用到的寄存器以这样的模式结束:popedi;恢复寄存器原先的值popesi;恢复寄存器原先的值popebx;恢复寄存器原先的值addesp,0C0h;与前面的sub esp,0C0h对应movesp,ebp;恢复栈指针popebp;恢复ebpret其中 “mov esp,ebp; pop ebp;”也可替换成一句“leave”指令。如果是__stdcall,最后一行的ret会变成ret0Ch这样。最后的那个数字代表从栈上弹出多少个字节,它应当等于函数参数的总大小。类的成员函数默认是采用__thiscall。它与__stdcall非常相似,区别是this指针会通过ecx传递。所以,如果在一个函数中发现ecx未被赋值就开始读它,那么多半是__thiscall。如pushebp;保存ebpmovebp, esp;设置栈指针pushecx;保存在这个函数中可能用到的寄存器pushebx;保存在这个函数中可能用到的寄存器pushesi;保存在这个函数中可能用到的寄存器movesi, ecx; 注意!!!ecx尚未被赋值就开始读了movebx, [esi+344h] ; this指针一般存放在esi中,并且在整个函数体内,esi尽量保持不变。另外再次强调,__thiscall末尾的ret语句要跟一…

Windows下调试ActiveX控件

VC较老的版本自带一个叫做ActiveX control test container的东西,从vs 2008开始,这个被移除了,改为以源代码的方式放在Samples里面发布。在VS的安装目录下有一个Samples目录,里面有一个VC2010Samples.zip,打开之后把C++/MFC/ole/TstCon解压缩出来并且编译即可。这个东西可以支持VBA脚本,于是就可以自动化测试ActiveX控件,比如Sub RunTest()
set ocx=TCForm.InsertControl("ShockwaveFlash.ShockwaveFlash.11","flash")
ocx.LoadMovie 0,"D:\Users\cm\doc\p2p\p2p.swf"
ocx.play
End Sub然后用tstcon.exe /D xxx.dsm 执行。但是我之前的用link.exe修改pe header的方法,似乎对ocx不好使了,所以用IDA调试ocx还是有些困难。另外,IDA似乎不支持加条件断点啊?