32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数
32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数
(如果想看所有代码,请下载课堂资料,里面有所有代码,这里会讲解怎么生成一个窗口程序)
一丶32位汇编编写Windows窗口程序
首先我们知道32位汇编是可以调用Windows API的,那么今天我们就调用windowsAPI来写一个窗口程序
如果你有windows开发知识,那么就很理解了,如果没有,那么跟着我写,跟着步骤去写,那么也可以写出来
首先我们要编写一个窗口程序(使用SDKAPI编写)有几个步骤
1.设计窗口类
2.注册窗口类
3.创建窗口
4.显示窗口
5.更新窗口
6.建立消息循环
7.窗口过程函数
总共需要这几步,每不单独做个讲解.
1.设计窗口类
设计窗口类,顾名思义,就是你要给你的窗口设置一些属性,比如我窗口的风格,名字,类名,图标,菜单什么的
这里windows为我们提供了一个结构体
WNDCLASS结构体,里面就包含了这些属性,我们只需要依次添加,看下WNDCLASS里面的内容
WNDCLASS
This structure contains the window class attributes that are registered by the RegisterClass function. typedef struct _WNDCLASS {
UINT style; //窗口的风格
WNDPROC lpfnWndProc; //窗口消息处理的过程函数
int cbClsExtra; //额外内存申请(不重要)
int cbWndExtra; //额外内存申请(不重要)
HANDLE hInstance; //程序的实例句柄
HICON hIcon; //图标
HCURSOR hCursor; //资源光标
HBRUSH hbrBackground; //窗口背景
LPCTSTR lpszMenuName; //窗口名字
LPCTSTR lpszClassName; } WNDCLASS ; //窗口类名
对于上面的结构体,我们只需要里面的参数需要什么内容即可
使用汇编编写:
include windows.inc
include user32.inc ;加载要使用的头文件和lib库,至于这些是什么,下面仔细讲解
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
.386
.model FLAT,stdcall
option casemap:none
.const ;常量区
g_szClassName db "ClassName",0 ;窗口类的类名名称
g_szWndName db "WndName",0 ;窗口的名称
.data ;初始化的数据区 .code ;代码区
WinMain proc ;程序启动的时候执行的入口函数
;设计我们的窗口类
LOCAL @wc:WNDCLASS ;定义WNDCLASS,对里面的属性修改
LOCAL @hInstance : HINSTANCE ;定义程序的实例句柄
LOCAL @hWnd:HWND ;定义我们的hWnd,接受创建窗口的时候的返回值\
LOCAL @msg:MSG ;定义消息循环的结构体 ;思路,第一步,取得窗口的实例句柄,给hInstance
invoke GetModuleHandle,NULL ;调用API即可获取,返回值默认放在Eax当中
mov @hInstance,eax
;check(为了排版,不写检查了)....
;开始给WNDCLASS各种属性赋值
mov @wc.style, CS_VREDRAW or CS_HREDRAW; ;默认,垂直和水平拉伸窗口,窗口内容重新布局和绘制
mov @wc.lpfnWndProc, WindowProc; ;窗口过程函数
mov @wc.cbClsExtra, 0; ;额外内存
mov @wc.cbWndExtra, 0; ;额外内存
mov eax, @hInstance ;实例句柄的值给eax,下方设置进去,(内存到内存不可以,所以中转)
mov @wc.hInstance, eax; ;给窗口设置实例句柄
mov @wc.hIcon, NULL; ;图标资源为NULL
mov @wc.hCursor, NULL; ;鼠标光标为NULL
mov @wc.hbrBackground, COLOR_ACTIVEBORDER; ;设置背景画刷
mov @wc.lpszMenuName, NULL; ;设置菜单名称
mov @wc.lpszClassName,offset g_szClassName;;设置窗口类名名称
;这里就设计完成了,下一步就要注册这个窗口类,到系统中,所以这里为中间线,注册窗口的代码我会接着这下面继续写,上面的代码就不重复写了,下面的几个步骤是一样的,最后在把整个的汇编代码贴上
WinMain endp
end WinMain
2.剩余步骤一起执行
;对于下方的API不熟悉的可以调用MSDN,下载地址在 www.w1x8.com,因为文件太大,所以不上传到课堂资料中了
;注册窗口类
invoke RegisterClass,addr @wc ;在这里我们使用伪指令addr,他的作用是自动帮我们计算局部变量所在的内存地址,如果对指令不挑明白,可以打开OD找到这个地方看下指令是怎么写的
;创建窗口
invoke CreateWindowEx, ;这里注意一下只能使用CreateWindowEx,因为.inc文件中没有CreateWindows
0 ;窗口的扩展风格
offset g_szClassName, ;窗口的类名
offset g_szWndName, ;窗口的标题名字
WS_OVERLAPPEDWINDOW, ;窗口的风格
CW_USEDEFAULT, ;下面4个默认的分别是否是 窗口的高度 宽度 ,窗口的x,y坐标
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, ;窗口父类的实例句柄
NULL, ;窗口的菜单
@hInstance, ;程序的实例句柄
NULL ;创建窗口的额外参数
mov @hWnd,eax ;创建窗口后返回一个窗口句柄,返回值地方在eax中,这个上面定义了
;显示窗口
invoke ShowWindow,@hWnd,SW_SHOW ;显示窗口
;更新窗口
invoke UpdateWindow,@hWnd
;建立消息循环
.while TRUE
invoke GetMessage,addr @Msg,NULL,0,0
;判断
.if (eax == -1)
.break
.endif
invoke TranslateMessage, addr @msg ;把虚拟键码,转化为键盘按键
invoke DispatchMessage, addr @msg ;把msg中的消息,放到窗口过程中执行
.endw
;建立窗口过程
WindowProc proc hWnd:HWND,uMsg:UINT,wParam,WPARAM,lParam:LPARAM
;判断消息执行
.if uMsg == WM_KEYDOWN
.....;执行你的代码
.endif
invoke DefWindowProc,hWnd,uMsg,wParam,lParam;
ret
WindowProc endp ;函数结束
对于上面的代码,不保证能正确执行,因为编写博客,不能把上面代码调试,所以思路代码都是一样的,我会发到课堂资料中
请参考课堂资料中的代码
3.资源的使用
现在我们还不能使用资源,那我们必须编译一个资源文件,.rc结尾,
资源文件,是vc++6.0中常用的资源文件,而编译资源文件的编译器是.rc.exe,这个编译器我都会放到
课堂资料中
首先编译一个资源弄文件
这里使用VC++6.0编写一个
主要代码就是这里,我们使用rc.exe编译这个资源弄文件(这个文件的后缀名是.rc结尾)
编译出来之后是.RES的文件,我们把它当做obj文件使用,连接到PE文件中(exe文件中)即可
但是我们在设计窗口类的时候,需要使用一下这个菜单资源的ID
菜单资源的ID,在资源对应的Result.h的头文件中,我们拿过来即可.
我们要做的就是把资源变为汇编中的即可
比如上面的DIR_MENU1 代表101
那我们用汇编编写为 IDR_MENU1 EQU 101 即可
我们使用link 连接到一起即可
link /subsystem:windows 窗口.obj AAA.RES
然后编译出来就有菜单了,如果响应消息,则在窗口过程函数中捕获WM_COMMAND消息即可
然后资源文件其实是二进制,连接到EXE中(也就是放到EXE当中),那么我们使用WinHex可以再不需要源码的
情况下,把名字修改了
我的WinHex没有设置编码,所以看得不太清楚,这里就是存放资源的地方,我们把名字修改了,重新打开我们的窗口
改为Y,重新打开窗口
可以看到,已经修改为YIle了,所以逆向是很好玩的.不需要代码,可以直接修改你的程序
二丶.inc文件格式,和.lib文件的说明
1..inc文件说明
上面我们使用了各种.inc文件,我们看下内部是什么,比如windows.inc
对于.inc文件,有个第三方出的工具,可以自动生成,我们看下(MASM32,会打包)
其中上面画框的使我们需要的,下面的我们不太关系,如果关心,可以自动尝试一下(这个工具建议收藏)
我们编写windows程序的时候,只需要包含一个windows.h即可编写代码,是因为windows.h里面有帮我们定义的各种宏,以及函数的声明,在这里我们使用的.inc也是一样的,所以像上面的各种宏,和使用的函数,我们都不用定义了
这里主要介绍一下,lib 转化为.inc文件,首先我们知道,lib文件中存放了各种函数的声明,参数个数,所以这个工具是提取lib,并且转化为对应的.inc文件
我们看一下吧,随便找个lib拷贝过去
拷贝到工具目录下(tools)
可以看到很多工具,这里 我们使用的是 l2inc 正确的读法 是 lib to inc ,这里的2代表是to的意思
可以看到也有inc转化为lib的,自己尝试
我们拷贝到l2inc文件下
打开CMD,进入当前的路径,输入 l2inc lib文件名 回车即可生成
那我们的汇编程序就可以使用了
inc文件中对应的就是函数的声明,可以看出,参数类型都是DWORD类型的
2.lib文件说明
比如昨天我们编译的HelloWord程序,就要手动编译的时候,加上对应的user32.lib,而user32.lib是保存了dll文件中的 名字,还有导出函数,所以加载了这个lib,会找对应的dll和他的导出函数,进而执行我们的程序
这里在文件内部使用的,所以我们连接的时候不用手动去写了
这里的lib文件是 动态的静态加载
什么意思:
动态的指的就是dll,静态的指的就是dll所对应的lib,这个lib保存了dll的路径信息,还有导出函数信息,当我们连接到EXE中的时候,会从lib中拷贝dll的路径,以及导出函数,然后放到exe当中,
当我们调用的时候,会根据dll的路径,找到对应的dll,根据导出函数,调用dll的导出函数(比如昨天的HELLO信息框)
静态加载:
静态加载则是直接把lib连接到exe当中,(这个lib中放的都是代码),相当于把代码拷贝到exe中,这样调用的时候,直接执行代码,而不从dll中去执行这个API了. 确定点是文件大,不容易维护,优点,这个程序任何windows平台上,都能运行,不管你有没有dll
关于静态加载,和动态加载,在下面的调用C库函数中讲解
三丶动态和静态的使用C库函数
1.首先是动态的使用
动态的使用我们需要加上 msvcrt.inc然后还需要msvcrt.lib
.inc 我们知道存的是函数的声明, 而.lib则是存放的dll的路径,以及导出函数
例子:
.
.model FLAT,stdcall
option casemap:none
;__UNICODE__ equ include msvcrt.inc
includelib msvcrt.lib ;crt_ 动态使用 .data
g_SzBuff db dup() ;使用Strcpy,拷贝到这里面
g_SiTile db "Hello", ;把Hello拷贝到szBuff里面
.const .code START:
invoke crt_strcpy ,offset g_SzBuff,offset g_SiTile ;拷贝字符串,为什么使用crt开头,因为调用约定是C,作者
;调用约定是C,那么会有名称粉碎,每次比如strcpy,则在前边加上
;_开头,如果是std调用约定,则在后面加上@符号,所以作者为了省事
;在_strcpy加上了crt,这样简单 ret end START
看下编译出的程序,使用OD调试查看
我们要拷贝字符串,则看下是否成功拷贝
拷贝后
然后我们 ALT + E 看下模块表,可以找到我们的MSVCRT
可以看出调用的是这个.dll的内容
看下Call
Call后面则不一样,表明调用的是Dll中,然后看下面的代码,有个 add ESP,0X8,则表明strcpy是一个C调用约定
因为C调用约定必须外面平栈
2.静态的使用
静态的使用,则用libc.lib,这里面存放了代码,但是需要注意一下,我们提供的工具 MASM32有这个,
而VC++6.0中也有,VS系列也有,至于使用那个版本,就看环境变量谁在前边了,(最好不用MASM32的)
MASM32的libC不全,会导致我们编写代码出错,我们可以从其他位置拷贝一个,放到MASM32的lib文件夹中
(因为我的环境变量他在最前边,所以优先找他,所以我要拷贝,或者你直接拷贝到根目录下)
静态使用分为两步
1.包含lib includelib libc.lib
2.对你使用的函数声明一下,因为没有inc文件了,所以都要自己声明
例子:
.
.model FLAT,stdcall
option casemap:none
;__UNICODE__ equ ; include msvcrt.inc
; includelib msvcrt.lib ;crt_ 动态使用 includelib libc.lib ;静态使用 strcpy proto c, :dword, :dword ;声明函数
.data
g_SzBuff db dup() ;使用Strcpy,拷贝到这里面
g_SiTile db "Hello", ;把Hello拷贝到szBuff里面
.const .code START:
; invoke crt_strcpy ,offset g_SzBuff,offset g_SiTile ;拷贝字符串,为什么使用crt开头,因为调用约定是C,作者
; ;调用约定是C,那么会有名称粉碎,每次比如strcpy,则在前边加上
; ;_开头,如果是std调用约定,则在后面加上@符号,所以作者为了省事
; ;在_strcpy加上了crt,这样简单
;静态使用
invoke strcpy, offset g_SzBuff,offset g_SiTile ret end START
看下OD调试(对于编译连接,这里不说了,很常用了,不会的自己多敲几遍,对于以后新增加编译选项则会对应的讲解一下)
我们可以看到,CALL直接成为了地址了,因为代码就在我么我们的EXE文件中,所以直接在对应的地址找到代码的执行位置执行即可.
第二讲资料:
链接:http://pan.baidu.com/s/1qXIW2sc 密码:zpq1
32汇编所有资料链接请看所有资料分享的总博客,里面集合了链接
32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数的更多相关文章
- 32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用
32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用 一丶32位(x86也称为80386)与8086(16位)汇编的区别 1.寄存器的改变 AX 变为 EAX 可以这样想,16位通 ...
- 内核开发知识第二讲,编写Kerner 程序中注意的问题.
一丶函数多线程的安全问题 什么是函数多线程安全. 简单来说就是 ,一个函数在调用过程中.还没有返回的时候.再次被其他线程调用了.但是函数执行的结果是可靠的.就可以了说这个函数是安全的. 比如我们在用户 ...
- 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)
32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...
- 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址
32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...
- 32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式
32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式 一丶RadAsm的配置和使用 用了怎么长时间的命令行方式,我们发现了几个问题 1.没有代码提醒功能 2.编写代码很慢,记不住各 ...
- x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式
目录 x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式 一丶x86指令复习. 1.1什么是x86指令. 1.2 x86与x64下的通用寄存器 1.3 OpCode 1.4 7种寻址方式 二 ...
- 20145314郑凯杰《信息安全系统设计基础》GDB调试32位汇编堆栈分析
20145314郑凯杰<信息安全系统设计基础>GDB调试32位汇编堆栈分析 本篇博客将对第五周博客中的GDB调试32位汇编堆栈进行分析 首先放上以前环境配置的图: 图1: 测试代码: #i ...
- 64位gcc编译32位汇编
由于使用as和ld来编译链接汇编程序,在使用C库的时候比较麻烦,需要输入比较多的指令,所以使用gcc进行编译链接.由于书中内容是32位汇编程序,但是机器使用的是64位操作系统,自带的gcc也是64位的 ...
- 【asm】64位编译32位汇编需要注意的
汇编语言在32位和64位下有区别 32位的汇编在代码前增加.code32 as可以通过--32指定生成32位汇编 在64位系统下ld链接生成32位程序: ld: i386 archi ...
随机推荐
- div标签清除float浮动样式方法
方法一. 这个方法来源于positioniseverything ,通过after伪类实现,完全兼容当前主流浏览器. 1 <style type="text/css"> ...
- Linux(2)文件和权限
用户目录 位于/home/user, 称为用户目录或家目录, 表示方法: /home/user ~ 相对路径和绝对路径 绝对路径 从 / 目录开始描述的路径外绝对路径 cd /home cd /usr ...
- Python中的可变对象和不可变对象
Python中的可变对象和不可变对象 什么是可变/不可变对象 不可变对象,该对象所指向的内存中的值不能被改变.当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一 ...
- Python爬虫初学(二)—— 爬百度贴吧
Python爬虫初学(二)-- 爬百度贴吧 昨天初步接触了爬虫,实现了爬取网络段子并逐条阅读等功能,详见Python爬虫初学(一). 今天准备对百度贴吧下手了,嘿嘿.依然是跟着这个博客学习的,这次仿照 ...
- 计算机四级网络工程师--《操作系统(Operating System)》重点内容学习
开篇语 今天开始看<操作系统>,没办法,计算机网络技术还算有点底子.至于操作系统要不是以前看过一些这方面的书籍,以及上学期学了单片机工作原理,我估计我真的是懵逼的!所幸,在网上找的233网 ...
- 一个普通的 Zepto 源码分析(二) - ajax 模块
一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...
- Apache崩掉:为进程配置合适的线程数
放假以来,服务器Apache二次崩掉了,不能再拖了,找bug解决: 崩掉的具体状况是,服务器出现弹框显示:Apache停止工作: 顺手关掉这个可恶的小弹框,世界就清静了,服务器正常运行: 具体问题: ...
- 关于error C2872: 'LONG_PTR' : ambiguous symbol
今天用VS2010创建了一个add-in工程,使用常量INVALID_HANDLE_VALUE时,编译器就提示如下错误: error C2872: 'LONG_PTR' : ambiguous sym ...
- Java 图片处理解决方案:ImageMagick 快速入门
一.ImageMagick介绍 ImageMagick是一个免费的创建.编辑.合成图片的软件,可以实现图片切割.颜色替换.图片缩略图.图片水印等各种效果.ImageMagick是免费开源软件,支持大多 ...
- 一个基于ES6+webpack的vue小demo
上一篇文章<一个基于ES5的vue小demo>我们讲了如何用ES5,vue-router做一个小demo,接下来我们来把它变成基于ES6+webpack的demo. 一.环境搭建及代码转换 ...