为什么要写这篇教程呢?
本文章仅提供学习,切勿将其用于不法手段!
因为想要成为一名白帽黑客,汇编语言是必须要掌握的!
无论是二进制漏洞挖掘,还是逆向工程!汇编语言,都是硬性基础之一!当然,你还需要学会C语言!为什么要学会C语言呢?IDA软件 会将 二进制代码 翻译成 汇编语言 和 C语言 !
你不会汇编语言,不会C语言,想要进行逆向工程,以及更深层次的 二进制漏洞挖掘,是非常困难!如果你希望挖掘 二进制漏洞 ,你还要学会 代码审计 !
你必须看得懂,汇编语言代码 和 C语言代码,这是硬性要求!
想要参加CTF竞赛,汇编语言 和 C语言 都是重要的底层基础知识。
现在,我们来接着讲一下二进制逆向方面的知识!漏洞挖掘的一些知识,也会在这一章节中进行讲解!
想要进行逆向工程,就必须了解 RFLAGS 标志寄存器中每一位的作用!
在 X64 环境下,RFLAGS
是一个 64 位的标志寄存器,但其中只有低 32 位是实际使用的,高 32 位是保留位。这 32 位标志寄存器用于存储处理器在执行指令过程中产生的各种状态信息,这些状态信息可以影响程序的执行流程。下面我将用大白话的方式讲解一下其中一些常用的标志位的作用:
-
进位标志(Carry Flag, CF):
- 当执行加法运算时,如果结果超出了寄存器的存储范围,就会产生进位,此时 CF 会被设置为 1。
- 当执行减法运算时,如果当前位的被减数小于减数,需要向前一位借位,此时 CF 也会被设置为 1。
- 这个标志位常用于处理需要跨越多位的算术运算。
-
零标志(Zero Flag, ZF):
- 当算术或逻辑运算的结果为 0 时,ZF 会被设置为 1。
- 这个标志位常用于判断运算结果是否为 0,从而决定程序的下一步操作。
-
符号标志(Sign Flag, SF):
- 当运算结果的最高位(即符号位)为 1 时,表示结果为负数,此时 SF 会被设置为 1。
- 反之,如果最高位为 0,表示结果为正数或零,SF 为 0。
- 这个标志位常用于判断运算结果的符号。
-
溢出标志(Overflow Flag, OF):
- 当执行有符号整数运算时,如果结果超出了有符号整数的表示范围,就会产生溢出,此时 OF 会被设置为 1。
- 需要注意的是,OF 只与有符号整数运算相关,无符号整数运算即使结果超出了范围也不会设置 OF。
-
辅助进位标志(Auxiliary Carry Flag, AF):
- 当执行 BCD(二进制编码的十进制)码加法或减法运算时,如果低 4 位向高 4 位产生了进位或借位,AF 会被设置为 1。
- 这个标志位主要用于处理 BCD 码的算术运算。
-
奇偶标志(Parity Flag, PF):
- 当运算结果中值为 1 的二进制位数是偶数个时,PF 会被设置为 1;否则设置为 0。
- 这个标志位通常用于奇偶校验,判断数据的奇偶性。
-
中断标志(Interrupt Flag, IF):
- 当 IF 被设置为 1 时,处理器允许外部或内部中断;当 IF 被设置为 0 时,处理器忽略中断请求。
- 这个标志位用于控制中断的使能状态。
-
方向标志(Direction Flag, DF):
- 当 DF 被设置为 1 时,字符串操作指令(如 MOVSB、CMPSB 等)会按减地址方向执行;当 DF 被设置为 0 时,按增地址方向执行。
- 这个标志位用于控制字符串操作指令的执行方向。
我们需要知道,除了上面的一些标志bit比特位之外,RFLAGS
寄存器中还会存在其它的一些标志bit比特位。但由于其它标志bit比特位的作用相对特殊或较少被真正使用,因此这里就不一一讲述了。在实际汇编语言编程中,了解RFLAGS标志寄存器中的
常用标志位的作用和用法,对于编写高效的汇编语言代码是非常重要的!
上面,我们讲解了RFLAGS寄存器中相关比特位的作用,下面,我们来讲述下,如何发现软件的真相!
通过IDA软件,我们看到了 taskmgr.exe ,也就是 WINDOWS 64 环境下 任务管理器 程序的源码!当然,这个源码,是通过IDA软件逆向出来的!
IDA软件,可以把软件程序的 二进制代码 转换为 汇编语言代码 !
更为强大之处在于,还可以通过再次逆向,将 汇编语言代码 转换为 C语言代码 !
现在知道 IDA 软件的强之处了吧?!
通过解析符号表,我们可以知道 taskmgr.exe 程序 使用了哪些 API 函数,或者定义了哪些内部函数!
我们来看一下,taskmgr.exe 程序 的 C语言代码 !
我们可以很清晰地看到 taskmgr.exe 程序 的 C语言代码 中 主调函数 WinMain 内部定义了哪些局部变量。我们可以看到所有变量的数据类型,是的,我们应该关心的是数据类型!还有局部变量的引用过程,以及局部变量的值变化!
char 是字符型变量,我们可以通过 sizeof(char) 来获得 char 型变量所占用的内存空间大小。
HRESULT 这个数据类型,如果你感到陌生,那么我们可以去看看它的定义!
看来 HRESULT 数据类型 是一个整型 !HRESULT 类型 的 变量,占用 4个字节的内存空间大小!
通过上面的解析,我们很清晰地知道了相关自定义数据类型的真相!
__int16
是一个数据类型,在编程中用来表示一个16位的整数。这种类型通常用于低级编程,比如在使用C或C++进行嵌入式系统编程时。它表示一个整数,其大小正好是16位(2字节),可以存储的值的范围是从 -32768 到 32767。这里的“__”前缀通常表示这是一个特定于编译器或平台的数据类型,不是C或C++标准的一部分,但大多数现代编译器都支持这种类型。
在不同的环境中, 可能会有不同的命名方式,比如 __int16、
short
、
int16_t
、
SHORT
等(在C99标准中定义),但这些类型在大多数情况下是等价的,都是用来表示16位整数的。
使用 类型时,开发者需要确保他们的代码和所使用的编译器或平台兼容,因为这是一个非标准的数据类型。在编写跨平台代码时,推荐使用标准库中定义的类型,如 ,以确保代码的可移植性。
unsigned 代表 无符号 !unsigned int 代表 无符号整型 !unsigned __int16 代表 无符号16位整数!__int16类型的变量占用2个字节的内存空间大小!
通过推导与解析,我们获知 WCHAR 变量类型占用的内存空间大小为2个字节,LPWSTR 类型变量 是 WCHAR 类型的 指针变量 !
LPWSTR 等同于 ( WCHAR * ) ,WCHAR 类型,我们也把它称为"宽字符类型“,在 WINDOWS 的编程环境中,一个汉字,占用2个字节,我们通过使用 宽字符类型的变量 来进行对于 汉字 的 存储!
LPWSTR 的用途是什么呢?
或者说,WCHAR * 类型变量的用途是什么呢?
指针变量 的 用途是什么?
指针变量的用途,是用于指向内存空间中指定区域,也就是说,指针变量中存储了内存空间中指定区域的起始地址!
那么,WCHAR * 类型变量的用途,一般情况下,则是为了指向 宽字符字符串 !
char * 通常用于 指向 ASCII码字符串(也称”单字符字符串“),而 WCHAR * 则用于指向 宽字符字符串 !你看懂了吗?
RunTimeSettings 类型是什么?
RunTimeSettings 类型 是一个结构体 !
RunTimeSettings 这个结构体类型,是在 taskmgr.exe 程序 的源代码中被定义的!
怎么知道 RunTimeSettings 这个结构体类型 是在 taskmgr.exe 程序 的源代码中被定义的呢?
看关键字 Local Types ,这是 本地类型集合 的意思!
而关键字 Type library ,则是 共享库(一般是 DLL 文件)的意思!
看这段代码,EtwCheckCoverage 函数,存在两个参数!
EtwCheckCoverage 函数的两个参数的数据类型大小是多少呢?
我们可以看到 EtwCheckCoverage 函数的两个参数 均为 qword 类型,而我们前面提到过,qword 类型的变量占用8个字节!因此,EtwCheckCoverage 函数需要的参数是两个8字节数据!
NtSetInformationProcess 函数是Windows NT内核提供的一个API接口,用于设置指定进程的信息。它是NTAPI(Native API)的一部分,通常用于内核层开发或与系统紧密相关的编程任务。这个函数允许开发者修改进程的状态或属性,例如设置进程是否为关键进程(critical process)等。
NtSetInformationProcess 函数的原型为:
__kernel_entry NTSTATUS NtSetInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength
);
NtSetInformationProcess 函数的参数为:
ProcessHandle
:目标进程的句柄。这个句柄通常通过 函数获得,并需要具有相应的访问权限。ProcessInformationClass
:指定要设置的信息类型。这是一个枚举值,定义了可以设置的不同类型的信息。例如,要设置进程是否为关键进程,可以使用 。ProcessInformation
:指向包含要设置的信息的缓冲区的指针。这个缓冲区的结构和内容取决于 参数的值。ProcessInformationLength
: 缓冲区的大小(以字节为单位)。
NtSetInformationProcess 函数的返回值为:
函数返回一个 NTSTATUS 类型的值,表示操作的成功或失败。如果操作成功,返回值通常表示成功代码;如果操作失败,返回值将表示错误代码。
NTSTATUS 类型,我们在上篇文章中提到过!关于 NTSTATUS 类型的取值范围,请自行百度 !
NtSetInformationProcess
NtSetInformationProcess 函数的使用场景:
- 设置进程为关键进程,这样当尝试终止该进程时,系统将会蓝屏,以防止重要进程的意外终止。
- 修改进程的调试端口信息,用于调试目的。
- 修改进程的内存保护模式等。
在这一章节中,我们重点强调了 RFLAGS 标志寄存器 和 专业逆向静态分析工具 IDA 的重要性!
这里有提到过 漏洞挖掘 知识吗?!
请您自行思考一下!安全漏洞 是如何一步一步被挖掘出来的!
0day 漏洞,如何被发现?!
方法,无外乎 动态调试 和 代码审计 !
什么是动态调试?
OD 软件,就是用来进行动态调试的!
如何进行 渗透测试 类的 动态调试呢?
你需要使用到 PYTHON 语言 和 PWNTOOLS 工具库,以及 PWNDBG 插件 !
代码审计,我们使用什么工具呢?
如果你审计的二进制程序,并没有为你提供对应的源代码,那么 IDA 软件,是个非常强大且好用的软件!事实上,一些恶意软件,或者病毒木马程序,通常不会给你提供二进制程序对应的源代码!那么, IDA 软件 将成为 你进行 0day 漏洞挖掘 和 恶意软件分析 方向的攻坚利器!
(未完待续)