小技巧大全-转自AoGo

  • 小技巧:关于获得正在运行的地址 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
经常看到使用Byte ptr/Word ptr/Dword ptr/Qword ptr 等等来临时转换数据,这里有一个小技巧。如:

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值