hao对《琢石成器》的笔记(30)
-
第20页 背景知识
这本书也是很早就读了。 = =! 我不用win32 ASM ,就当是《windows核心编程》的汇编版,虽然《windows核心编程》讲得更细,更广,但是这两本书我认为各有各的优点吧。至少我第一次学习逆向有收获的是看这本书。很多小知识也是。 放上来主要是为了让我的读书笔记不空洞,算是记录自己的人生学习经历了。等书丢失了,回来也可以找笔记看关键点(靠近本质的)。 1.80x86处理器的工作模式
80386处理器有3种工作模式:实模式,保护模式和虚拟86模式。实模式和虚拟86模式是为了和8086处理器兼容而设置的。保护模式是80386处理器的工作模式,在此方式下,处理器可以寻址4GB的地址空间。同时,保护模式也提供了处理器先进的多任务,内存分页管理和优先级保护等机制。 引自 背景知识 1.1实模式
80386处理器被复位或在加电时以实模式启动。各寄存器以实模式初始化,寻址方式和8086一样,由段寄存器的内容乘以16当作基址,加上段内偏移最终形成物理地址。寻址空间为1MB。32位寄存器只使用了低20位 在实模式下,所有的段都是可读写,可执行的。实模式下,不支持优先级,所有指令相当于工作在ring 0。 引自 背景知识 1.2保护模式
80386在保护模式下,发挥最大威力,所有功能都是可用的。所有32根地址线都可供寻址,物理寻址空间高达4GB。 保护模式下,支持多任务,可以依靠仅在一条指令中实现任务切换。任务环境的保护工作由处理器自动完成。 保护模式下,支持优先级机制,不同的程序可以运行在不同的优先级上。优先级分四个级别(ring0~ring3),ring0为最高优先级,应用程序一般运行在ring3. 引自 背景知识 1.3虚拟86模式
虚拟86模式是为了在保护模式下执行8086程序而设置的。虚拟86模式是以任务形式在保护模式下执行的。所以支持任务切换和内存分页。 引自 背景知识 2.windows内存管理
在实模式下,段地址被放在16位的段寄存器中,然后在指令中用16位的偏移地址寻址。换算公式:段地址*16+16位偏移得到物理地址。 当处理器工作在保护模式和虚拟86模式下,32位地址线可以用,访问4G大的内存。段地址+偏移的计算方法显然无法覆盖这么大的范围,但因为8086的限制不存在了,所有通用寄存器为32位,2^32=4G。所以用任何一个通用寄存器间接寻址,不必分段就已经可以访问到所有内存地址。 在保护模式下,段寄存器就更有用了。在定义地址空间的安全属性上派上了用场。 段寄存器是16位的,无法放下保护模式下64位的段描述符。所以就把所有段的段描述符(Segment Descriptor)放在指定位置,组成一个段描述符表(Descriptor Table)。而段寄存器中的16位用来做索引信息,指定这个段的属性用段描述符表中的第几个描述符来表示。 段描述符表的位置:80386中引入两个新的寄存器来管理段描述符表。一个是48bits的全局描述符表寄存器GDTR,一个是16bits的局部描述符表寄存器LDTR。GDTR指向GDT。LDTR指向LDT。 GDT包含系统所有任务都可用的段描述符(OS所使用的代码段,数据段,堆栈段。以及各任务的LDT段。)。GDT只有一个。 每个任务都有一个独立的LDT。它包含每个任务私有的代码段,数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门,调用门描述符。 和GDTR直接指向内存地址不同,LDTR和CS,DS等段选择寄存器一样只存放索引值。随着任务的切换,只要改变LDTR的值,系统当前的LDT也随之切换。 引自 背景知识 GDTR,LDTR GDT,LDT 和selector的关系3.分页机制
在保护模式下,段选择器+偏移地址转换后形成“线性地址”(虚拟地址),而不是“物理地址”。 引自 背景知识 分页机制有我笔记,改天我贴上来。
页表规定的不仅仅是地址映射,同时还规定了页的访问属性,是否可读,可写。利用这个机制可以在硬件层次上支持虚拟内存的实现。 引自 背景知识 内存地址转换表4.windows的内存安排
windows的内存安排 -
第22页 准备编程环境
Win32 PE文件的开发过程 -
第45页 准备编程环境
其实直接用RadASM就可以了。书上介绍太麻烦。不要makefile什么的了。
.rc是资源脚本,可以编辑。 引自 准备编程环境 -
第88页 使用MASM
使用MASM,其实就是它的文法,下面我归纳总结一下: Win32汇编,程序的基本构造跟DOS下差不太多。 下面是个Hello World的程序: .386 .model flat, stdcall option casemap:none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;include文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data szCaption db 'A MessageBox !',0 szText db 'Hello ,World ! ',0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;代码段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code start: invoke MessageBox, NULL, offset szText,\ offset szCaption, MB_OK invoke ExitProcess, NULL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start .386是伪指令,用来告诉编译器在本程序中使用的指令集。在80386以及以上的处理器中,使用这句是必不可少的。(注意,这不是纯汇编,是MASM汇编,有文法的。) 如果后面带p(例如:.386p)就表示程序可以使用特权指令。如果我们要写VxD等驱动程序,就有可能用到类似指令。 .model用来定义程序的工作模式。但对于win32应用程序来说只有一种模式,就是flat(平坦模式),因为每个进程运行在独立的4GB内存空间中。 如果定义了平坦模式,MASM就自动为各种段寄存器做了如下定义: ASSUME cs:flat, ds:flat, ss:flat, es:flat, fs:error, gs:error 指令格式: .model 内存模式 [, 语言模式] [,其他模式] win32汇编中有各种段, .code, .const, .data .data? 与DOS不同,它没有堆栈段,因为系统会为程序分配一个向低址扩展的段作为堆栈段。这些段绝对不是DOS汇编中那种意义的段,而是内存的“分段”。所有的“分段”合起来,包括系统所使用的地址空间,组成了4GB空间。4GB空间被分页机制管理,每页4KB,每页都有自己的属性,“分段”的概念实际上就是把不同类型的数据或代码归类,再放到不同属性的内存页。必须注意与DOS汇编中“段”的不同含义。 数据段: .data .data?和.const 的数据,分别把数据放在PE文件不同的节区(section)(详细参考PE文件结构)。 .data可读可写。已经初始化,放在PE文件的_DATA节区,类似与C中static变量和全局变量,会增大PE文件大小。(.exe文件)。 .data?可读可写。未定义。存放在_BBS节区。编译出来不会增加PE文件大小。编译器只为它保留大小信息,不会浪费磁盘空间。 代码段: .code 所有指令必须写在代码段中,存放在PE文件的_TEXT节区。.code段不可写。代码段的属性是由PE文件头部中的属性位决定的。可以修改。ring0程序直接有权利修改代码段。 程序的结束和入口: 在C语言中不必显式指定程序由哪里开始执行,编译器已经约定从main函数执行了。在汇编里,程序员可以指定从代码段的任何一个地方开始执行。 end [开始地址] 调用win32 API: DOS下调用(显式)系统功能是中断,而到了win32下则不是了(实际上在内核态下还是调用了int 2e,这个先不考虑),win32系统中的功能模块则是放在dll文件中的,dll文件也是PE文件结构。 kernel32.dll -----系统服务功能。包括内存管理,任务管理和动态链接 GDI32.dll-------图形设备接口。利用VGA与DRV之类的显示设备驱动程序完成显示文本等功能。 USER32.dll------用户接口服务。建立窗口和传送消息。 不同的dll提供不同的系统功能,所有的这些dll组成了win32编程环境。 调用API: 因为MASM为简化开发,用了invoke伪指令,来简化函数调用,实际上完成了push等参数入栈操作和平衡堆栈操作。 API的返回值一般放在eax中。只有dword一种类型。 字符串相关的API有W和A型的,MessageBoxW和MessageBoxA,前者处理Unicode,后者处理ANSI。Unicode占2bytes,ANSI占1bytes。所以为了让程序更有移植性,一般不显式指定W或者A。直接: if UNICODE MessageBox equ <MessageBoxW> else MessageBox equ <MessageBoxA> include [XX.inc] .inc为所有DLL函数生命列表,每个dll对应[dll名.inc]文件。 includelib 在win32汇编中,程序必须知道API在哪,否则必须搜索系统所有dll,并且无法处理不同dll中的同名函数,所以必须有个文件来包括dll库正确的定位信息,这就是lib文件(导入库)。DOS下的C语言函数库也是lib文件(称静态库),因为函数实现都存在lib中了。缺点就是每个可执行文件都包括了相同函数的代码,浪费磁盘空间,在执行的时候也浪费内存。
lib文件只是告诉链接器在链接的时候到指定库(dll)中去找API函数的位置信息而已。 引自 使用MASM MASM定义全局和局部变量: 全局: 变量名 类型 初始值1,初始值2,... 变量名 类型 重复数量 dup (初始值1,初始值2,...) 局部: local 变量名[[重复数量]]:[类型] local @var:dword, @var2:word,@var3:byte
在80386处理器中,以dowrd为界对齐时对内存访问最快。(所以不要轻易去数结构体的大小) 引自 使用MASM 子程序定义方式: 子程序名 proc [距离] [语言类型] [可视区域] [USES 寄存器列表][,参数:类型]...[VARARG] local 局部变量列表 指令 子程序名 endp 分支语句: .if 条件表达式1 指令 [.else if 条件表达式2] 指令 ..... [.else ] 指令 .endif 循环语句: .while 条件测试表达式 指令 [.break [.if 退出条件]] [.continue] .endw 类似C中的wile(){} .reapt 指令 [.break [.if 退出条件]] [.continue] .until 条件测试表达式 类似C语言中的do{}wile() 代码组织: 1.使用频繁的部分把它们封装成黑匣子,尽量把全局变量设置成局部变量。 2.子程序规模尽量小。不应该太大,行数尽量在几百行以内。 3.尽量从以前的代码中拷贝相似的代码,把子程序封装成黑匣子,随着积累,开发程序是很快的。
-
第97页 第一个窗口程序
窗口运行的过程机制 -
第99页 第一个窗口程序
1.模块和句柄
一个模块代表的是一个运行中的.exe文件或dll文件,用来代表这个文件中所有的代码和资源,磁盘上的文件不是模块,装入内存才叫模块。一个应用程序调用API,用到dll时,dll装入内存,就产生了不同的模块,为了区分地址空间中的不同模块,每个模块都有一个唯一的模块句柄来标识。 在win32中,模块句柄在“数值”上等于程序装入内存的起始地址(基地址),用GetModelHandle获得。 hInstance(实例句柄)概念源于win16. 引自 第一个窗口程序 句柄只是一个数值而已,对于程序员无意义,(其实是句柄表的索引,引用内核对象的),用来表示各种资源的编号而已。 引自 第一个窗口程序 -
第120页 使用资源
资源文件的”源文件“是以.rc为扩展名的脚本文件,由资源编译器rc.exe编译成res为扩展名的二进制文件,最后链接的时候由link.exe链接进PE文件。 引自 使用资源 -
第144页 使用资源
位图(bitmap)是windows储存图像的方式。使用位图的优越之处就是操作速度快。 windowsGDI中广泛支持的是bmp文件,其他格式jpg与tif不能直接用,要使用这些文件必须转换到位图格式才能使用。 引自 使用资源 -
第146页 使用资源
大部分工作在主窗口完成,和用户互交一般是对话框(有些功能没有必要全部放在主窗口界面上)。 引自 使用资源 普通窗口和对话框的区别:
普通窗口RegisterClass,CreateWindow,ShowWindow,UpdateWindow,消息循环函数(GetMessage,TransalteMessage,DispatchMessage),窗口过程回调。 非模态对话框CreateDialogParam,然后(非内建)消息循环,然后到内建窗口过程WM_CREATE 到WM_INITDIALOG,WM_CLOSE,WM_DESTROY 引自 使用资源 TIPS:内建消息循环就是windows干的事情,就是不是我们干的,
模态对话框DialogBoxParam,然后内建消息循环,然后到内建窗口过程WM_CREATE 到WM_INITDIALOG,WM_CLOSE,WM_DESTROY 引自 使用资源 -
第242页 图形操作
windows为每个窗口维护一个”绘图信息结构“。 GDI接口把程序和硬件分离开来。 程序设置一个周期为100ms的定时器,windows会每隔100ms调用TimeProc子程序。 ”设备环境“只是一个环境,是设备属性的一组定义,程序输出的图形数据透过”设备环境“被定向到具体设备上,”设备环境“本身不存储这些数据。 引自 图形操作
hao的其他笔记 · · · · · · ( 全部427条 )
- P2P网络技术原理与C++开发案例
- 5
- 大话移动通信
- 1
- 图解网络硬件
- 1
- 写给大家看的C++书
- 1
- Orange'S
- 1
- 虚拟机
- 1
- 大规模C++程序设计
- 10
- Linux Shell脚本攻略
- 3
- HTTP权威指南
- 3
- C++ API设计
- 8
- C++语言的设计和演化
- 5
- 构建嵌入式LINUX系统
- 3
- 七周七语言
- 15
- 链接器和加载器
- 1
- Windows网络与通信程序设计
- 2
- Windows核心编程(第5版)
- 16
- C++GUI Qt4编程
- 3
- 图解TCP/IP (第5版)
- 12
- Python学习手册
- 5
- 编写可读代码的艺术
- 14
- 你一定爱读的极简欧洲史
- 2
- 短码之美
- 1
- 程序员的自我修养
- 17
- 美国纽约摄影学院摄影教材(上)
- 2
- Win32多线程程序设计
- 8
- 竹林蹊径
- 4
- 鸟哥的Linux私房菜
- 4
- Linux/Unix设计思想
- 6
- 程序设计语言的形式语义
- 1
- Windows驱动开发技术详解
- 9
- 你必须知道的495个C语言问题
- 5
- Windows内核原理与实现
- 44
- PCI Express 体系结构导读
- 3
- 程序员的数学
- 5
- 深入浅出 MFC 第二版
- 2
- 并发的艺术
- 4
- 群和它的图象表示
- 1
- C语言接口与实现
- 1
- 致命元素
- 2
- 深入解析Windows操作系统
- 51
- Linux C编程一站式学习
- 13
- 淘宝技术这十年
- 1
- 高效程序的奥秘
- 1
- 花田半亩
- 1
- 于丹:重温最美古诗词
- 1
- 诛仙8(大结局)
- 1
- 深入理解计算机系统(原书第2版)
- 9
- C和指针
- 9
- 寒江独钓
- 5
- Windows程序设计
- 9
- 数据结构与算法分析
- 11
- 80X86汇编语言程序设计教程
- 3
- 数学分析教程
- 1
- 操作系统概念(第六版)
- 12
- 算法竞赛入门经典
- 10
- C++反汇编与逆向分析技术揭秘
- 12