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. 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)

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

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

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

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

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

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

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

  6. 64位gcc编译32位汇编

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

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

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

  8. Winform DevExpress控件库(二) 使用SplashScreenManager控件定制程序加载页面

    SplashScreenManager控件:主要作用是显示在进行耗时操作时的等待界面: 位于 工具箱 -> Navigation & Layout(导航栏与布局类控件) 目录下: 在工具 ...

  9. Android Phonebook编写联系人UI加载及联系人保存流程(一)

    2014-01-06 17:05:11 将百度空间里的东西移过来. 本文适合ROM定制做Phonebook的童鞋看,其他人飘过即可- Phonebook添加/编辑联系人UI加载及保存联系人流程,是一系 ...

随机推荐

  1. socket.io简单入门(一.实现简单的图表推送)

    引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...

  2. Oracle 使用SqlPlus管理

    Oracle 使用SqlPlus 安装,一键安装,很简单.安装过程,一定要记住密码 一.登陆sqlplus 连接本地服务器,可以直接,打开cmd: 可以直接不用登陆,如果登陆需要输入用户名.密码. s ...

  3. Android App 开发技能图谱

    操作系统 Windows/MacOSX/Linux 编程语言 Java HTML/JS (Hybrid/Web App) C/C++ (NDK) SQL (DB) Kotlin 开发工具 IDE An ...

  4. Winform程序以Icon的形式显示在任务栏右下角

    Form最小化是指整个Form都缩小到任务栏上,但是是以Form的标题栏形式显示的, 若是想让Form以Icon的形式显示在任务栏右下角,则需要给Form添加一个NotifyIcon控件, 在使窗体最 ...

  5. 【CSharp】C#开发ActiveX插件

    这几天Web项目中需要用到ActiveX插件(PS:听说这个是好久好久的东西了...),由于项目中需要调用本地资源所以只能研究研究这位老兄了. 先说说自己学习他的经历,开始的时候是用百度引擎检索自己所 ...

  6. 学习笔记——Maven实战(五)自动化Web应用集成测试

    自动化集成测试的角色 本专栏的上一篇文章讲述了Maven与持续集成的一些关系及具体实践,我们都知道,自动化测试是持续集成必不可少的一部分,基本上,没有自动化测试的持续集成,都很难称之为真正的持续集成. ...

  7. Java for LeetCode 064 Minimum Path Sum

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  8. file operation note

    从HLE回来,大家拍了2499张照片,分放在N个文件夹下,下面的python将下层目录中文件移动到上层 import os,shutil dst=os.getcwd()+os.sep for path ...

  9. 初识IOS

    编译环境: ssh cloud@10.0.4.148  mx-cloud 1.关于ARM架构 IPHONE上的ARM-CPU架构在不断的进化过程中,目前情况如下: ARMv8 / ARM64 = iP ...

  10. 你听说过PHP 的面向方面编程吗?

    面向方面编程(AOP)对于PHP来说是一个新的概念.现在PHP对于 AOP 并没有官方支持,但有很多扩展和库实现了这个特性.本课中,我们将使用 Go! PHP library 来学习 PHP 如何进行 ...