C指针原理(31)-win32汇编及.NET调试
来源:互联网 发布:edius8软件下载 编辑:程序博客网 时间:2024/06/07 23:09
在WINDOWS系统能用到汇编的机会不多,基本都可以用C或C++代劳,更何况现在MICROSOFT的Visual Studio 系列工具非常强大,WINDOWS下的开发已经在向.NET方面发展,实际调用WINDOWS SDK的机会也不多。 WIN32汇编编写窗口程序需要调用大量的WINDOWS 的API,而且提供了高级语言才有的条件语句和循环语句,难度相对于LINUX下的AT&T汇编要小很多。
本博客所有内容是原创,如果转载请注明来源
http://blog.csdn.net/myhaspl/
汇编可以开发WINDOWS程序?答案是肯定的,用WIN32汇编语言开发出来的WINDOWS程序具有执行效率高、占用空间小等特点。
我们用WIN32汇编构建第一个WINODWS程序,这个程序完成显示一个带问号的对话框,对话框的内容是现在系统时间。
.model flat, stdcall
option casemap :none
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
;程序的入口
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
;#################################################################
大功造成,运行一下试试效果吧!
下面我们接着来做一个有些难度的helloworld,这个程序将系统时间直接显示在桌面上。程序源代码如下:
.model flat, stdcall
option casemap :none
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
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
;程序的入口
_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
invokeszCatStr,addr sztext,addr szbuffer
popad
ret
_callgetnow endp
;#########################################################################
_showtext proc lpsztext:DWORD
LOCAL@Desktopdc:HDC
LOCAL@dwcolor:DWORD
pushad
mov@dwcolor,00FF0000h
invokeGetWindowDC,NULL
cmpeax,0
jne @f
invokeMessageBox,NULL,offset szmstext2,offset szmscap,MB_ICONERROR
@@:
mov@Desktopdc,eax
invokelstrlen,lpsztext
movebx,eax
invokeSetBkMode,@Desktopdc,TRANSPARENT
invokeSetTextColor,@Desktopdc,@dwcolor
invokeTextOut,@Desktopdc,300,300,lpsztext,ebx
invokeMessageBox,NULL,offset szmssucesstext,offsetszmssucesscap,MB_ICONINFORMATION
cmpeax,0
jne @f
invokeMessageBox,NULL,offset szmstext1,offset szmscap,MB_ICONERROR
@@:
popad
ret
_showtext endp
;#########################################################################
因此COLORREF类型的变量就是DWORD型变量。
因此,在此只简单介绍一下,首先来看一段简单的窗口程序。注意";"表示注释
- ;加上注释和个人理解
- .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程序,这个程序完成显示一个带问号的对话框,对话框的内容是现在系统时间。
- .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
确环境变量设置好后,进入DOS窗口开始编译。
大功造成,运行一下试试效果吧!
- .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
- 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
- invokeszCatStr,addr sztext,addr szbuffer
- popad
- ret
- _callgetnow endp
- ;#########################################################################
- _showtext proc lpsztext:DWORD
- LOCAL@Desktopdc:HDC
- LOCAL@dwcolor:DWORD
- pushad
- mov@dwcolor,00FF0000h
- invokeGetWindowDC,NULL
- cmpeax,0
- jne @f
- invokeMessageBox,NULL,offset szmstext2,offset szmscap,MB_ICONERROR
- @@:
- mov@Desktopdc,eax
- invokelstrlen,lpsztext
- movebx,eax
- invokeSetBkMode,@Desktopdc,TRANSPARENT
- invokeSetTextColor,@Desktopdc,@dwcolor
- invokeTextOut,@Desktopdc,300,300,lpsztext,ebx
- invokeMessageBox,NULL,offset szmssucesstext,offsetszmssucesscap,MB_ICONINFORMATION
- cmpeax,0
- jne @f
- invokeMessageBox,NULL,offset szmstext1,offset szmscap,MB_ICONERROR
- @@:
- popad
- ret
- _showtext endp
- ;#########################################################################
- end start
因此COLORREF类型的变量就是DWORD型变量。
.NET堆栈原理
1、用调试器调试线程
本博客所有内容是原创,如果转载请注明来源
http://blog.csdn.net/myhaspl/
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 Sub
- End 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
- End Sub
- 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 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 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 Sub
00000083 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指针原理(31)-win32汇编及.NET调试
- C指针原理(1)-AT&T汇编
- C指针原理(2)-AT&T汇编
- C指针原理(3)-AT&T汇编
- C指针原理(4)-AT&T汇编
- C指针原理(5)-AT&T汇编
- C指针原理(28)-AT&T汇编
- C指针原理(29)-AT&T汇编
- C指针原理(94)-汇编基础(1)
- C指针原理(95)-汇编基础(2)
- C指针原理(27)-汇编分析C指针机制
- 关于win32汇编的调试
- C指针原理(6)-C内嵌汇编
- C指针原理(7)-C内嵌汇编
- C指针原理(8)-C内嵌汇编
- C指针原理(9)-C内嵌汇编
- Win32调试API原理
- Win32调试API原理
- Tomcat(免安装版)的安装与配置
- 【Unity3D】【NGUI】UIScrollBar
- 分析av_open_input_file的主要流程
- 包含《三目运算、BT交换、数组查询》的超级练习!
- Swing 带标题栏的右键菜单(三)增强版
- C指针原理(31)-win32汇编及.NET调试
- 八大Linux/Unix服务器内存转储工具
- HTML5自学手册--HTML5简介(1)
- Wine的中文显示与字体设置
- ORACLE ORA-01722 错误解决
- C++写的与http交互的类CHttpClient
- java 泛型 extends 多个
- cocos2dx初接触之创建工程
- jinja2模板设计者文档和API文档