1. 程式人生 > >win32彙編基礎概念

win32彙編基礎概念

一、關於暫存器

暫存器有EAX,EBX,ECX,EDX,EDI,ESI,ESP,EBP等,似乎IP也是暫存器,但只有在CALL/RET在中會預設使用它,其它情況很少使用到,暫時可以不用理會。
EAX是WIN32 API 預設的返回值存放處。
ECX是LOOP指令自動減一的暫存器。
ESP是堆疊指標。
EBP經常用來在堆疊中定址。
ESI好像常常用在指標定址中,EDI不大清楚。

二、關於記憶體定址

WIN32中記憶體是平坦的,對於每個程式來說都可以使用2G範圍的地址,但各個程式之間並不會干擾,這是因為各個程式所使用到的實體記憶體被Windows自行安排,不會互相覆蓋,而且一個程式不會隨意地訪問到另一個程式的地址空間。

三、關於堆疊

Windows為每個程式安排了堆疊段,它是從高地址向低地址延伸的,之所以採用這種方式,是因為這樣可以使堆疊指標始終指向最近入棧的元素的起始地址,這樣的話,為訪問這個元素提供了非常便利的方式。

ESP作為堆疊指標始終指向棧頂,如果看一下PUSH和POP的操作就可以明白這句話:
PUSH: ESP <-- ESP-4 (ESP+3,ESP) <-- 入棧元素
POP: 出棧元素 <-- (ESP+3,ESP) ESP <-- ESP+4

因為PUSH和POP自動修改了ESP的值,使它始終指向棧頂了。當然也可以自己來修改ESP的值,例如我們可以:
sub  esp,4  ;這樣就把棧頂指標向下移動了。
這種操作常常用在區域性變數的分配中,在子程式中使用到區域性變數時,就在堆疊中為它們提供空間,這樣可以使子程式退出時收回區域性變數佔用的空間,有利於子程式的模組化。

我們可以用ESP來定址堆疊中的元素,比如ESP指向當前棧頂元素的起始地址,ESP-4指向前一個元素的起始地址,不過因為ESP常常在變化,這樣用ESP在堆疊中定址的話不方便,所以我們就用EBP來代替ESP定址,首先把EBP入棧儲存,然後把ESP賦值給EBP,這樣就可以用EBP來定址堆疊中的資料了。我用一個例子來說明堆疊的變化。

push  0x00000001           ;1
push  ebp                  ;2
mov  ebp,esp               ;3
push  0x12345678           ;4
mov  eax,dword ptr[ebp+4]  ;5
mov  ebx,dword ptr[ebp-4]  ;6
mov  ax,word ptr[ebp-2]    ;7
mov  al,byte ptr[ebp-1]    ;8
mov  al,byte ptr[ebp-3]    ;9
mov  ax,word ptr[ebp-3]    ;10

 

5 eax=0x00000001
6 ebx=0x12345678
7 ax=0x1234
8 al=0x12
9 al=0x56
10 ax=0x3456


堆疊使用在子程式的實現中,當呼叫子程式時,首先把引數入棧,然後把返回IP入棧,然後轉移到子程式處,如果有區域性變數,則下移ESP,然後初始化該區域性變數,這樣用到EBP來定址區域性變數,引數的定址同樣要用到EBP。


四、簡單的幾個關鍵字

ptr  顯式指定後面的資料的型別
offset 全域性變數的地址
addr  區域性變數的地址,也可以用在全域性變數上
local  定義區域性變數
proc  定義子程式
proto  宣告子程式

五、例子

