C指针原理(23)-win32汇编及.NET调试
2018-12-28 20:36:07
在WINDOWS系統能用到匯編的機會不多,基本都可以用C或C++代勞,更何況現在MICROSOFT的Visual Studio 系列工具非常強大,WINDOWS下的開發已經在向.NET方面發展,實際調用WINDOWS SDK的機會也不多。 WIN32匯編編寫窗口程序需要調用大量的WINDOWS 的API,而且提供了高級語言才有的條件語句和循環語句,難度相對于LINUX下的AT&T匯編要小很多。
匯編可以開發WINDOWS程序?答案是肯定的,用WIN32匯編語言開發出來的WINDOWS程序具有執行效率高、占用空間小等特點。
一、開發工具下載與安裝
在眾多WIN32匯編開發工具中,MASM32筆者比較偏愛,它具有很多代碼示例和豐富的開發資源,在下列下載地址中選擇一個地址下載MASM32。
http://website.assemblercode.com/masm32/m32v9r.zip
http://masm32.masmcode.com/masm32/m32v9r.zip
http://webhost.ccp.com/~win32/hutch/m32v9r.zip
二、知識預備
1、寄存器
為了提高運算速度和數據的存取速度,在計算機的CPU內,有一組硬件裝置,第一個裝置內存放CPU運算需要的數,這些數值可供CPU直接存取,這組裝置叫寄存器。寄存器分為通用寄存器、段寄存器、程序指針寄存器、標志寄存器。
編程最常用就是通用寄存器,常用的通用寄存器有eax,ebx,ecx,edx,esi,edi等等,現代計算機的CPU一般是以32位為單位進行運算,因此一個寄存器最大能存放32位的二進制數。每個寄存器通常都有它默認的用法,所謂默認只是一種編程的習慣,你可以不遵守這些用法,但是有些情況下必須遵守,因為我們開發的是WINDOWS程序,要遵守WINDOWS操作系統的規定和匯編語法本身的約束,比如調用一個WINDOWSAPI函數,返回值放在EAX,堆棧的棧頂地址在esp,在匯編語言的循環中,ECX內存放循環的次數。具體寄存器的使用會在以后介紹。
2、堆棧
堆棧是個非常古老的概念,在DOS時代就有了,也是個非常重要的東西,程序沒了它就活不了,堆棧就是在內存里分配一個區域,使用這個區域必須遵守一個規定:后進先出,后進來的先出去,可以把它想像成一個空木箱,首先往里面放棉衣,然后往里面放書,最后放上運動服。如果要取出書,必須得把最后放上的運動服取出,放的順序是棉衣->書->運動服,取的順序是運動服->書->棉衣,堆棧也是如此。
先解釋一下什么是地址,內存價格的便宜和內存容量的擴大,WINDOWS虛擬內存早已出現,內存中放著眾多的數據,必須要有方法表示內存某個地點,這個地點就用地址來表示。把內存以字節為單位劃分,某個地址表示某個字節的地址,如左下圖是一個內有4個成員的堆棧,堆棧里的成員以一個字節為單位(數的右邊標明了以十六進制表示的地址,如1001)
±-+
|AF| 地址:AF21
±-+
|03| 地址:AF20
±-+
|30| 地址:AF19
±-+
|F1| 地址:AF18
±-+
堆棧是向下增長的,每增加一個成員,棧頂(堆棧頂部的地址)的地址減1,對于這個堆棧,棧頂地址是AF18,如果再往這個堆棧里增加一個成員的話,它的地址是:AF18-1=AF17。如果往這個堆棧里增加一個32位的數,棧頂的地址是多少呢,32位的數占4個成員的位置,棧頂的地址為:AF18-4=AF14。
在這個堆棧中增加一個32位數DAB0CD90,新的堆棧如下:
±-+
|AF| 地址:AF21
±-+
|03| 地址:AF20
±-+
|30| 地址:AF19
±-+
|F1| 地址:AF18
±-+
|DA| 地址:AF17
±-+
|B0| 地址:AF16
±-+
|CD| 地址:AF15
±-+
|90| 地址:AF14
±-+
如果從堆棧里拿走一個32位數,則棧頂的地址為:AF14+4=AF18
三、WIN32匯編語言的語法
為了方便大家理解和入門,下面盡量使用宏匯編和偽指令地方進行描述,也正因為有了宏匯編和偽指令的幫助,WIN32匯編才具有很多高級語言的特性,很多語法和C差不多。
1、WIN32匯編程序基本結構
.386
.MODEL Flat,STDCALL
.DATA
初始化值的全局變量定義.DATA?
未初始化值的全局變量定義.CONST
常量定義.CODE
.............................程序入口LABEL
........................end程序入口LABEL2、變量定義
(1)定義全局變量
全局變量定義在.data和.data?內,
初始化變量的定義方式如下:
.data
變量名 類型 初始值1,初始值2,…
變量名 類型 重復次數dup(初始值1,初始值2,…)
注意:如果用?表示初始值的話,則表示0未初始化變量的定義方式是
.data?
變量名 類型 ?(2)條件測試語句
(A)基本結構
.IF條件程序代碼[.ELSEIF]條件比較程序代碼.......[.ELSE]
程序代碼.ENDIF(3)操作符
(A)比較操作符
== 相等!= 不等于
大于
>= 大于或等于< 小于
<= 小于或等于& 位測試
! 邏輯非&& 邏輯與
|| 邏輯或
(B)位操作符
AND按位與OR 按位或
XOR 異或
SHL邏輯左移SHR邏輯右移?標志寄存器操作符
CARRY?是否進位OVERFLOW? 是否溢出
PARITY? 奇偶位是否置位
SIGN? 符號位標志位是否被置位
ZERO? 零位標志位是否置位
(4)循環語句
(A)while語句
while 條件
....................[.break[.if 退出條件]]
[.contine[.if 退出條件]]]
.end
(B)repeat語句
.repeat
…
…
[.break[.if 退出條件]]
[.contine[.if 退出條件]]]
.until 條件(或.untilcxz [條件])
(5)子程序定義
1、定義
子程序名 proc [距離][語言類型][可視區域][USERS 寄存器列表][,參數:類型]…[VARARG]local 局部變量列表
…
…
…
子程序名 endp
2、如果在未定義前使用,要聲明、
函數名 proto [距離][語言][參數1]:數據類型,[參數2]:數據類型,…
(6)數據結構
(A)聲明
wndclass struct
…
…
…
wndclass ends
(B)定義
mystruct wndclass<1,1,…,1>
mystruct wndclass <>
?使用
mov eax,mystruct.lpfnwndproc
mov esi,offset mystruct
assume esi: ptr WNDCLASS
mov eax,[esi].lpfnwndproc
…
assume esi:nothing
四、在WIN32匯編中的使用WINDOWS API
WIN32匯編如果沒有API的幫助無法實現很多功能,筆者沒見過在WIN32匯編程序不調用API的。
調用API實際上是靠堆棧來完成參數傳遞的,既然是堆棧,那就要遵守后進先出的原則,這意味API的第一個參數是最后一個放入堆棧的,最后一個參數是第一個放入堆棧的。
調用方式如下:
push 參數n
…
push 參數2
push 參數1
call API函數名
為了簡化代碼,也可以使用以下這種方式調用API
invoke API函數名,參數1,參數2,…,參數n
我們用WIN32匯編構建第一個WINODWS程序,這個程序完成顯示一個帶問號的對話框,對話框的內容是現在系統時間。
首先,打開MASM32Editor(在桌面上可以找到圖標),在里面輸入以下代碼:
.386.model flat, stdcalloption casemap :none;#################################################################
include windows.incinclude user32.incinclude kernel32.incinclude gdi32.incinclude masm32.incincludelib user32.libincludelib kernel32.libincludelib gdi32.libincludelib masm32.lib;#################################################################
.data?
szbuffer db 100 dup(?)
.data
szcaptionName db “我的HELLO,WORLD!”,0
szbegin db “現在時間:”
sztext db 100 dup(?)
;################################################################# .code
start:
;程序的入口
call _callgetnow
invoke MessageBox,NULL,offset szbegin,offsetszcaptionName,MB_ICONQUESTION or MB_OK
invoke ExitProcess,eax
;#################################################################
_callgetnow proc
pushad
invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100
invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100
_callgetnow endp
;#################################################################
end start
將上述代碼保存為HELLOWORLD.ASM后,對程序進行編譯。
在編譯前參照下圖設置好系統的環境變量,path變量加上x:\masm32\bin,lib變量加上x:\masm32\lib,include變量加上x:\masm32\include。
確環境變量設置好后,進入DOS窗口開始編譯。
首先運行ml,編譯成coff文件格式
然后運行LINK,進行鏈接,生成EXE文件,
大功造成,運行一下試試效果吧!
下面我們接著來做一個有些難度的helloworld,這個程序將系統時間直接顯示在桌面上。程序源代碼如下:
.386.model flat, stdcalloption casemap :none ;#########################################################################include windows.incinclude user32.incinclude kernel32.incinclude gdi32.incinclude masm32.incincludelib user32.libincludelib kernel32.libincludelib gdi32.libincludelib masm32.lib;#########################################################################.data?szbuffer db 100 dup(?).dataszmssucesscap db "HELLO,WORLD!深入",0szmssucesstext db "在桌面的(300,300)處顯示了當前時間",0szmscap db "錯誤",0szmstext1 db "無法在桌面上顯示!",0szmstext2 db "無法得到全屏DC!",0szbegin db "現在時間:"sztext db 100 dup(?) ;#########################################################################.codestart: ;程序的入口_showtext proto :DWORDcall _callgetnowinvoke _showtext,offset szbegininvoke ExitProcess,eax ;######################################################################### _callgetnow procpushadinvokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100invokeszCatStr,addr sztext,addr szbufferpopadret _callgetnow endp ;######################################################################### _showtext proc lpsztext:DWORDLOCAL@Desktopdc:HDCLOCAL@dwcolor:DWORDpushadmov@dwcolor,00FF0000hinvokeGetWindowDC,NULLcmpeax,0jne @finvokeMessageBox,NULL,offset szmstext2,offset szmscap,MB_ICONERROR@@:mov@Desktopdc,eaxinvokelstrlen,lpsztextmovebx,eaxinvokeSetBkMode,@Desktopdc,TRANSPARENTinvokeSetTextColor,@Desktopdc,@dwcolorinvokeTextOut,@Desktopdc,300,300,lpsztext,ebxinvokeMessageBox,NULL,offset szmssucesstext,offsetszmssucesscap,MB_ICONINFORMATIONcmpeax,0jne @finvokeMessageBox,NULL,offset szmstext1,offset szmscap,MB_ICONERROR@@:popadret _showtext endp ;#########################################################################end start以上程序中有幾個重要的GDI相關的API,下面簡要介紹一下
(1)
invoke SetBkMode,@Desktopdc,TRANSPARENT
設置背景方式為透明
(2)
invoke SetTextColor,@Desktopdc,@dwcolor
設置字體顏色為藍色
(3)
invoke TextOut,@Desktopdc,300,300,lpsztext,ebx
在300,300處顯示文本
(4)
invoke GetWindowDC,NULL
取得桌面DC
(5)
mov @dwcolor,00FF0000h
設置顏色為藍色。@dwcolor是一個DWORD型的變量,
可以在相關頭文件中找到這樣的定義:
typedef DWORD COLORREF;
因此COLORREF類型的變量就是DWORD型變量。
COLORREF變量如何表示顏色呢,只有一個雙字大小,它的表示格式是(16進制):
0x00bbggrr
bb表示藍色,gg表示綠色,rr表示紅色
00FF0000h:藍
0000ff00h:綠
000000FFh:紅
程序運行效果如下:
因此,在此只簡單介紹一下,首先來看一段簡單的窗口程序。注意";"表示注釋
;加上注釋和個人理解
.386
.model flat,stdcall
option casemap:none
;以下定義INCLUDE文件
include winows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
include kernel32.lib
;以下定義數據段
.data ? ;定義變量
hinstance dd ?
hwinmain dd ?
.const ;定義常量,字符串全部要以0結尾,因為在內存中0是字符串的結束符
szclassname db ‘billclass’,0
szcaptionmain db ‘bill’s firt program’,0
sztext db ‘WIN32匯編,BILL!!!!’,0
;以下是代碼段
.code
;定義窗口過程
_procwinmain proc uses ebx edi esi,hwnd,umsg,wparam,lparam
;定義局部變量用關鍵字local
local @stps:PAINTSTRUCT
local @strect:PAINTSTRUCT
local @hdc
mov eax,umsg ;取得傳入過程的消息變量值
;-----------下面開始根據消息類型的不同作出不同的處理
.if eax == WM_PAINT ;如果消息是窗口繪制
invoke BeginPaint,hwnd,addr@stRect;WIN32匯編調用API程序后,API程序將返回值放在EAX中,
;客戶區準備
mov @hdc,eax;取得設備句柄
invoke GetclientRect,hwnd,addr @stRect;addr是取變量的地址但只能用在INVOKE語句中且
;不能同時使用
;EAX寄存器傳參數,因為ADDR會用到EAX。
;此API的含義是取得描述客戶區的結構放在@stRect
invoke drawText,@hdc,addr sztext,-1,addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER ;語句換行符是\,顯示’WIN32匯編,BIL
;L!!!!’,并設置其為單行DT_SINGLE
;等等LINE
invoke EndPaint,hwnd,addr @stPs
.elseifmeax==WM_CLOSE
invoke DestroyWindow,hwinmain ;銷毀窗口
invoke PostQuitMessage,Null ;向消息循環中發出退出消息
.else
invoke DefWindowProc,hwnd,uMsg,wPara,lParam;如果不是上述消息,則執行WINDOWS標準的默認消息處
;理,如鍵盤等消息
ret;返回
.endif
xor eax,eax ;eax清0
ret
_ProcWinMain endp
;以上這個子程序處理窗口消息的,是窗口的回調函數,該項函數不是我們調用,是由WINDOWS調用用來處理
;窗口消息的,我們調用的是DispatchMessage,DispatchMessage再回過頭來調用窗口過程。
_WinMain Proc ;主程序
local @stWndClass:WNDCLASSEX
local @stmsg:MSG
invoke GetModuleHandle,Null ;得到應用程序句柄
mov hInstance,eax ;將應用程序的句柄放入hInstance變量
invoke RtlZeroMemory,addr @stWndClass,sizeof WndClassEX ;msdn的解釋TheRtlZeroMemory routine
;fills a block of memory with zeros,即
;0填充stWndClass結構變量所占的內存,也就是初始化
;-----下面注冊窗口類
invoke loadcursor,0,IDC_ARROW ;加載箭頭形指針句柄
mov @stWndClass.hCursor,eax ;鼠標指針賦值
push hInstance
pop @stWndClass.hInstance ;窗口句柄賦值
mov @stWndClass.cbsize,sizeof WNDCLASSEX ;結構大小
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW ;設置窗口樣式
mov @stWndClass.lpfnwndproc,offset _procwinmain;設置回調函數,也就是窗口消息處理過程
mov @stwndclass.hbrbackground,COLOR_WINDOW+1
mov @stwndclass.lpszclassname,offset szclassname ;設置窗口類的名稱
invoke RegisterClassEx,addr @stwndclass ;傳上述設置好的結構以注冊窗口類
;建立顯示窗口
invoke CreateWindowEx,WS_EX_CLIENTEDGE,\
offset szclassname,offsetszcaptionmain,\
WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,\
NULL,hinstance,NULL ;建立窗口并返回句柄在EAX中
mov hwinMain,eax ;剛創建的窗口句柄賦值
invoke showwindow,hwinmain,SW_SHOWNORMAL ;顯示窗口
invoke updatewindow,hwinmain ;刷新窗口客戶區,導致客戶區窗口paint
;消息循環,win32匯編得自行建立WINDOWS消息循環,不過這樣更自由,可以徹底地控制程序
.while true
invoke GetMessage,addr @stMsg,null,0,0 ;WINDOWS在系統內部有個系統消息隊列,
;并為每個應用程序還維護了一個消息隊列,將這些屬于這些程序窗口范圍內的
;系統消息發到該應用程序消息隊伍中,這個API的作用就是從自己的應用程序
;消息隊伍中接收消息。
.break .if eax==0 ;If the function retrieves the WM_QUIT message, the return value is zero.
;invoke Translate(msdn),也就是說,當程序退出里,消息隊伍里會有WM_QUIT消息, ;就退出循環,意味著退出程序。
invoke translatemessage,addr @stmsg;由應用程序對消息進行預處理,如把基于鍵盤掃描碼的按鍵消息黑心 ;換成ASCII碼的鍵盤消息等
invoke dispatchmessage,addr@stmsg ;將預處理好的消息發給WINDOWS,WINDOWS將其分派給該程序的相應窗;口處理過程處理,那么WINDOWS怎么知道窗口處理過程在哪呢,剛才不是已經注冊過窗口類了,這就是為什么窗口;類要注冊的原因了,那么為什么不能由程序自己處理消息,非得發給WINDOWS呢,其一、一個應有程序的窗口很多,如果自己處理的話,得建立一個窗口列表,上面記錄每個窗口的窗口處理過程。其二、WINDOWS對于一些實時性很;強的信息采用直接調用窗口處理過程的方法。
.endw
ret
_winmain endp
;沒有下面的代碼程序無法執行,因為START語句指定程序啟動的入口點
start:
call _winmain
invoke ExitProcess,NULL;退出
end start
可以看到上面代碼和用C編寫的WIN SDK程序很相似。我們接著繼續看2個例子:
例1:用WIN32匯編構建第一個WINODWS程序,這個程序完成顯示一個帶問號的對話框,對話框的內容是現在系統時間。
首先,打開MASM32Editor(在桌面上可以找到圖標),在里面輸入以下代碼:
.386 .model flat, stdcall option casemap :none ;################################################################# include windows.inc include user32.inc include kernel32.inc include gdi32.inc include masm32.inc includelib user32.lib includelib kernel32.lib includelib gdi32.lib includelib masm32.lib ;################################################################# .data? szbuffer db 100 dup(?) .data szcaptionName db "我的HELLO,WORLD!",0 szbegin db "現在時間:" sztext db 100 dup(?) ;################################################################# .code start: ;程序的入口 call _callgetnow invoke MessageBox,NULL,offset szbegin,offsetszcaptionName,MB_ICONQUESTION or MB_OK invoke ExitProcess,eax ;################################################################# _callgetnow proc pushad invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100 invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100 invokeszCatStr,addr sztext,addr szbuffer popad ret _callgetnow endp ;################################################################# end start將上述代碼保存為HELLOWORLD.ASM后,對程序進行編譯。
在編譯前參照下圖設置好系統的環境變量,path變量加上x:\masm32\bin,lib變量加上x:\masm32\lib,include變量加上x:\masm32\include。
確環境變量設置好后,進入DOS窗口開始編譯。
首先運行ml,編譯成coff文件格式
然后運行LINK,進行鏈接,生成EXE文件,
大功造成,運行一下試試效果吧!
例2:系統時間直接顯示在桌面上。程序源代碼如下:
Asm代碼
.386
.model flat, stdcall
option casemap :none
;#########################################################################
include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include masm32.inc
;#########################################################################
.data?
szbuffer db 100 dup(?)
.data
szmssucesscap db “HELLO,WORLD!深入”,0
szmssucesstext db “在桌面的(300,300)處顯示了當前時間”,0
szmscap db “錯誤”,0
szmstext1 db “無法在桌面上顯示!”,0
szmstext2 db “無法得到全屏DC!”,0
szbegin db “現在時間:”
sztext db 100 dup(?)
;#########################################################################
.code
start:
;程序的入口
_showtext proto :DWORD
call _callgetnow
invoke _showtext,offset szbegin
invoke ExitProcess,eax
;#########################################################################
_callgetnow proc
pushad
invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100
invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100
_callgetnow endp
;#########################################################################
_showtext proc lpsztext:DWORD
LOCAL@Desktopdc:HDC
LOCAL@dwcolor:DWORD
_showtext endp
;#########################################################################
end start
以上程序中有幾個重要的GDI相關的API,下面簡要介紹一下
(1)
invoke SetBkMode,@Desktopdc,TRANSPARENT
設置背景方式為透明
(2)
invoke SetTextColor,@Desktopdc,@dwcolor
設置字體顏色為藍色
(3)
invoke TextOut,@Desktopdc,300,300,lpsztext,ebx
在300,300處顯示文本
(4)
invoke GetWindowDC,NULL
取得桌面DC
(5)
mov @dwcolor,00FF0000h
設置顏色為藍色。@dwcolor是一個DWORD型的變量,
可以在相關頭文件中找到這樣的定義:
typedef DWORD COLORREF;
因此COLORREF類型的變量就是DWORD型變量。
COLORREF變量如何表示顏色呢,只有一個雙字大小,它的表示格式是(16進制):
0x00bbggrr
bb表示藍色,gg表示綠色,rr表示紅色
00FF0000h:藍
0000ff00h:綠
000000FFh:紅
.NET堆棧原理
1、用調試器調試線程
1)棧調用
以下面代碼為例
Imports System.Threading
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim main_x As Integer main_x = 5 Call sub1(main_x) End Sub Private Sub sub1(sub1_x As Integer) Dim jg As Integer jg = sub1_x sub1_x Call sub2(jg) End Sub Private Sub sub2(sub2_x As Integer) Dim jg As Integer jg = sub2_x 2 '在下一句設置斷點 jg = jg * jg End SubEnd Class
我們首先來看調用堆棧,在調試菜單中選擇調用堆棧,可看到過程的調用順序:
然后查看線程
最后查看局部變量
此外,我們還可以研究一下這個線程的調用時堆棧情況,通過反匯編代碼,在調用堆棧窗口中選擇“轉到反匯編”
Private Sub sub2(sub2_x As Integer)
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,14h
00000006 mov dword ptr [ebp-10h],ecx
00000009 mov dword ptr [ebp-4],edx
0000000c cmp dword ptr ds:[0256B1B8h],0
00000013 je 0000001A
00000015 call 62A16743
0000001a xor edx,edx
0000001c mov dword ptr [ebp-8],edx
0000001f mov eax,dword ptr [ebp-10h]
00000022 mov dword ptr [ebp-14h],eax
00000025 mov ecx,dword ptr [ebp-10h]
00000028 call 628F5C25
0000002d mov dword ptr [ebp-0Ch],eax
00000030 push 32h
00000032 mov edx,dword ptr [ebp-0Ch]
00000035 mov ecx,dword ptr [ebp-14h]
00000038 call FFDF30D0
0000003d mov ecx,dword ptr [ebp-4]
00000040 call FFFFFF70
00000045 mov ecx,63h
0000004a call FFDF2940
0000004f nop
Dim jg As Integer
jg = sub2_x 2
00000050 mov eax,dword ptr [ebp-4]
00000053 mov edx,2
00000058 imul eax,eax,2
0000005b jno 00000062
0000005d call 62A19A30
00000062 mov dword ptr [ebp-8],eax
'在下一句設置斷點
jg = jg jg
00000065 mov eax,dword ptr [ebp-8]
00000068 imul eax,dword ptr [ebp-8]
0000006c jno 00000073
0000006e call 62A19A30
00000073 mov dword ptr [ebp-8],eax
00000076 nop
00000077 nop
00000078 mov ecx,63h
0000007d call FFDF2A60
00000082 nop
00000083 mov esp,ebp
00000085 pop ebp
00000086 ret
ESP是棧頂指針
ebp是基址指針
±----+
+基址 +
±----+
+棧內容+
+棧內容+
+棧內容+
+棧內容+
+棧內容+
+棧頂 +
如上圖所示,基地的地址比棧頂的地址大,就是向下增長。
寄存器ebp和esp保存著當前的基址和棧頂地址
首先,進入函數時
00000000 push ebp
備份基址指針
00000001 mov ebp,esp
然后設置基址指針指向棧頂,相當于為當前棧清空了內容,做好在棧中分配局部變量的準備
00000003 sub esp,14h
完成棧(可以理解為本函數可訪問的棧)的空間分配,將棧頂指針向下增長14h(向下增長的意思是棧的空間增長規律是地址遞減)。相當于棧中已經容納了14h的空間
Dim jg As Integerjg = sub2_x 200000050 mov eax,dword ptr [ebp-4]
00000053 mov edx,2
00000058 imul eax,eax,2
0000005b jno 00000062
0000005d call 617391D0
00000062 mov dword ptr [ebp-8],eax
'在下一句設置斷點
jg = jg jg
00000065 mov eax,dword ptr [ebp-8]
00000068 imul eax,dword ptr [ebp-8]
0000006c jno 00000073
0000006e call 617391D0
00000073 mov dword ptr [ebp-8],eax
從上面這段代碼可以看出來
sub2_x分配在了dword ptr [ebp-4] ,而jg分配在了dword ptr [ebp-8]
最后,離開函數時,恢復進入函數前棧的指針,相當于釋放了本次在棧中分配的空間
End Sub00000083 mov esp,ebp
恢復棧頂指針
00000085 pop ebp
恢復基址指針
00000086 ret
2、修改默認棧的大小
Dim 線程變量名 As Thread = New Thread(函數名,以字節為單位的棧大小)比如
Dim mythread As Thread = New Thread(myfun,1024*512)分配了512kb字節
總結
以上是生活随笔為你收集整理的C指针原理(23)-win32汇编及.NET调试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 中的单引号报错_shell中的
- 下一篇: spring boot配置dubbo(X