发信人: flashboy()
整理人: winsy(2003-03-05 16:37:08), 站内信件
VB是个高级程序语言,不允许你做那些如嵌入汇编等工作,但天下没有不可能的
事,让兔子抽烟也是可能的。VB已经是个编译器而非BASICA之类的解释器,对VB
编译器的编译过程有所了解后,就能基本做到为所欲为。
VB的compile过程也如所有compile的一样,包含编译(compile)和连接(link)。在
VB里实际上是调用c2.exe和link.exe来完成的。c2是微软的“两次过(second-pa
ss)”编译器。在VB的集成环境里,VB通过WIN32API的CreateProcess来调用c2和
link,注意,这就是个突破点,可以把这个调用hook起来,就可以介入VB的编译
连接过程。
VB用C2对你项目中的每个文件进行编译,然后产生目标库(object modules),并
把这些目标库暂存在你的TEMP目录下,等全编译完了后把它们在link起来,生成
EXE文件。C2有很多参数可用,其中最关键的是FAs,这个参数让编译器产生汇编
的源程序。
明天再续。。
为什么我们用VC?
因为VC灵活自由,
从高处看,可以做继承,可以做重载,可以做多态性。
从低处看,可以操作指针,可以嵌入汇编。
从结果看,可以调整不同的编译参数使目标码效率高,执行快,尺寸小。
VC真是写系统程序的唯一选择。
为什么我们用VB?
因为写程序和调试程序的速度是用VC写的几十倍。有了VB才有了RAD(快速程序开
发)这个词。
为什么我们不用VB?
因为VB不能做VC可以做的上述事情。
等一等,是VB不能做还是大多数人不会做??
在进行下去之前,为了有效的拦截VB的编译器,我们要安装一个利器。利器安装
后,我们就可以随心所欲地拦截VB的编译器。如果把Hook Compiler激活,你一旦
编译。就会看到有个显示编译参数的窗口显示出来。上一篇说过有个很重要的参
数是“-FAs”,(格式是: -FAs -Fa "C:\myvb\modbas.lst")。这个编译参数可
以使编译器产生汇编源码。看到这里,怎样嵌入你自己的汇编程序应该也猜出来
了。对,就是修改VB产生的那个汇编程序,再用MASM编译程OBJ。或者,你想做的
更干脆的话,从头到尾用汇编也行。用同名文件替换VB的OBJ就行了。同理,你可
以嵌入你的VC程序,BC程序,FORTRAN程序。比如你对某些VB的运算速度不满意,
想用VC或ASM重写。你可以只写一个空的VB函数(只有一个名字)。然后编译,中间
截住,狸猫换太子,换上你自己VC,ASM目标库。在让VB继续生成EXE执行文件。
多好!有点做黑客的感觉。
汇编的编译器(ML.EXE)可以在DDK里找到,是MASM 6.11d版,可以从MS下载。看看
下面的实例:有个VB程序做除2的工作,
Public function DivideBy2(lngDividend as Long) as Long DivideBy2 = l
ngDividend / 2End Function
编译后汇编码如下:
?DividBy2@Module1@@AAGXXZ PROC NEAR ; Module1::DividBy2, COMDAT; 2
: Public Function DividBy2(lngDividend As Long) As Long push ebp mov
ebp, esp sub esp, 8 push OFFSET FLAT:___vbaExceptHandler mov eax, DWO
RD PTR fs:__except_list push eax mov DWORD PTR fs:__except_list, esp s
ub esp, 48 ; 00000030H push ebx push esi push edi mov DWORD PTR __
$SEHRec$[ebp+8], esp mov DWORD PTR __$SEHRec$[ebp+12], OFFSET FLAT:$S2
6 xor eax, eax; 3 : Divideby2 = lngDividend / 2 lea edx, DWORD
PTR _unnamed_var1$[ebp] mov DWORD PTR _DividBy2$[ebp], eax mov DWORD P
TR _Divideby2$[ebp], eax mov eax, DWORD PTR _lngDividend$[ebp] lea ecx
, DWORD PTR _Divideby2$[ebp] mov DWORD PTR _unnamed_var1$[ebp], 5 fild
DWORD PTR [eax] fstp QWORD PTR -64+[ebp] fld QWORD PTR -64+[ebp] cmp
DWORD PTR __adjust_fdiv, 0 jne SHORT $L48 fdiv QWORD PTR __real@8@4000
8000000000000000 jmp SHORT $L49$L48: push DWORD PTR __real@8@400080000
00000000000+4 push DWORD PTR __real@8@40008000000000000000 call __adj_
fdiv_m64$L49: fstp QWORD PTR _unnamed_var1$[ebp+8] fnstsw ax test al,
13 ; 0000000dH jne SHORT $L41 call DWORD PTR __imp_@__vbaVarMove f
wait push $L40$L35:; 4 : End Function
天哪,VB竟产生了这么多乱七八糟的代码。你可以在上面动手优化,结束后,用
:
ml /c /Cp /coff /Zm module1.lst
编译你自给的OBJ。
你也可以完全在ASM或VC写个模块。在这种工作方式下,要注意的是VB每次编译动
态产生函数名,这个VC里用的函数名不同。在替换OBJ时要注意使名字一致。比如
VB产生的名字是:
?DividBy2@Module1@@AAGXXZ
VC里面可能是?DividBy2@@GXF@Z,所以要手工改名字。
加入不同的编译参数还可以做不少事情。例如:VB只能产生ActiveX DLL? 谁说的
,用了/EXPORT或/DEF参数就能输出函数从而产生一个普通的DLL文件。