Hello.asm檔案的內容如下: ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 第一部分:模式和源程式格式的定義語句               .386                            ; 指令集               .model flat,stdcall             ; 工作模式               option casemap:none             ; 格式 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 檔案定義 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include           windows.inc include           user32.inc includelib        user32.lib include           kernel32.inc includelib        kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 資料段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               .data szCaption       db    'A MessageBox !',0 szText          db    'Hello, World !',0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 程式碼段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               .code start:               invoke     MessageBox,NULL,offset szText,offset szCaption,MB_OK               invoke     ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               end start        ; 指定程式的入口   1.         第一部分模式和源程式格式的定義語句 第一行 指定使用的指令集(編譯器使用) Win32環境工作在80386及以上的處理器中,所以必須定義.386。如果程式(VxD等驅動程式)中要用到特權指令,那麼必須定義.386p。 第二行 定義程式工作的模式(包括記憶體模式、語言模式、其它模式) 對Win32程式來說,只有一種記憶體模式,即flat(平坦)模式。 Win32 API呼叫使用的是stdcall格式,所以Win32彙編中必須在.model中加上stdcall引數。 第三行 option語句        由於Win32 API中的API名稱區分大小寫,所以必須定義option casemap:none,來表明程式中的變數和子程式名對大小寫敏感。   2.         包含全部段的源程式結構: .386 .model flat,stdcall option casemap:none <一些include語句> .stack [堆疊段的大小] .data <一些初始化過的變數定義> .data? <一些沒有初始化過的變數定義> .const <一些常量定義> .code <程式碼> <開始標記> <其他語句> end 開始標記   3.         段的定義 資料段        .data               已初始化資料段,可讀可寫的已定義變數; 當程式裝入完成時,這些值就已經在記憶體中;               資料定義在.data段中會增加可執行檔案的大小;               .data段一般存放在可執行檔案的_DATA節區(Section)內;        .data?               未初始化資料段,可讀可寫的未定義變數,在可執行檔案中不佔空間;               這些變數一般作為緩衝區或者在程式執行後才開始使用。               資料定義在.data?資料段中不會增加可執行檔案的大小;               .data?段一般存放在可執行檔案的_BSS節區內;        .const               常量,可讀不可寫的變數;   程式碼段        .code               所有的指令都必須寫在程式碼段中;               Win32中,資料段是不可執行的,只有程式碼段有可執行的屬性;               對於執行在特權級3的應用程式,.code段不可寫。除非把可執行檔案PE頭部中的屬性位改成可寫;               對於執行在特權級0的程式,所有的段都有讀寫許可權,包括程式碼段;               .code程式碼段一般存放在可執行檔案的_TEXT節區內;   堆疊段        .stack               與DOS彙編不同,Win32彙編不必考慮堆疊。系統會自動分配堆疊空間;               堆疊段的記憶體屬性是可讀寫並且可執行;               靠動態修改程式碼的反跟蹤模組可以拷貝到堆疊中去邊修改邊執行;               緩衝區溢位技術也會用到這個特性;   4.         呼叫作業系統功能的方法: DOS下 作業系統的功能通過各種軟中斷來實現。        應用程式呼叫作業系統功能將經歷如下三個過程:               把相應的引數放在各個暫存器中再呼叫相應的中斷;               程式控制權轉到中斷中去執行;               完成以後通過iret中斷返回指令回到應用程式中;        DOS下呼叫系統功能方法的缺點:               所有的功能號定義是難以記憶的數字;               80x86系列處理器能處理的中斷最多隻能有256個;               通過暫存器來傳遞引數,對於引數較多的函式很不方便; Win32下        系統功能模組放在Windows的動態連結庫(DLL)中        作為Win32 API核心的3個DLL:               KERNEL32.DLL    系統服務功能。               GDI32.DLL           圖形裝置介面。               USER32.DLL         使用者介面服務。   常用API的引數和函式宣告,檢視文件《Microsoft Win32 Programmer's Reference》   5.         Win32 API的函式原型宣告 函式原型宣告的彙編格式如下: 函式名 proto [距離] [語言] [引數1]:資料型別, [引數2]:資料型別,...... proto是函式宣告的偽指令 距離可以設定為NEAR、FAR、NEAR16、NEAR32、FAR16或FAR32,由於Win32中只有一個平坦的段,無所謂距離,所以在定義時可以忽略距離。 語言型別可是使用.model所定義的預設值。   以訊息對話方塊函式MessageBox為例 C格式如下: int MessageBox(        HWND hWnd,              // Handle to owner window        LPCTSTR lpText,         // text in message box        LPCTSTR lpCaption,     // message box title        UINT uType                 // message box style        );   彙編格式如下: MessageBox Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword 或者寫為 MessageBox Proto :dword,:dword,:dword,:dword 編譯器只對引數的數量和型別感興趣,引數的名稱只是增加可讀性,所以可以省略。 對於組合語言來說,Win32環境中的引數實際上只有一種型別,就是一個32位的整數(dword,double word),雙字,四位元組。     6.         呼叫Win32 API 呼叫API有如下兩種方法: 1)        invoke invoke是MASM提供的偽指令;               invoke偽指令的好處就是能夠提高程式碼的可讀性,減少錯誤;               invoke做了下面三件事:                      在編譯的時候,由編譯器把invoke偽指令展開成相應的push指令和call指令;                      進行引數數量的檢查工作;                      如果帶的引數數量和宣告時的數量不符,編譯器會報錯; 2)        push和call的組合 80386處理器的指令   invoke     MessageBox,NULL,offset szText,offset szCaption,MB_OK 也可寫為 push NULL push offset szText push offset szCaption push MB_OK call MessageBox   7.         Win32 API函式返回值的處理方法 對於組合語言來說,Win32 API函式返回值的型別只有dword一種型別,它永遠放在eax中。 如果要返回的內容在一個eax中放不下,Win32 API採用如下方法來解決: a)         一般是eax中返回一個指向返回資料的指標; b)        在呼叫引數中提供一個緩衝區地址,資料直接返回到這個緩衝區中去。類似變參的概念;   8.         與字串相關Win32 API的分類 在Win32環境中,根據兩個不同的字符集(ANSI字符集和Unicode字符集),可以把和字串相關的API分成兩類: a)         處理ANSI字符集的Win32 API函式 函式名稱的尾部帶一個“A”字元; ANSI字串是以NULL結尾的一串字元陣列,每一個ANSI字元佔一個位元組的寬度; 例如:MessageBoxA Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword b)        處理Unicode字符集的Win32 API函式 函式名稱的尾部帶一個“W”字元;               每一個Unicode字元佔兩個位元組的寬度,所以可以同時定義65536個不同的字元;               例如:MessageBoxW Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword   Windows 9x系列不支援Unicode版本的API,絕大多數的API只有ANSI版本。 只有Windows NT系列才完全支援Unicode版本的API。 為了編寫在幾個平臺中都能通用的程式,一般應用程式都使用ANSI版本的API函式集。   提高程式可移植性的一個方法:

