【原创】masm无jmp table直接调用API示范教程(简单有效 附转换工具下载)
;*****************************************************************************************************************;作者:zklhp
;Email:zklhp@
;QQ:493165744
;*****************************************************************************************************************
问题的来源来自这个贴 http://www.
核心就是 C语言调用API的时候没有jmp table 而用masm调用时会生成jmp table
jmp table的相关知识可以看罗云彬的书中PE文件部分 这里不多说
上代码
程序代码:
;MASMPlus 代码模板 - 控制台程序 ;***************************************************************************************************************** ;作者:zklhp ;Email:zklhp@ ;QQ:493165744 ;直接调用API示范教程 ;***************************************************************************************************************** .386 .model flat, stdcall option casemap :none include windows.inc ;或者包含工具包中提供的argcount.asm 两者原理一样 ;include user32.inc ;include kernel32.inc ;include masm32.inc ;include gdi32.inc include user32d.inc include kernel32d.inc ;includelib gdi32.lib includelib user32.lib includelib kernel32.lib ;includelib masm32.lib include macro.asm .data lpMsg db "Hello World!",0 .data? buffer db 260 dup(?) .CODE START: MessageBox 0,offset lpMsg,CTXT('直接调用哦'),0 ;暂停显示,回车键关闭 ExitProcess 0 end START
反汇编
程序代码:
00401000 > 6A 00 PUSH 0 00401002 68 0D304000 PUSH CONSOLE.0040300D 00401007 68 00304000 PUSH CONSOLE.00403000 ; ASCII "Hello World!" 0040100C 6A 00 PUSH 0 0040100E FF15 08204000 CALL DWORD PTR DS:[<&user32.MessageBoxA>>; user32.MessageBoxA 00401014 6A 00 PUSH 0 00401016 FF15 00204000 CALL DWORD PTR DS:[<&kernel32.ExitProces>; kernel32.ExitProcess
奥秘在工具生成的user32d.inc文件中
程序代码:
externdef _imp__MessageBoxA@16:PTR pr4 MessageBox equ <invoke _imp__MessageBoxA@16,>
实现机制 Hume 大大的文章中提到过 可惜的是10年后我才看到 唉~
iWin32,iWin32i,避免jmp tabel,有两种方法避免生成jmp tabel(thx to EliCZ's macro)
一种我以前写的一篇文章里面介绍过,就是利用声明
_imp__&Win32Api&A proto :DWORD,....
然后
call dword ptr [_imp__&Win32Api&A]
格式另一种是ELiCZ的方法,就是声明
externdef _imp__&Win32Api&A@NUM:DWORD,其中NUM是参数个数
然后
call _imp__&Win32Api&A来调用.
由于用EliCZ的方法写的macro较长,下面根据我的方法写一个宏:
iWin32 Macro Win32API:REQ,args:VARARG
LOCAL sz1
sz1 TEXTEQU <>
% FOR pxx,
IFNB
push pxx
sz1 CATSTR sz1,<,:DWORD>
ENDIF
ENDM
sz1 SUBSTR sz1,2,@SizeStr(%sz1)-1
sz1 CATSTR <_imp__&Win32API>,< PROTO >,sz1
sz1
call DWORD PTR [_imp__&Win32API]
ENDM
下面iWin32i可以根据情况生成对ansi或者UNICODE的调用,前提是定义UNICODE=0或者TRUE...
iWin32i Macro Win32API:REQ,args:VARARG
IF UNICODE
iWin32 Win32API&W,
ELSE
iWin32 Win32API&A,
ENDIF
ENDM
一种我以前写的一篇文章里面介绍过,就是利用声明
_imp__&Win32Api&A proto :DWORD,....
然后
call dword ptr [_imp__&Win32Api&A]
格式另一种是ELiCZ的方法,就是声明
externdef _imp__&Win32Api&A@NUM:DWORD,其中NUM是参数个数
然后
call _imp__&Win32Api&A来调用.
由于用EliCZ的方法写的macro较长,下面根据我的方法写一个宏:
iWin32 Macro Win32API:REQ,args:VARARG
LOCAL sz1
sz1 TEXTEQU <>
% FOR pxx,
IFNB
push pxx
sz1 CATSTR sz1,<,:DWORD>
ENDIF
ENDM
sz1 SUBSTR sz1,2,@SizeStr(%sz1)-1
sz1 CATSTR <_imp__&Win32API>,< PROTO >,sz1
sz1
call DWORD PTR [_imp__&Win32API]
ENDM
下面iWin32i可以根据情况生成对ansi或者UNICODE的调用,前提是定义UNICODE=0或者TRUE...
iWin32i Macro Win32API:REQ,args:VARARG
IF UNICODE
iWin32 Win32API&W,
ELSE
iWin32 Win32API&A,
ENDIF
ENDM
根据原理其实有好多种不同的写法 工具生成的是externdef的 其实还可以这样
程序代码:
__imp__MessageBoxA@16 proto syscall __imp__ExitProcess@4 proto syscall ;syscall调用规范不修饰 ;调用 xor eax,eax lea ecx,lpMsg mov edi,DWORD PTR [__imp__MessageBoxA@16] push eax push ecx push ecx push eax call edi push eax call DWORD PTR [__imp__ExitProcess@4]
程序代码:
_imp__MessageBoxA proto stdcall :DWORD,:DWORD,:DWORD,:DWORD _imp__ExitProcess proto stdcall :DWORD ;切记第二种方法前面只有一个下划线 原因去查stdcall的修饰方式 xor eax,eax lea ecx,lpMsg mov edi,DWORD PTR [_imp__MessageBoxA] push eax push ecx push ecx push eax call edi push eax call DWORD PTR [_imp__ExitProcess]
因为能用masm32工具包中的l2extia.exe转换所有写了这个例子 要是都手工生成就挺麻烦的 呵呵
从这个小例子也反映了汇编的灵活性 当然也反映了汇编的复杂性 在这里灵活的同义词就是复杂
代码+MasmPlus工程+转换软件
MessageBox_D.zip
(35.12 KB)
[ 本帖最后由 zklhp 于 2012-2-8 15:43 编辑 ]