4. OpCode:Prefixes - Part II

本文详细介绍了x86指令集中的前缀(Prefixes)功能,包括改变默认操作数大小、地址大小、重复前缀、段超越前缀及LOCK前缀,并通过实例解释了它们的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 4. Prefixes - Part II

转自老罗

I'll be back.

-- Arnold Schwarzenegger, The Movie - "Terminator"(1984)

Prefixes合集

在前一章中我们已经知道:

  1. 所有Prefixes的长度都是1个字节。
  2. 一个OpCode可能会有几个Prefixes。
  3. 如果有多个Prefixes,那么它们的顺序可以打乱。
  4. 如果Prefixes不能对随它之后的OpCode起作用,那么它就会被忽略。

现在我们将要学习剩下的几个Prefixes,它们可以被划分为5个集合,分别是:

  1. Change DEFAULT operand size. (66)
  2. Change DEFAULT address size. (67)
  3. Repeat prefixes. (F2, F3)
  4. Segment override prefixes(change DEFAULT segment). (2E, 36, 3E, 26, 64, 65)
  5. LOCK prefix. (F0)

Prefix 66

在前面我们已经学习过它了,而且也够详细的了,对吗?

Prefix 67

改变默认的地址大小。

请注意:6766的分别在于,66改变的是默认的操作数大小,而67则是地址的大小。两者有什么差异呢?

8A 00    MOV AL, [EAX]

现在把它的OpCode改成以67开头的:

67 8A 00    MOV AL, [BX+SI]

我们可以看到:

  1. 地址由原来的32位的[EAX]变成了16位的[BX+SI]。
  2. 疑问来了:为什么不是[AX],而是[BX+SI]呢?

第2个问题我们将会在以后的{ModR/M}和{SIB}的格式讲解中回答。现在我们可以暂时认为,在16位的地址模式中无法完全使用32位中的对应的地址模式,两种模式中的寄存器有着一定的区别。(看不明白?没关系,后面的章节中会详细解释)

强调一点:Prefix 67同样也是一个“触发器”,它起的作用是“切换”,而不是“指定”。

Repeat Prefixes (F2, F3)

Repeat Prefixes通常是与movsscascmps等串指令搭配使用的,它们有:

F2: REPNE
F3: REP / REPE

Repeat Prefixes作为一个串操作指令的前缀,它重复执行其后的串操作指令。每一次重复都先判断(E)CX是否为0,如为0就结束重复,否则(E)CX的值减1,然后再重复其后的串操作指令。所以当(E)CX的值为0时,就不再执行其后的操作指令。

它类似于LOOP指令,但LOOP指令是先把(E)CX的值减1,后再判断是否为0。

举例:

CLD
MOV ECX, 3
REP MOVSB

运行的结果是把DS:(E)SI的3个字节(byte)移动到ES:(E)DI去。

有两点规则:

  1. 你可以看到有3种Repeat Prefixes的助记符:rep/repe/repene,但是只有2个OpCode:F2F3
  2. 如果某些指令只使用前缀rep,那么这里的rep可以用repe或者repne来代替。

第2条规则比较难以理解,对吗?我们来举个例子:

REP LODSB
REPE LODSB
REPNE LODSB

这3条助记符的运行结果都是一样的:它会重复运行指令LODSB一共(E)CX次,而不管它的Repeat Prefixes是rep/repe[F3]还是repne[F2]。

但是请注意:第2条规则的适用范围仅仅是只使用rep”的指令,意即无论是F2还是F3,对指令的执行结果都无影响,而这样的指令非常的少!

从OpCode的角度来看rep/repe[F3]和repne[F2]的区别:

我们知道,重复串指令时可能会改变某些标志位(例如ZF),在这种情况下,有些指令与重复前缀搭配使用时,F2F3会把最后一位与标志位ZF进行比较,如果它们不相同,则重复串指令的操作将会结束。而有些指令不用进行这个比较的操作,因此标志位ZF对这些指令的运行结果无影响。

讲得不够清楚?呵呵,把F2F3转换成二进制就能明白了。

1111 0010  F2
1111 0011  F3

最后我们再来看看Repeat Prefixes的结束条件:

Repeat Prefiex的结束条件
Repeat Prefix结束条件1结束条件2
REPECX=0None
REPEECX=0ZF=0
REPNEECX=0ZF=1

从上表中可以看出:reperepne的结束必须同时满足两个结束条件,而rep只管ECX等不等于0。

看到这里,再结合上面的第2条规则,我们就能更清楚了:由于rep并不与标志位ZF进行比较,所以它可以被替换成repe或者repne,对执行结果无影响!

Segment Override Prefixes (2E, 36, 3E, 26, 64, 65)

我们先来看看这些Prefixes是什么:

Prefixes && Explanation
PrefixExplanation
2ECS segment override prefix
36SS segment override prefix
3EDS segment override prefix
26ES segment override prefix
64FS segment override prefix
65GS segment override prefix

再来看一个例子:

   8B 03    MOV EAX, [DWORD DS:EBX]
65 8B 03    MOV EAX, [DWORD GS:EBX]

65就是一个Segment override prefix,用来改变默认的段,从上表中我们可以看出:65代表的是段GS。注意!这里也是用默认的概念。

读者在这里也许会存在一个疑问:默认?我怎么知道当前默认的是哪个段呢?以及为什么要用默认的概念呢?

答案是这样的:在使用内存中的数据时,处理器必须首先知道它的段地址(Segment)和偏移量(Offset),但是如果在每个地方都要显式地直接指出段地址,那么在OpCode格式中就必须增加一个新的域,这将会比现有的OpCode体系多占用大量的字节,而且处理器也必须多花费额外的时钟周期来进行解码——无论在空间还是时间上,都不值得!

