必要性

  • 纯汇编语言开发
  • 高级语言内联汇编
  • Windows内核编程
  • 逆向分析

汇编语言种类

  • x86汇编语言
  • x64汇编语言
  • 伪指令
  • 高级数据表示
  • win32汇编入门
  • 内联汇编

硬编码

程序是由数据和指令构成,在底层都是二进制(通常以十六进制查看),本质上并无太大区别。CPU 仅通过指令指针(如 EIP/RIP)指向的内存地址来将其解析为指令还是数据。

  • 概念定义:在逆向分析中,“硬编码”通常指代机器码(Machine Code)或操作码(Opcode)。它是 CPU 硬件能够直接识别、解码并执行的底层指令字节。
  • 与汇编的关系:汇编语言是硬编码的“助记符”。人读汇编,机器读硬编码。两者基本是一一对应的关系(经过汇编器编译)。
    • 例如:汇编指令 NOP 对应的硬编码是 90;INT 3(断点)对应的硬编码是 CC。
  • 在逆向工程中的应用:
    • Patch(打补丁/爆破):通过修改可执行文件中的硬编码来改变程序逻辑。例如将条件跳转 JZ(常对应硬编码 74)修改为强制跳转 JMP(EB)或用 NOP(90)填充掉某段验证代码。
    • 特征码搜索:杀毒软件、游戏反作弊或外挂开发中,常通过定位一段特定的硬编码序列(Signature)来寻找关键函数或恶意代码。
    • Shellcode 开发:在漏洞利用(Pwn)时,通常需要手动构造一段去除了坏字符(如 00)的硬编码字节流注入到内存中让 CPU 执行。

指令编码的结构

根据 x86/x64 架构标准,一条完整的机器指令由多个字段组成,长度是可变的,但最大总长度不超过 15 Bytes。参考 image_beb032.png 中的示意图,其从左到右的标准结构拆解如下:

  1. Prefixes (指令前缀)
    • 可选,0~4 Bytes
    • 用于修改指令的默认执行行为。
    • Legacy Prefix: 包括段覆盖(如 FS:)、操作数大小覆盖(如 66)、地址大小覆盖(如 67)、LOCK前缀(F0)或重复前缀(REP 系列)。
    • REX Prefix: 仅在 64 位 (x64) 模式下存在,用于访问新增的 8 个通用寄存器 (R8-R15) 或是强制使用 64 位操作数大小。
  2. Opcode (操作码) 必有,1~3 Bytes
    • 指令的核心,决定了 CPU 具体要执行什么动作(例如 MOV、ADD、JMP)。
  3. ModR/M (寻址方式/寄存器)
    • 可选,1 Byte
    • 如果指令需要用到内存寻址或涉及寄存器操作,通常会有这个字节。它由三部分按位(Bit)组成:
      • Mod (2 bits) + Reg/Opcode (3 bits) + R/M (3 bits)
  4. SIB (比例-变址-基址)
    • 可选,1 Byt
    • 当 ModR/M 字段不足以表达复杂的内存寻址时(例如数组寻址 [Base + Index * Scale + Disp]),会引入 SIB 字节。它也由三部分组成:
      • Scale (比例,如 1,2,4,8,占 2 bits) + Index (变址寄存器,占 3 bits) + Base (基址寄存器,占 3 bits)
  5. Displacement (位移/偏移量)
    • 可选,1, 2, 4 或 8 Bytes
    • 内存寻址时所用到的地址偏移值。
  6. Immediate (立即数)
    • 可选,1, 2, 4 或 8 Bytes
    • 直接硬编码在指令中的常量数据(例如指令 MOV EAX, 0x12345678 中的 0x12345678 就是立即数)。

指令前缀