相關推薦

win32 彙編基礎概念整理

一、關於暫存器 暫存器有EAX,EBX,ECX,EDX,EDI,ESI,ESP,EBP等,似乎IP也是暫存器,但只有在CALL/RET在中會預設使用它,其它情況很少使用到,暫時可以不用理會。 EAX是WIN32 API 預設的返回值存放處。 ECX是LOOP指令自動減一的暫存器。 ESP是堆

win32彙編基礎概念

一、關於暫存器 暫存器有EAX,EBX,ECX,EDX,EDI,ESI,ESP,EBP等,似乎IP也是暫存器,但只有在CALL/RET在中會預設使用它,其它情況很少使用到,暫時可以不用理會。 EAX是WIN32 API 預設的返回值存放處。 ECX是LOOP指令自動減一的暫存器。 ESP是堆

程式語言的底層描述(1)——彙編基礎概念的開始之入門

該主題預設在類unix作業系統中進行討論 gcc編譯器可通過不同的引數,生成不同階段的編譯檔案,比如,我們想生成可執行檔案,就用gcc -o;要生成目的碼.o,就用gcc -c;要生成彙編程式碼.s,就用gcc -S, 程式編譯的順序是,編譯器先根據.c原始檔產生.s彙編

RabbitMQ基礎概念詳細介紹

可用性 將不 tar connect 相互 abi 封裝 編寫 綁定 原文地址:http://www.diggerplus.org/archives/3110 引言 你是否遇到過兩個(多個)系統間需要通過定時任務來同步某些數據?你是否在為異構系統的不同進程間相互調用、通

JS基礎概念

文件 數字 true while語句 第一個 加載 截取 pre js基礎 JS基礎概念 1. 算法及流程圖 算法類型:1.算數算法;2.事務性算法(解決某個問題的方法和先後順序)。 JS語法概述 1. 引入JS的方法 1.用<script src=""><

kafka-通俗易懂基礎概念

kafka python topic 一些大的網站如果想統計用戶的訪問情況,如果每個用戶的訪問,都在後端經過一系列的用戶行為分析,然後再給客戶返回結果這顯然不現實,直接寫入數據庫,數據庫也扛不住,這時候就需要一個消息系統,在用戶一個請求過來後,服務器只需要把這次操作扔到後端,不用管後

【extjs6學習筆記】0.1 準備:基礎概念(02)

json over cal 類的屬性 tab 常用事件 data 微軟 基於 Ext 類 Ext 是一個全局單例的對象,在 Sencha library 中它封裝了所有的類和許多實用的方法。許多常用的函數都定義在 Ext 對象裏。它還提供了像其他類中一些頻繁使用的方法

