Fasm---Win32汇编学习2

            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 'api
kernel32.inc'
    include 'api
user32.inc'

 

 

 

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

 

ExitProcess proto  uExitCode: DWORD
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章