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函数来退出程序。。

 

ExitProcess proto  uExitCode: DWORD

 

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

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,ecx, 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] .
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。 首先,16位汇编和32位汇编是两种不同的汇编语言,它们的主要区别在于它们所支持的指令集的不同。 在保护模式下,操作系统将内存划分为多个段,每个段具有不同的特权级别和访问权限。在这种模式下,程序可以访问更大的内存空间,并且可以执行更复杂的操作。在保护模式下,编写汇编代码需要使用一些新的指令和数据类型,例如段选择器、描述符表等。 对于16位汇编,常用的编译器有MASM、TASM等。在编写汇编代码时需要注意以下几点: 1. 16位汇编程序是基于段的,需要定义段寄存器和偏移地址。 2. 16位汇编程序使用的指令集较为简单,只支持较少的指令集。 3. 在保护模式下,需要使用32位寄存器来访问段寄存器和描述符表。 对于32位汇编,常用的编译器有NASM、FASM等。在编写汇编代码时需要注意以下几点: 1. 32位汇编程序是基于平面模式的,不需要定义段寄存器。 2. 32位汇编程序使用的指令集更加丰富,支持更多的指令集。 3. 在保护模式下,需要使用32位寄存器来访问段寄存器和描述符表。 总的来说,在编写汇编代码时需要充分理解汇编语言的特点和保护模式下的内存管理机制,以及熟悉所使用的编译器和指令集。同时,需要注意代码的可读性和可维护性,尽量使用注释和模块化的代码结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值