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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章