nodejs零基礎詳細教程1:安裝+基礎概念

img res 安裝過程 pkg 實時 linkedin 圖標 過程 好的 第一章 建議學習時間2小時 課程共10章 學習方式:詳細閱讀,並手動實現相關代碼 學習目標:此教程將教會大家 安裝Node、搭建服務器、express、mysql、mongodb、編寫後臺業務邏輯

java 基礎概念 -- 數組與內存控制

nbsp 堆內存 數組元素 art pan popu ace article pac 問題1: Java在聲明數組的過程中,是怎樣分配內存的? 在棧內存中 建一個數組變量,再在堆內存中 建一個 數組對象。至於詳細的內存分配細節,還得看 該初始化是 數組動態初始化 還是

Linux同步與相互排斥應用(零):基礎概念

使用 line 關系 並發執行 來看 文章 必須 生產者 而且 【版權聲明:尊重原創,轉載請保留出處:blog.csdn.net/shallnet 或 .../gentleliu,文章僅供學習交流,請勿用於商業用途】 當操作系統進入多道批處理

python3 基礎概念

small obj 如果 公司 不可變類 col targe 形象 height 一、3.x新特性 1、print (),打印,3.x必須加括號 2、raw_input,3.x改為input 二、簡介 Python是著名的“龜叔”Guido van Ros

2017.06.29數據挖掘基礎概念第六,八,九章

之前 屬性。 prior 選擇 處理 挖掘 允許 什麽是 單元 第六章51、關聯規則的挖掘的兩個過程1、找出所有的頻繁項集2、由頻繁項集產生強關聯規則52、頻繁項集挖掘方法 1、Apriori算法 2、挖掘頻繁項集的模式增長方法 3、使用垂直數據格式挖掘頻繁項

2017.06.29數據挖掘基礎概念第四章

構建 企業 操作 允許 包含 元數據 體系結構 當前 然而 第四章39、為什麽在進行聯機分析處理(OLAP)時,我們需要一個獨立的數據倉庫,而不是直接在日常操作的數據庫上進行 1、提高兩個系統的性能 2、操作數據庫支持多事務的並發處理,需要並發控制和恢復機制,確保一

基礎概念

們的 例如 區別 行為 事物 創建 自己 避免 要求 1、面向對象3大特點 封裝:封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。 繼承:繼承是指這樣一種能力:它可以使用現有類的

K8S基礎概念

使用 外部 清理 lac six 基本上 新的 容器 所有 一、核心概念 1、Node Node作為集群中的工作節點,運行真正的應用程序,在Node上Kubernetes管理的最小運行單元是Pod。Node上運行著Kubernetes的Kubelet、kube-proxy

軟件測試基礎概念總結

開發 提高 運行程序 手機軟件 標準化 理論 report 計算 管理 一、軟件測試概述 (一)什麽是測試,與測試相關常見活動有哪些? 測試:與科學方法中的實驗類似,是對事物狀態、功能的測量和觀察。通過將測量結果與已知狀態或理論假設相比較,測試者得以對事物狀態、功能做出

粵嵌java培訓第一天筆記-java基礎概念

ont 類型 運算符 按位或 次循環 規則 是否 支持 har 一、二進制數   1、最高位為0,表示正數;最高位為1,表示負數。   2、相應的負數與正數之間進行轉換方式:通過補碼方式進行轉換,即:取反再加1。     例如:0000 0001 表示 +1;通過對 000

站點分析基礎概念之訪問停留時間

基礎概念 sso ack nts visit gin san faq iss 類型:計數度量 定義:訪問停留時間(Visit Duration)是指一次訪問的持續時間。典型的計算方法是在一次訪問中,用戶最後一次操作發生的時間減去第一次操作發生的時間。

機器學習基礎概念筆記

最大 什麽 mar 機器學習 決策 常見 idg 框架 評估 監督學習:分類和回歸屬於監督學習。這類算法必須知道預測什麽,即目標變量的分類信息。   常見算法:k-近鄰算法、線性回歸、樸素貝葉斯算法、支持向量機、決策樹、Lasso最小回歸系數估計、Ridge回歸、局部加權線

oracle DDL,DML,DCL, 基礎概念詳解

aud ase class con ani 概念 ddl 數據庫狀態 修改 一、SQL語言,有兩個組成部分:   DML(data manipulation language):它們是SELECT、UPDATE、INSERT、DELETE,命令是用來對數據庫裏的數據進行操作