自修改代码的用途是什么?
有没有真正的自我修改代码的用途?
我知道,他们可以用来构build蠕虫/病毒,但我想知道是否有一个很好的理由,程序员可能不得不使用自我修改代码。
有任何想法吗? 假设的情况也是受欢迎的。
原来,“ 自我修改代码 ”的维基百科条目有一个很好的列表:
- 半自动优化状态依赖的循环。
- 运行时代码生成或运行时间或加载时间(例如在实时graphics领域中很stream行)中algorithm的专业化,例如通用sorting实用程序准备代码以执行在特定调用中描述的密钥比较。
- 改变对象的内联状态 ,或者模拟closures的高级构造。
- 修补子程序地址调用 (通常在dynamic库加载时完成),或者在每次调用修补子程序对其参数的内部引用时使用其实际地址。 这是否被认为是“自我修改的代码”是一个术语的情况。
- 演化计算系统 ,如遗传编程。
- 通过使用反汇编器或debugging器来隐藏代码以防止反向工程 。
- 隐藏代码以逃避病毒/间谍软件扫描软件等的检测 。
- 用重复操作码的滚动模式填充100%的内存(在某些体系结构中), 擦除所有程序和数据 ,或者烧录硬件 。
- 压缩要在运行时解压缩和执行的代码 ,例如,当内存或磁盘空间有限时。
- 一些非常有限的指令集别无select,只能使用自修改代码来实现某些function 。 例如,只使用“如果是负数的指令”的减法分支的“单指令集计算机”机器不能进行间接复制(类似于C程序中的“* a = ** b”语言)而不使用自修改代码。
- 更改容错指令
关于使用自修改代码来阻止黑客的问题:
在几次固件更新的过程中,DirectTV慢慢地在他们的智能卡上组装了一个程序,以销毁被黑客非法收到无偿渠道的卡片。 有关更多信息,请参阅“ 黑色星期天黑客”中的杰夫编码恐怖文章。
我已经看到自修改代码用于:
-
速度优化,让程序在运行中为自己编写更多的代码
-
晦涩难懂,使逆向工程更加困难
在以前的RAM是有限的,自修改代码被用来节省内存。 现在,例如像UPX这样的应用程序压缩实用程序被用来在加载应用程序的压缩图像之后解压缩/修改自己的代码。
因为Commodore 64没有多个寄存器,并有一个1Mhz的处理器。 当你需要通过一个值来读取一个内存地址的偏移量时,修改源代码更容易。
@Reader: LDA $C000 STA $D020 INC Reader+1 JMP Reader
这是我最后一次写自修改代码:-)
20世纪60年代的汇编语言使用自修改代码来实现没有堆栈的函数调用。
Knuth,v1,1ed p.182:
MAX100 STJ EXIT ;Subroutine linkage ENT3 100 ;M1. Initialize JMP 2F 1H CMPA X,3 ;M3. Compare JGE *+3 2H ENT2 0,3 ;M4. Change m LDA X,3 ;(New maximum found) DEC3 1 ;M5. Decrease k J3P 1B ;M2. All tested? EXIT JMP * ;Return to main program
在包含此编码作为子程序的较大程序中,单指令“JMP MAX100”将使寄存器A被设置为位置X + 1至X + 100的当前最大值,并且最大位置将出现在rI2 。 在这种情况下子程序链接是通过指令“MAX100 STJ EXIT”和稍后的“EXIT JMP *”实现的。 由于J寄存器的操作方式,退出指令将跳转到MAX100原始参考位置之后的位置。
编辑:可能很难看到发生了什么,即使在这里简要的解释。 在MAX100 STJ EXIT
, MAX100
是指令标签(也就是整个程序的标签), STJ
表示存储跳转寄存器(我们刚从哪里来), EXIT
表示标记为“EXIT”的存储单元是商店的目标。 EXIT
,我们稍后看到的是最后一条指令的标签。 所以它是覆盖代码! 但是,许多指令(包括这里的STJ
)隐含地只覆盖指令字的操作数部分。 所以JMP
保持不变, *
是一个虚拟标记,因为放在那里真的没什么意义,只会被覆盖。
在寄存器间接寻址不可用的地方也可以使用自修改代码,但是您需要的地址就在寄存器中。 PDP-1 LISP:
dap .+1 ;deposit address part of accumulator in (IP+1) lac xy ;load accumulator with (ADDRESS) [xy is a dummy symbol, just like * above]
这两条指令通过修改加载指令的操作数来执行ACC := (ACC)
。
像这样的修改是比较安全的,在古色古香的build筑中,它们是必要的。
很多原因。 closures我的头顶上:
-
运行时类的构造和元编程。 例如,拥有一个与SQL表连接的类工厂,并生成专用于该表的客户类(带有列访问器,查找方法等)。
-
那么当然还有着名的bitblt例子和正则expression式。
-
基于RT信息dynamic优化跟踪JIT
-
ada风格generics函数在增生环境中的子types专业化。
– MarkusQ
因为它真的很酷,有时候这就够了。
dynamic链接是一种自我修改(修补绝对和/或相对跳转位置),这通常是由O / S的程序加载器完成的。
人工智能?
neural network是一种自我修改的代码。
然后有自我修改的进化algorithm 。
大声笑 – 我已经写了两次自修改代码:
- 当我第一次学习汇编语言,之前我了解间接索引访问
- 偶然,作为汇编语言和C的指针错误
我可以想象,自修改代码可能比替代scheme更有效,但是没有什么明显的突破。 一般来说,这是要避免的 – debugging噩梦等 – 除非你故意试图混淆上面提到的。
Mike Abrash回顾了Dr. Dobb's Journal的Pixomatic代码生成器: http ://www.ddj.com/architect/184405807。 这是一个软件3D DX7(?)兼容的光栅器。
实现自己的脚本语言的应用程序经常这样做。 例如,数据库服务器通常以这种方式编译存储过程(或查询)。
SwiftShader中的dynamic代码生成是自修改代码的一种forms,使其能够有效地在CPU上实现Direct3D 9。