指令前缀是可选的,最多可包含 4 个字节(每组最多选一个),主要用于修改指令的默认执行行为。按功能分组如下:

  1. LOCK 和 REPEAT 前缀 (LOCK & REPEAT)
    • F0:LOCK。锁总线前缀。用于多核环境下确保接下来的内存操作是“原子操作”,防止被其他线程打断(常见于并发同步汇编指令,如 lock xadd)。
    • F2:REPNE / REPNZ。当不相等或非零时,重复执行后面的字符串指令。
    • F3:REP / REPZ。当相等或为零时,重复执行后面的字符串指令(常配合 movsd、stosb 等指令用于内存拷贝或初始化)。
  2. 段前缀指令 (Segment Override)
    • 用于覆盖指令默认使用的段寄存器。在现代操作系统(如 Windows)的平坦内存模型中,CS/SS/DS/ES 的前缀基本不再起实际地址隔离作用,但 FS 和 GS 依然极其重要。
    • 2E:CS (代码段)
    • 36:SS (堆栈段
    • 3E:DS (数据段)
    • 26:ES (附加数据段)
    • 64:FS。在 32 位逆向和免杀中非常关键。 32 位 Windows 中,FS 寄存器指向 TEB (线程环境块)。恶意代码常通过 FS:[0x30] 获取 PEB,进而动态遍历导出表寻找 API 地址,实现无导入表运行(特征隐藏)。
    • 65:GS。在 64 位 Windows 环境中接替了 FS 的作用(例如 GS:[0x60] 指向 64 位的 PEB)。
  3. 操作数宽度前缀指令 (Operand-Size Override)
    • 66:用于切换默认的操作数大小。例如,在 32 位模式下,寄存器默认使用 32 位(如 EAX)。如果指令机器码前加了 66 前缀,CPU 就会将其降级作为 16 位操作数处理(如 AX)。
  4. 地址宽度前缀指令 (Address-Size Override)
    • 67:用于切换默认的内存寻址大小。例如,在 32 位环境下强制使用 16 位地址模式寻址,或者在 64 位环境下强制使用 32 位地址。

环境配置

VC→win32应用程序向导(选择空项目)→属性→高级→入口点(main)→生成依赖项(选择masm)→添加汇编程(asm后缀)

扩展:asmdude

代码基本套路

.586  ;指令集
.MODEL flat,stdcall ;内存模式、语言模式、其他模式
includelib user32.lib ;调用静态库
includelib kernel32.lib 
ExitProcess PROTO,dwExitCode:DWORD ;伪指令
MessageBoxA PROTO hWnd:DWORD,lpText:BYTE,lpCaption:BYTE,uType:DWORD
;option
;option casemap:none,是否对大小写敏感
.data
;.data:数据,定义初始值
;.data?:未初始化数据段
;.const:常量数据段
;.code:代码段
;.stack:堆栈段,现在不需要,系统会自动调用
Number DWORD 0
text db "shellcode",0
.code
main proc
	mov eax,5
	mov ebx,6
	add eax,Number
	push 0
	push offset text
	push offset text
	push 0
	call MessageBoxA
	add esp,16
	call ExitProcess
main ENDP
END main.586  ;指令集
.MODEL flat,stdcall ;内存模式、语言模式、其他模式
includelib user32.lib ;调用静态库
includelib kernel32.lib 
ExitProcess PROTO,dwExitCode:DWORD ;伪指令
MessageBoxA PROTO hWnd:DWORD,lpText:BYTE,lpCaption:BYTE,uType:DWORD
;option
;option casemap:none,是否对大小写敏感
.data
;.data:数据,定义初始值
;.data?:未初始化数据段
;.const:常量数据段
;.code:代码段
;.stack:堆栈段,现在不需要,系统会自动调用
Number DWORD 0
text db "shellcode",0
.code
main proc
	mov eax,5
	mov ebx,6
	add eax,Number
	push 0
	push offset text
	push offset text
	push 0
	call MessageBoxA
	add esp,16
	call ExitProcess
main ENDP
END main

汇编使用:注释

汇编函数没有main,需要指定主函数

硬件知识

CPU的内部组成

  • 运算器进行信息处理
  • 寄存器进行信息存储
  • 控制器控制各种器件进行工作
  • 内部总线连接各种器件,在它们之间进行数据的传送

寄存器是程序员可以用指令读写的部件。程序员通过改变各种寄存器的内容实现对CPU的控制

image.png

通用寄存器

8086/8088 CPU寄存器组

包括4个16位数据寄存器,两个16位指针寄存器,,两个16位变址寄存器,一个16位指令执政,4个16位段寄存器,,1个16位标志寄存器,一共十四个16位寄存器 image.png

image.png

通用寄存器

数据寄存器

4个16位数据寄存器:AX、BX、CX、DX;主要用来保存操作数或运算结果等信息,它们的存在节省了为读取操作数所需占用总线和访问存储器的时间

控制寄存器

标志寄存器

image.png 8086/8088 CPU中有一个16位的标志寄存器,包含了9个标志,主要用于反映处理器的状态和运算结果的某些特征。各标志在标志寄存器中的位置如下所示:

image.png

有些指令的执行会影响部分标志,而有些指令的执行不会影响标志,反过来,有些指令的执行后某些标志的影响,有些指令不受标志的影响。编写程序时,需要充分注意指令与标志的关系。有些指令的执行会影响部分标志,而有些指令的执行不会影响标志,反过来,有些指令的执行后某些标志的影响,有些指令不受标志的影响。编写程序时,需要充分注意指令与标志的关系。

相关基础知识

度量单位

基本数据度量单位: 1BYTE=8BIT WORD=2BYTE=16BIT DWORD=4BYPE=32BIT QWORD=8BYPE=64BIT

数据存储度量单位 1KB=1024BYPE=8192BIT 1MB=1024KB 1GB=1024MB 1TB=1024GB

取值范围 BYPE=有符号:-128至127|无符号:0至255 WORD=有符号:-32768至32767|无符号:0至65535 DWORD=有符号:-2147483648至2147483647|无符号:0-4294967295 QWORD=有符号:-9223372036854775808至9223372036854775808

X86处理架构基本概念

基本微机设计

1d12bf9c76e3429e957c04113e948ce6.png

时钟周期

v2-464417834617a4920095c2ec93e5533d_1440w.jpg 时钟周期是处理器执行动作的最小时间单位。处理器的主频越高,其时钟周期就越短,执行操作的速度就越快。但是主频的提高也会带来其它问题,比如功耗和散热,因此现代CPU会权衡性能和功耗这两方面的影响;同时主频也做不到无限提高,因为电流的传输也是需要点时间的。

在计算机中,时钟周期提供了一个统一的时间基准,使得不同的硬件组件和指令能够按照同样的时间节奏进行操作。各个组件和指令可以根据时钟信号的跳变来确定何时开始和结束各自的操作,从而实现同步和协调。

加载执行程序

  1. 磁盘寻找文件
  2. 访问文件信息
  3. 加载程序至内存
  4. 执行指令,分配Process ID
  5. 进程自动运行
  6. 结束后从内存移除

操作模式

保护模式

保护模式是Intel 80286及后续x86系列处理器的核心运行模式,随80286处理器首次引入。该模式通过段级保护与特权级检查机制实现内存保护功能,支持分页系统和硬件虚拟内存管理,被Linux、FreeBSD及Windows 2.0之后版本等操作系统采用。处理器启动时默认进入实模式,需通过程序切换至保护模式

虚拟8086模式

8086 CPU 中寄存器总共为 14 个,且均为 16 位 。即 AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAG,CS,DS,SS,ES 共 14 个。而这 14 个寄存器按照一定方式又分为了通用寄存器,控制寄存器和段寄存器。

实地址模式

实模式:(即实地址访问模式)它是Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式。实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是2的20次幂(1M)的可访问内存空间(物理内存和BIOS-ROM),软件可通过这些地址直接访问BIOS程序和外围硬件。实模式下处理器没有硬件级的内存保护概念和多道任务的工作模式。但是为了向下兼容,所以80286及以后的x86系列兼容处理器仍然是开机启动时工作在实模式下。80186和早期的处理器仅有一种操作模式,就是后来我们所定义的实模式。实模式虽然能访问到1M的地址空间,但是由于BIOS的映射作用(即BIOS占用了部分空间地址资源),所以真正能使用的物理内存空间(内存条),也就是在640k到924k之间。1M地址空间组成是由16位的段地址和16位的段内偏移地址组成的。用公式表示为:物理地址=左移4位的段地址+偏移地址。

实模式寻址采用和8086相同的16位段和偏移量,最大寻址空间1MB,最大分段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。

系统管理模式

系统管理模式(SMM)是Intel处理器架构中的一种特殊模式,用于执行系统底层功能,如电源管理和安全防护。

内存管理机制

X86下每个进程都有独立的虚拟4GB的内存空间;X64每个进程理论上有虚拟的16EB空间,程序之间禁止以外访问其他程序的代码和数据

内存速度相对于寄存器数量要多很多

物理内存

image.png 32位物理内存如图

操作系统引导过程

Windows

artplayer_00_44.png

固件与主引导初始化阶段

系统上电后,根据硬件固件体系结构的不同(Legacy BIOS 或 UEFI),引导路径分为两条分支:

  • Legacy BIOS 路径:
    1. BIOS POST:系统固件执行自检(Power-On Self-Test),完成硬件基础检测。
    2. MBR (Master Boot Record):BIOS 读取磁盘第一个扇区(主引导记录),执行其中的引导代码。(0x7c00)
    3. VBR (Volume Boot Record):MBR 定位活动分区,加载卷引导记录。
    4. bootmgr:VBR 控制权移交给 Windows 启动管理器(bootmgr)。
  • UEFI 路径:
    1. EFI POST:UEFI 固件执行平台初始化与硬件检测。
    2. bootmgfw.efi:固件直接从 EFI 系统分区(ESP)加载并执行 UEFI 版启动管理器(bootmgfw.efi)。

操作系统加载器阶段

启动管理器(bootmgr / bootmgfw.efi)读取 BCD (Boot Configuration Data) 数据库,决定启动参数并转交控制权:

  • 对于 Legacy BIOS,控制权移交给 winload.exe。
  • 对于 UEFI,控制权移交给 winload.efi(注:图中标识为 winloda.efi)。

winload 的主要职责包括:

  1. 切换 CPU 进入保护模式/长模式,启用分页机制。
  2. 将内核镜像文件(ntoskrnl.exe 或 PAE 模式下的 ntkrnlpa.exe)载入内存。
  3. 加载硬件抽象层(HAL,如 halacpi.dll / Halmacpi.dll)。
  4. 加载标记为 “boot class” 的底层引导驱动程序。

内核初始化与系统级驱动载入阶段

  1. 内核接管控制权:ntoskrnl.exe 初始化内核数据结构、内存管理(MM)、进程管理(PS)及对象管理器(OB)。
  2. 驱动与服务装载:
    • 加载标记为 “system class” 的系统级驱动程序。
    • 初始化 “system class” 服务。
  3. 加载核心子系统组件:
    • 加载图形与窗口管理内核模块 Win32K.sys。
    • 映射系统预定义的已知 DLL 列表(Known DLLs,如 ntdll.dll 等)至公共内存。

会话管理与进程树构建阶段

内核完成基本初始化后,拉起第一个用户态进程 smss.exe (Session Manager Subsystem)。smss.exe 负责划分和创建独立的工作会话(Sessions):

Session 0

smss.exe 派生出 Session 0 的 smss.exe 子进程,进而创建:

  • Csrss.exe (Client/Server Runtime Subsystem):负责控制台窗口及进程/线程创建的系统子系统。
  • wininit.exe (Windows Initialization Process):负责初始化系统服务和关键安全组件,进而启动:
    • lsass.exe:本地安全身份验证服务,处理用户登录鉴权与安全策略。
    • lsm.exe:本地会话管理器(用于管理终端服务及会话状态)。
    • services.exe:服务控制管理器(SCM),负责拉起后台 Windows 服务。

Session 1

smss.exe 派生出 Session 1(或更高编号,对应登录的用户环境)的 smss.exe 子进程,进而创建:

  • Csrss.exe:Session 1 对应的 Win32 子系统进程。
  • winlogon.exe (Windows Logon Process):负责用户登录界面(SAS / Secure Attention Sequence)的呈现与交互。

用户环境与外壳加载阶段

在 Session 1 中,当用户凭据验证通过(或系统自动登录)后,winlogon.exe 将依次拉起用户态进程:

  1. userinit.exe:用户初始化进程。执行组策略、加载用户注册表配置(HKCU)、运行启动项脚本。
  2. explorer.exe:Windows 资源管理器(桌面外壳程序)。userinit.exe 启动 explorer.exe 后自身退出,系统正式呈现用户桌面,引导流程全部完成。

Bios引导原理

;======= clear screen
mov ax,0600h
mov bx,0700h
mov cx,0
mov dx,0184fh
int 10h

;======= set focus
mov ax,0100h
mov bx,0000h
mov dx,0000h
int 10h

;======= dispaly on Start Booting
mov ax,1301h
mov bx,000fh
mov dx,0000h
mov cx,10
push ax
mov ax,ds
mov es,ax
pop ax
mov bp,StartBootMessage
int 10h