您的位置:首页 > 其它

Fasm---Win32汇编学习2

2008-04-24 00:35 435 查看
FASM--Win32汇编学习2
在本课中,我们将用汇编语言写一个 Windows 程序,程序运行时将弹出一个消息框并显示"Win32 fasm"。

理论:

Windows 为我们编程人员提供了大量的资源。其中最重要的就是Windows API (Application Programming Interface)。Windows API

是一组强大的函数。它们本身驻扎在Windows中供人们随时使用。这些函数大部分被包含在几个动态链接库中,譬如 “Kernel32.dll”, “user32.dll”, “GDI32.DLL”,Kernel32.dll 中的函数主要供我们处理内存管理和进程调度。user32.dll中的函数主要供我们控制用户界面。GDI32.DLL中的函数主要供我们处理图形方面。除了以上这3个动态链接库,你可以包含其他的动态链接库中的函数。当然你必须要有足够的这些动态链接库的资料。

 

动态链接库,顾名思义,这些API的代码本身不包含在Windows可执行文件中,而是在使用时才被加载。为了让应用程序在运行的时候找到这些函数。就必须首先把有关重定位的信息嵌入到可执行文件中。这些信息存在引入库中。由链接器在链接程序的时候将相关信息找出嵌入到可执行文件中。

我们FASM是通过宏来构建引入表的,所以我们需要自己通过Fasm的提供宏来包含相关的DLL和引入相应的函数。

当我们的应用程序在被加载时,PE Loader会读取相应引入表结构的成员来绝对能够读入的DLL,和相应DLL中的函数,最后将DLL加载到内存后,然后将相应的函数地址重定位,以便我们调用函数。

如果从字符集的相关性来分我们的API分为两类,一类是处理ANSI字符集的,一类是处理UNICODE字符集的。前一类的尾部带有“A”字符。 后一类的尾部带有“W”字符。(我想:W是代表宽字符的意思吧)。我们比较熟悉的ANSI字符串是以NULL结尾的一串字符数组。每一个ANSI字符是一个BYTE宽。对于欧洲体系ASNI已经足够了。但是对于成千上万的唯一字符的几种东方语言体系来说只能用UNICODE字符集了。每一个UNICODE字符占2个字节宽。这样就就可以在一个字符串中使用65336个不同字符了。

这也是为了增加UNICODE的原因。在大多数情况下,我们都可以包含一个头文件,在其中定义一个宏,然后在实际调用函数的时候就不用在函数名称后面加“A”和“W”字符了。


<#ifdef UNICODE

#define fool() foolW()

#else

#define fool()

#endif

>

 

先来个FASM的框架

format PE GUI 4.0

entry start

section '.data' data readable

 

section '.import' import data readable writeable

 

section '.code' code readable executable

start:

 

 

我们的应用程序是从entry指定的入口点处开始执行的。程序逐条指令开始执行,因为我们cpu是通过读取eip寄存器的值来绝定读入相应的数据执行的,所以我们程序一直执行直到遇到jmp jnz je 等跳转语句后将程序控制权转移其他语句,最后程序若要退出WINDOWS则必须调用ExitProcess函数来退出程序。。

 

 

这里是函数的原型。函数原型会告诉编译器该函数的属性。这样在编译链接的时候编译器就会进行相应的类型检查。

FunctionName PROTO [ParameterName]:DataType,[ParameterName]:DataType,...

这个就是fasm函数的原型。

 

在前面的ExitProcess函数有一个dword类型参数。当你调用高层invoke的时候,你可以简单的认为invoke有一个参数类型检查的语句。

 

例如你这样call ExitProcess

但你实现没有将dword类型的参数压入堆栈,编译链接的时候不会出错,程序在运行的时候显然出错。

 

但是你可以这样写 invoke ExitProcess ,那么编译器则会进行类型检查,并提示错误。。

invoke语句格式

INVOKE expression [,arguments]

expression 既可以是一个函数名也可以是一个函数指针。参数由逗号隔开。大多数api原型放在头文件中。我们fasm的头文件在include目录下。

现在我们回到ExitProcess。 其中uExitCode是退出码,用来退出程序返回给windows的。你可以这样写。

 

invoke ExitProcess, 0

把这一行放到开始的标示符下。

 

format PE GUI 4.0

include 'win32a.inc'

entry start

section '.data' data readable

 

section '.import' import data readable writeable

library, kernel32, 'kernel32.dll'

include 'api/kernel32.inc'

section '.code' code readable executable

start:

invoke ExitProcess, 0

我们的应用程序从win32a.inc头文件中得到相关变量结构体的定义,还需要从其他的头文件中得到函数原型。上面我们调用的函数在kernel32.dll中,我们必须通过fasm提供library宏来包含相应的dll,并且需要包含相应的头文件。因为这里是相应函数的原型。

接下来我们来调用一个消息框,

MessageBox PROTO hwnd:DWORD, lpText:DWORD, lpCaption:DWORD, uType:DWORD

hWnd 是父窗口的句柄。句柄代表您引用的窗口的一个地址指针。它的值对您编 Windows 程序并不重要(译者注:如果您想成为高手则是必须的),您只要知道它代表一个窗口。当您要对窗口做任何操作时,必须要引用该窗口的指针。
lpText 是指向您要显示的文本的指针。指向文本串的指针事实上就是文本串的首地址。
lpCaption 是指向您要显示的对话框的标题文本串指针。
uType 是显示在对话框窗口上的小图标的类型。

下面是完整的程序


format PE GUI 4.0


include 'win32a.inc'


entry start




offset equ




section '.data' data readable


szCaption db 'test',0


szText db 'win32 fasm',0






section '.code' code readable executable




start:


xor ecx, ecx


invoke MessageBox,eax, offset szText, offset szCaption,MB_OK


invoke ExitProcess,ecx




section '.import' import data readable writeable


library kernel32, 'kernel32.dll',


user32, 'user32.dll'


include 'apikernel32.inc'


include 'apiuser32.inc'




 



你编译链接上面的程序,呵呵出现一个消息框。 “win32 fasm ” 。 由于fasm中没有offset操作符,因为fasm是自动取全局变量的地址的,但是我们可以通过声明一个无值的符号常量offset。这样编译器在编译的时候将我们的offset是抛弃的,但是我们的源代码中看起来可读性比较好。。library是fasm提供我们的宏,因为fasm就是靠宏来构建输入表的。library的格式是macro library [name,string] .

ExitProcess proto uExitCode: DWORD
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: