- 小技巧:关于获得正在运行的地址 by 天杀
代码自定位是病毒常用的东西.常见格式如下
call @4
@4: pop ebx
有人说
用@4: mov ebx,$ 来代替上面的2条语句,一样可以得到相同的效果
实际是不一样的.上面的那个是运行时候直接获得的.
下面的那个$是编译器计算的.是一个静态的东西
- 小技巧:环境保护 by txj_killer
遇到一个问题调试了半天才发现原来是ReadProcessMemory函数会改变ecx寄存器的值,放在这里,大家以后调用这个函数的时候记得保护好现场:)
AoGo补充:一般而言,GDI函数不会破坏ebx/esi/edi三个寄存器,字符串或内存操作函数一般会改写esi/edi/ecx,甚至全部,所以,好的方法是在不敢确定函数是否会破坏某个寄存器时,在这个函数调用前设置某个寄存器的值,调用完后把这个寄存器的值显示出来,看是否和调用前一样就可以确认了。当然如果函数修改了这个寄存器刚才与你设置的值一样,嘿嘿,算你晦气。
小技巧:运行时得到某处的实际地址 by IPOz
call @4
@4: pop ebx
大家知道call指令会把其下一条指令的地址压入栈顶,所以当执行到@4时,ss:[esp]就是@4的地址 ! 这样,pop ebx就会将@4的地址"弹"入ebx了.
小技巧:关于对“小技巧 运行时得到某处的实际地址”的一点补充 by 鬼龙之舞
call @4
@4: pop ebx
大家知道call指令会把其下一条指令的地址压入栈顶,
所以当执行到@4时,ss:[esp]就是@4的地址 !
这样,pop ebx就会将@4的地址"弹"入ebx了.
如果我对上面没有理解错误的话,
用@4: mov ebx,$ 来代替上面的2条语句,一样可以得到相同的效果
小技巧:补充《关于对“小技巧 运行时得到某处的实际地址”的一点补充》 by forgot
引用原文:
----------------------------------------------------------------
call @4
@4: pop ebx
大家知道call指令会把其下一条指令的地址压入栈顶,
所以当执行到@4时,ss:[esp]就是@4的地址 !
这样,pop ebx就会将@4的地址"弹"入ebx了.
如果我对上面没有理解错误的话,
用@4: mov ebx,$ 来代替上面的2条语句,一样可以得到相同的效果
----------------------------------------------------------------
使用mov ebx, $将得到@4的offset,如果不能被系统Loader装载到预定地址,对ebx所指内容操作将会出错。
- 小技巧:在弹出菜单的同时再次弹出菜单 by AoGo
这是一个一直有争议并且都没有完美实现的问题,有人自己写类,有人自己写窗口模拟,其实,它真的很简单,简单到一个什么程度?
无需任何的技巧,只要在TrackPopupMenuEx函数的Flags标志位中or上TPM_RECURSE or TPM_RIGHTBUTTON标志,一切OK,你甚至可以在这个菜单上马上弹出另一个菜单。简单得很。
- 小技巧:移位指令在Win32消息处理中的一些问题 by AoGo
大家在处理有些字节拼装的消息时,一定是用Shr等指令来移位,这里有一个小问题,要注意:
如WM_MOUSEWHEEL消息,它的wParam的高字节保存了当前的鼠标滚动的方向,-120表示向上滚动,120表示向下滚动,此时,这样处理是错的:
mov eax,wParam
shr eax,16
.if eax==-120
... ..
为什么?因为移位指令移位的同时,把最高位也移动了,此时,符号位到了ax的最高位,结果判断eax自然总是正数,此时,应该直接判断ax,或使用扩展指令。如:
... ...
.if ax==-120
就行了,这一般只在高位或低位会为负的情况下注意,因为正数移位后判断eax仍然行得通。
- 小技巧:masm中宏指令的bug by AoGo
当使用GetCaretPos获得当前的光标位置后,假设它为负数,我需要知道它是否小于0,结果:
.if p.y<0
... ... ;1
.elseif p.y>eax
... ... ;2
.endif
结果你猜怎么样?;1段永远不会执行,因为编译器编译时把.if p.y<=0编译成了:
cmp p.y,0
jb xxx
结果可想而知,p.y是负数,按照无符号数来对待就成了正数了,比如-100,成了65435,自然出错。这是masm的一个bug.
所以,提醒大家,在碰到有符号数的判断时,尽量使用负数比较,或者自己写判断代码,如负数比较:
.if p.y<=-1 等价于 .if p.y<0
上述代码编译器会自动选择jge/jle/jl/jg系列指令。
自己判断:
cmp eax,0
jle xxx
... ...
jmp @F
xxx:
cmp p.y,eax
jle @F
... ...
@@:
同时,其它宏指令如.while也有这个出错的bug。
记得有符号数处理时要注意就行了,否则会出现莫名其妙的错误,却找不到哪里出错。
纠正:
这不能算是一个bug,一位论坛的网友提醒了我,其实,在做这种比较时,可以把它临时当成有符号数以便让masm选择,如:
.if SDWORD ptr p.y<0
... ...
就可以了。类似的可以转换成SWORD SBYTE,前面的s表示有符号。
<script language="vbscript" type="text/javascript"> parent.windowtitle.innerhtml="<font color=blue>小技巧:masm中宏指令的bug</font> by AoGo" </script>
- 小技巧:数据转换操作 by AoGo
buffer db "0123456789",0
lea esi,buffer
mov al,byte ptr [esi] ;al=='0'
mov ax,word ptr [esi] ;ax=='01'
mov eax,dword ptr [esi] ;eax=='0123'
发现什么了吗?
<script language="vbscript" type="text/javascript"> parent.windowtitle.innerhtml="<font color=blue>小技巧:数据转换操作</font> by AoGo" </script>
- 小技巧:Win32编程中请慎用ebx/esi/edi by 电子管
根据我的试验,在win2000以上操作系统对于ebx,esi,edi好像是拿来就用,没有进行保护和恢复,如果你的程序中使用了这几个寄存器,请一定先压栈,用完后恢复。否则会使程序在win98下正常,在win2000下出现莫名其妙的非法操作,一般是提示某个地址不能进行读写操作,而这个地址并不在你的程序的控制下。
- 小技巧:关于div/idiv/mul/imul指令的用法 by AoGo
大家可能深有体会,在使用div/idiv指令时,运行程序常常会莫明其妙的弹出"该程序执行非法操作"的错误,通常是"除法溢出",但是,你的代码可能如下:
mov eax,1000
cwd
div cx
一般在使用了cwd指令后,就可以正常,但是很不稳定,我就觉得奇怪,为什么会这样?
huitiansou的解答:
对:“关于div/idiv/mul/imul指令的用法 by AoGo”产生Bug的原因
那是因为被除数达到了双精度值,
所以不能用符号扩展,
而只能将高16位送0
我们只要保证edx为0就可以了,在运行32位数的除法时,建议使用这个方法,绝对不会操作非法操作(当然除0/溢出除外)
例子:
xor edx,edx
mov eax,6527363
mov ecx,28732
div ecx
你只要把上面的xor edx,edx指令一去掉,保证100%非法操作。
另外,乘法指令也可以这样做。可以保证更安全。
- 小技巧:Win32不需要释放的资源 by AoGo
LoadCursor,LoadIcon,LoadString
GetStockObject
这几个函数获得的句柄无需释放。
- 小技巧:字符串操作指令 by AoGo
lodsb
stosb
movsb
rep/repz/repnz
cmpsb
scasb等等,
这些指令其实速度很慢,好的方法是用寄存器间接寻址,如:
lodsb mov al,byte ptr [esi]
inc esi
stosb mov byte ptr [edi],al
inc edi
等等,千万不要在程序中使用rep movsb,这样做速度很慢的。
例:一个字符串复制函数
lstrcpyn proc uses esi edi ecx,src,des,ilen
mov ecx,ilen ;要复制的长度
mov esi,src
mov edi,des
@@:
mov al,byte ptr [esi]
inc esi
mov byte ptr [edi],al
cmp al,0 ;终止符
jz @F
loopnz @B
@@:
ret
lstrcpyn endp
- 小技巧:结构类型转换快速操作 by AoGo
一般在WM_NOIFY消息中处理是这样的:
lParam传过来的是一个NMHDR结构的地址,普通处理如下:
mov ecx,lParam
assume ecx:ptr NMHDR
push ecx
.if [ecx].code==NM_CLICK
.endif
pop ecx
assume ecx:nothing
好的方法是:
直接加上结构类型转换:
mov ecx,lParam
.if (NMHDR ptr [ecx]).code==NM_CLICK
.endif
这样做极方便.
总是使用assume,这不是运行时的,是编译时编译器做的操作。
- 小技巧:LEA指令的妙用 by Matt Pietrek
LEA另一用途就是代替乘法运算,比如LEA EAX,[EAX*4+EAX]就要比用MUL去实现EAX*5来得快捷,具体原因很复杂,反正事实就是这样.
- 小技巧:汇编的数据无类型 by AoGo
大家都知道汇编有byte,word,dword,fword,tword等等类型,可是为什么常说汇编数据无类型呢?这是因为在汇编编程里面,这些数据类型都是可以互转的,比如说,word就是两个byte,如果定义了worddata dw 100 dup(?),那么使用的时候就可以把它当成byte来使用,如invoke wsprintf,offset worddata,offset keyword,100.其它的如local rect:RECT,其实可以把它当成byte缓冲来使用,如:
lea esi,rect
lea edi,buffer
mov cx,sizeof rect
rep movsb
invoke MessageBox,hWin,offset rect,0,0
这就是汇编的数据无类型之说的由来.
- 小技巧:xor的一个小妙用 by AoGo
用xor与同一数据进行两次运算后将得到运算前的值,如:
eax=200
xor eax,100
xor eax,100
结果eax还是等于200
- 小技巧:在窗体标题栏做画 by AoGo
很简单,只需要处理WM_NCPAINT消息就行了,就是Windows Message Not Client Paint -- 非客户区的重画,这个时候就能在标题栏上做画,另一个方法是使用GetWindowDC函数,此函数与GetDC的唯一区别就是GetWindowDC是获得整个窗体的DC,而GetDC只是获得客户区的DC.
<script language="vbscript" type="text/javascript"> parent.windowtitle.innerhtml="<font color=blue>小技巧:字符串操作指令</font> by AoGo" </script>