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拷贝到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拷贝到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文件中,所以直接在对应的地址找到代码的执行位置执行即可.

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

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

  7. 64位gcc编译32位汇编

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

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

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

  9. GDB调试32位汇编堆栈分析

    GDB调试32位汇编堆栈分析 测试源代码 #include <stdio.h> int g(int x){ return x+5; } int f(int x){ return g(x)+ ...

随机推荐

  1. java异常处理的设计

    有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程序时,如何设计异常处理的代码,如何时抛异常,捕获到了怎么处理,而不是讲 ...

  2. 无废话ExtJs 入门教程二[Hello World]

    无废话ExtJs 入门教程二[Hello World] extjs技术交流,欢迎加群(201926085) 我们在学校里学习任何一门语言都是从"Hello World"开始,这里我 ...

  3. 聊聊CSS postproccessors

      阿里妈妈 @一丝 准备发布其CSSGrace,即CSS后处理插件,于是顺便聊聊CSS postprocessors. 从Rework说起 Rework是TJ大神开发的CSS预处理框架.但为什么会出 ...

  4. [CareerCup] 9.4 Subsets 子集合

    9.4 Write a method to return all subsets of a set. LeetCode上的原题,请参见我之前的博客Subsets 子集合和Subsets II 子集合之 ...

  5. [SQL]SQL语言入门级教材_SQL语言快速入门(五)

    SQL语言快速入门(一) SQL是英文Structured Query Language的缩写,意思为结构化查询语言. SQL语言的主要功能就是同各种数据库建立联系,进行沟通.按照ANSI(美国国家标 ...

  6. XAML(4) - 标记扩展

    在为元素设置值时, 可以直接设置值, 但有时标记扩展非常有帮助.标记扩展包含花括号,其后是定义了标记扩展类型的字符串标志. 下面是一个Static Resource标记扩展: <Button N ...

  7. JQuery select控件的相关操作

    JQuery获取和设置Select选项方法汇总如下: 获取select 先看看下面代码: $("#select_id").change(function(){//code...}) ...

  8. 兔子--Android中的五大布局

    LinearLayout:被称为线性布局,分为水平和垂直,设置的垂直或水平的属性值,来排列全部的子元素.全部的子元素都被堆放在其他元素之后,因此一个垂直列表的每一行仅仅会有一个元素,而无论他们有多宽, ...

  9. android studio导入矢量svg图标技巧

    1.在android studio中打开File-->Settings-->Plugins,在Plugins中输入SVG2VectorDrawable搜索插件,并安装. 2.安装完成重启a ...

  10. 【算法系列学习】Dijkstra算法变形 [kuangbin带你飞]专题四 最短路练习

    https://vjudge.net/contest/66569#problem/B 类试题:noip2013 货物运输 POJ 1797 Heavy Transportation 方法一:Dijks ...