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库函数的更多相关文章

  1. 32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用

    32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用 一丶32位(x86也称为80386)与8086(16位)汇编的区别 1.寄存器的改变 AX 变为 EAX  可以这样想,16位通 ...

  2. 内核开发知识第二讲,编写Kerner 程序中注意的问题.

    一丶函数多线程的安全问题 什么是函数多线程安全. 简单来说就是 ,一个函数在调用过程中.还没有返回的时候.再次被其他线程调用了.但是函数执行的结果是可靠的.就可以了说这个函数是安全的. 比如我们在用户 ...

  3. 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)

    32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...

  4. 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址

    32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...

  5. 32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式

    32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式 一丶RadAsm的配置和使用 用了怎么长时间的命令行方式,我们发现了几个问题 1.没有代码提醒功能 2.编写代码很慢,记不住各 ...

  6. x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式

    目录 x64汇编第二讲,复习x86汇编指令格式,学习x64指令格式 一丶x86指令复习. 1.1什么是x86指令. 1.2 x86与x64下的通用寄存器 1.3 OpCode 1.4 7种寻址方式 二 ...

  7. 20145314郑凯杰《信息安全系统设计基础》GDB调试32位汇编堆栈分析

    20145314郑凯杰<信息安全系统设计基础>GDB调试32位汇编堆栈分析 本篇博客将对第五周博客中的GDB调试32位汇编堆栈进行分析 首先放上以前环境配置的图: 图1: 测试代码: #i ...

  8. 64位gcc编译32位汇编

    由于使用as和ld来编译链接汇编程序,在使用C库的时候比较麻烦,需要输入比较多的指令,所以使用gcc进行编译链接.由于书中内容是32位汇编程序,但是机器使用的是64位操作系统,自带的gcc也是64位的 ...

  9. 【asm】64位编译32位汇编需要注意的

    汇编语言在32位和64位下有区别    32位的汇编在代码前增加.code32    as可以通过--32指定生成32位汇编 在64位系统下ld链接生成32位程序:    ld: i386 archi ...

随机推荐

  1. C++ STL Binary search详解

    一.解释 以前遇到二分的题目都是手动实现二分,不得不说错误比较多,关于返回值,关于区间的左闭右开等很容易出错,最近做题发现直接使用STL中的二分函数方便快捷还不会出错,不过对于没有接触过的同学,二分函 ...

  2. Sublime text 3搭建Python开发环境

    前辈们说的已经很多了,但是自己依旧会出现各种问题,写篇日志记录这次的搭建经验. 1.安装python,我用的是python3.5,可以上官网下载 2.安装Sublime text 3,可以上官网下载 ...

  3. Android service 服务的应用之电话监听器以及短信监听器

    首先建立一个项目工程文件,如下图所示:

  4. com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column 'goodsName' cannot be null

    com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column 'goodsName' cannot be n ...

  5. [NOIP2015] 斗地主 大爆搜

    考试的时候想了半天,实在是想不到解决的办法,感觉只能暴力..然后暴力也懒得打了,小数据模拟骗30分hhh 然而正解真的是暴力..大爆搜.. 然后我的内心拒绝改这道题(TAT) 不过在wcx大佬的帮助下 ...

  6. [Java] Java读取Word文档

    前言 最近需要做一些NLP 方面的工作,使用的是Java,在此总结一下使用Java读取Word(.doc)格式文件的方法. Apache基金会非常厉害,开源工具包POI就可以处理微软家的文档,甚至包括 ...

  7. [算法题] Add Two Numbers

    题目内容 题目来源:LeetCode You are given two non-empty linked lists representing two non-negative integers. ...

  8. URL的概念

      URL(Uniform Resource Locator)直接翻译为"统一资源定位符" URL的作用:描述一个在网络上的资源   schema://host[:port#]/path/.../[? ...

  9. Linux - 简明Shell编程12 - 定制输出(ColorOutput)

    脚本地址 https://github.com/anliven/L-Shell/tree/master/Shell-Basics 示例脚本及注释 #!/bin/bash echo -e "\ ...

  10. JS正则密码复杂度校验之:至少有多种字符中的其中几种

    概述 续接上文的密码校验要求: 这个需求有两个难点,一,是如何使用正则匹配所有半角英文标点符号,二,是如何验证密码段中在要求的四种(大写字母,小写字母,数字,标点符号)类型中至少存在三种. 第一个难点 ...