CIL nop操作码的目的是什么?

问题描述 投票:81回答:20

我正在通过MSIL,并注意到MSIL中有很多nop指令。

MSDN文章说,如果对操作码进行了修补,它们将不采取任何措施,并被用来填充空间。在调试版本中使用的版本比发行版本更多。

我知道在汇编语言中会使用这些类型的语句来对齐后面的指令,但是为什么在MSIL中需要MSIL nop?

((编者注:接受的答案是关于机器代码NOP的,而不是问题最初询问的MSIL / CIL NOP。)

assembly bytecode cil
20个回答
105
投票

NOP有几个用途:

  • 他们允许调试器在一行上放置一个断点,即使该断点与生成的代码中的其他断点合并。
  • 它允许加载程序修补具有不同大小的目标偏移量的跳转。
  • 它允许将代码块在特定边界处对齐,这对于缓存很有用。
  • 它允许增量链接通过调用新节来覆盖代码块,而不必担心整个函数的大小改变。

3
投票
它们的一种经典用法是使调试器始终可以将源代码行与IL指令相关联。

3
投票
[在软件破解场景中,解锁应用程序的经典方法是用NOP修补检查密钥,注册或时间段或诸如此类的行,因此它无能为力,只是继续启动应用程序,就像已注册。

3
投票
[我也已经在代码中看到过NOP,它们会对其进行自我修改以混淆其作为占位符的功能(老式的老式复制保护)。

3
投票
如ddaa所说,nops使您可以考虑堆栈中的差异,因此,当您覆盖返回地址时,它会跳转到nop底座(连续很多nops),然后正确命中可执行代码,而不是跳转到指令中不是开头的某个字节。

2
投票
Nop对于缓冲区溢出漏洞的有效负载至关重要。

1
投票
它们允许链接器用较短的指令(短跳转)替换较长的指令(通常为长跳转)。 NOP占用了额外的空间-代码无法四处移动,因为它会阻止其他跳转工作。这是在链接时发生的,因此编译器无法知道长跳转还是短跳转是适当的。

至少,这是他们的传统用途之一。


1
投票
这不是对您的特定问题的答案,但是在过去,如果您无法设法用其他有用的指令来填充它,则可以使用NOP来填充NOP-Slides

1
投票
。NET编译器是否对齐MSIL输出?我以为它可能对加快对IL的访问很有用……而且,我的理解是,它被设计为可移植的,并且在某些其他硬件平台上需要对齐的访问。

1
投票
我学到的第一个程序集是SPARC,所以我熟悉分支延迟槽,如果您不能用另一条指令填充它,通常是要放在分支指令上方的指令或循环增加计数器的指令,您使用NOP。

我不熟悉破解,但是我认为使用NOP覆盖堆栈很常见,因此您不必精确计算恶意功能的开始位置。


1
投票
我使用NOP来自动调整进入ISR后累积的等待时间。非常方便地把握时机。

10
投票

以下是调试如何使用MSIL / CIL nops(不是x86机器代码nop):

语言编译器(C#,VB等)使用Nops定义隐式序列点。这些告诉JIT编译器在哪里确保可以将机器指令映射回IL指令。

[Rick Byer在nop上的博客条目,解释了一些细节。

C#还将Nops放在呼叫说明之后,以便源中的返回站点位置是呼叫,而不是呼叫之后的行。


-1
投票
branch delay slot将在内存破坏利用有效载荷中有用。当然,nopnop类似>

8
投票

[它为代码中的基于行的标记(例如断点)提供了机会,而发行版本不会发出任何标记。


6
投票

当针对特定处理器或体系结构进行优化时,它还可以使代码运行更快:

长时间以来,处理器采用了多个并行运行的流水线,因此可以同时执行两条独立的指令。在具有两个管线的简单处理器上,第一个可以支持所有指令,而第二个仅支持一个子集。另外,当必须等待尚未完成的上一条指令的结果时,在流水线之间会有一些停顿。

在这种情况下,专用的[[nop可能会迫使下一条指令进入特定的流水线(第一条,或者不是第一条),并改善后续指令的配对,从而使nop的成本下降被摊销了。


5
投票
伙计!无操作真棒!这是一条只消耗时间的指令。在昏暗的黑暗时代,您可以使用它来对关键循环中的时序进行微调整,或者更重要的是,它可以用作自我修改代码中的填充物。

5
投票
在我最近(四年)工作的一个处理器中,使用NOP来确保上一个操作在下一个操作开始之前已完成。例如:

将值加载到寄存器(需要8个周期)8月加1进行注册

这确保在进行加法运算之前,寄存器具有正确的值。

另一个用途是填充执行单元,例如中断向量必须为一定大小(32字节),因为向量0的地址为0,向量1的地址为0x20,依此类推,因此编译器将NOP放入如果需要的话。


4
投票
他们可能会在调试时使用它们来支持

edit-and-continue”。它为调试器提供了工作空间,可以在不更改偏移量的情况下用新代码替换旧代码,等等。


4
投票
在缓冲区溢出漏洞利用中使用的DebuggingModes.IgnoreSymbolStoreSequencePoints有一些非常规的用法。

4
投票
50年为时已晚,但是嘿。

Nop很有用,如果您手动键入汇编代码。如果必须删除代码,则可以不输入旧的操作码。

类似地,您可以通过覆盖一些操作码来插入新代码,然后跳转到其他地方。在这里放置了覆盖的操作码,然后插入新代码。准备好后,您跳回去。

有时您必须使用可用的工具。在某些情况下,这只是一个非常基本的机器代码编辑器。

如今,对于编译器而言,这些技术已经毫无意义了。

© www.soinside.com 2019 - 2024. All rights reserved.