因此,为了解决这个问题,一个方案诞生了:

指令由不同的定义被划分为不同的组,每个组各自有一个默认的段:

CS: for EIP pointer
ES: 目的操作数是内存单元的串指令(movs, cmps等),在这里源操作数是储存在段DS里面。
SS: 堆栈操作(push, pop等)
DS: 剩下的数据操作指令。

有了这个规则,处理器识别当前应该用哪个段将会变得非常简单而直接:

  1. 如果有“Segment override prefix”,那么就使用这个prefix所指定的段。
  2. 否则就使用默认的段。

看看:

   AC     LODS [BYTE DS:ESI]
3E AC     LODS [BYTE DS:ESI]

从上面的表中可以查出,3E是表示段DS,但是实际上在这里即使不直接指明3E,处理器也是会使用DS的,因为DS是指令LODS的默认段。

最后值得一提的是64,它表示的是段FS,也许读者会对FS不太熟悉,平时好像很少会用到。没关系,我们来简单介绍一下:FS一般是由SEH(结构化异常处理)所使用,但是由于SEH不属于OpCode格式的范畴,所以我们在这里不必深究,知道有这个概念就行了。

LOCK Prefix (F0)

对于这个Prefix,Intel的文档已经解释得很清楚了,不过它的具体意义对OpCode的格式学习并无任何帮助,有兴趣的读者可以在<<Intel Architecture Software Developer's Manual Volume 2: Instruction Set Reference>>的3-387页看到关于它的详细解释。在OpCode的格式学习中,我们只需要知道F0表示的是助记符LOCK就足够了。

The End Of Prefixes

结束了吗?

是的!关于Prefixes的格式学习到此就告一段落了。在接下来的章节中,我们将会学习最激动人心的一部分:如何对OpCode进行手工解码。



(注:如果出现链接打不开的情况,请去掉IE浏览器的“工具->Internet选项->高级->总是以UTF-8发送URL”前面的勾。谢谢!)
 
Windows 系统修复工具主要用于解决 Windows 11/10 系统中的各种常见问题,具有操作简单、功能全面等特点: 文件资源管理器修复:可解决文件资源管理器卡死、崩溃、无响应等问题,能终止崩溃循环。还可修复右键菜单无响应或选项缺失问题,以及重建缩略图缓存,让图片、视频等文件的缩略图正常显示,此外,还能处理桌面缺少回收站图标、回收站损坏等问题。 互联网和连接修复:能够刷新 DNS 缓存,加速网页加载速度,减少访问延迟。可重置 TCP/IP 协议栈,增强网络连接稳定性,减少网络掉线情况,还能还原 Hosts 文件,清除恶意程序对网络设置的篡改,保障网络安全,解决电脑重装系统后网络无法连接、浏览器主页被篡改等问题。 系统修复:集成系统文件检查器(SFC),可自动扫描并修复受损的系统文件。能解决 Windows 激活状态异常的问题,还可重建 DLL 注册库,恢复应用程序兼容性,解决部分软件无法正常运行的问题,同时也能处理如 Windows 沙箱无法启动、Windows 将 JPG 或 JPEG 保存为 JFIF 等系统问题。 系统工具维护:提供启动管理器、服务管理器和进程管理器等工具,用户可控制和管理启动程序、系统服务和当前运行的进程,提高系统的启动和运行速度,防止不必要的程序和服务占用系统资源。还能查看系统规格,如处理器线程数、最大显示分辨率等。 故障排除:集成超过 20 个微软官方诊断工具,可对系统问题进行专业排查,还能生成硬件健康状态报告。能解决搜索和索引故障、邮件和日历应用程序崩溃、设置应用程序无法启动等问题,也可处理打印机、网络适配器、Windows 更新等相关故障。 其他修复功能:可以重置组策略设置、catroot2 文件夹、记事本等多种系统设置和组件,如重置 Windows 应用商店缓存、Windows 防火墙设置等。还能添加重建图标缓存支持,恢复粘滞便笺删除
资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 今天给大家分享一个关于C#自定义字符串替换方法的实例,希望能对大家有所帮助。具体介绍如下: 之前我遇到了一个算法题,题目要求将一个字符串中的某些片段替换为指定的新字符串片段。例如,对于源字符串“abcdeabcdfbcdefg”,需要将其中的“cde”替换为“12345”,最终得到的结果字符串是“ab12345abcdfb12345fg”,即从“abcdeabcdfbcdefg”变为“ab12345abcdfb12345fg”。 经过分析,我发现不能直接使用C#自带的string.Replace方法来实现这个功能。于是,我决定自定义一个方法来完成这个任务。这个方法的参数包括:原始字符串originalString、需要被替换的字符串片段strToBeReplaced以及用于替换的新字符串片段newString。 在实现过程中,我首先遍历原始字符串,查找需要被替换的字符串片段strToBeReplaced出现的位置。找到后,就将其替换为新字符串片段newString。需要注意的是,在替换过程中,要确保替换操作不会影响后续的查找和替换,避免遗漏或重复替换的情况发生。 以下是实现代码的大概逻辑: 初始化一个空的字符串result,用于存储最终替换后的结果。 使用IndexOf方法在原始字符串中查找strToBeReplaced的位置。 如果找到了,就将originalString中从开头到strToBeReplaced出现位置之前的部分,以及newString拼接到result中,然后将originalString的查找范围更新为strToBeReplaced之后的部分。 如果没有找到,就直接将剩余的originalString拼接到result中。 重复上述步骤,直到originalStr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值