【问题标题】:What are the uses of self modifying code? [closed]自修改代码的用途是什么? [关闭]
【发布时间】:2009-02-05 16:34:24
【问题描述】:

自修改代码有什么实际用途吗?

我知道它们可用于构建蠕虫/病毒,但我想知道程序员可能不得不使用自修改代码是否有充分的理由。

有什么想法吗?也欢迎假设情况。

【问题讨论】:

    标签: executable self-modifying


    【解决方案1】:

    原来“self-modifying code”上的维基百科条目有一个很棒的列表:

    1. 状态相关循环的半自动优化
    2. 运行时代码生成,或在 运行时或加载时间(很流行, 例如,在 实时图形),如一般 排序实用程序准备要执行的代码 a中描述的关键比较 特定的调用。
    3. 改变对象的内联状态,或模拟高层 建造闭包。
    4. 子程序地址调用的修补,通常在加载时完成 动态库,或者,在每个 调用修补子例程的 对其参数的内部引用 以便使用他们的实际地址。 这是否被视为 '自修改代码'与否是一个案例 术语。
    5. 进化计算系统,例如基因编程。
    6. 隐藏代码以防止逆向工程,如通过使用 反汇编器或调试器。
    7. 隐藏代码以逃避检测病毒/间谍软件扫描软件和 之类的。
    8. 使用滚动模式填充 100% 的内存(在某些体系结构中) 重复操作码,擦除所有 程序和数据,或老化 硬件
    9. 压缩代码在运行时解压并执行, 例如,当内存或磁盘空间不足时 有限。
    10. 一些非常有限的指令集别无选择,只能使用 自修改代码以达到一定的 功能。例如,“一 指令集计算机”机器 仅使用 如果为负,则减并分支 “指令”不能做间接的 复制(类似于 C 编程中的“*a = **b” 语言)不使用自修改 代码。
    11. 更改容错的说明

    关于使用自我修改代码挫败黑客的问题:

    在几次固件更新过程中,DirectTV 在他们的智能卡上慢慢组装了一个程序,以销毁被黑客入侵以非法接收未付费频道的卡。有关更多信息,请参阅 Black Sunday Hack 上 Jeff 的 Coding Horror 文章。

    【讨论】:

    • DirectTV 的黑色星期天黑客?
    • Monkey patching 也可以被认为是自修改代码。它在依赖第三方库时很有用。
    【解决方案2】:

    我见过用于以下用途的自修改代码:

    1. 速度优化,让程序在运行中为自己编写更多代码

    2. 混淆,使逆向工程更加困难

    【讨论】:

    • 从历史上看,这在游戏软件的版权保护机制中非常流行。
    • 在一些旧的 8 位微型 (BBC) 游戏上需要使用哪个 btw 才能让它们从磁盘而不是盒式磁带运行。
    【解决方案3】:

    在以前 RAM 有限的情况下,使用自修改代码来节省内存。如今,例如UPX 等应用程序压缩实用程序用于在加载应用程序的压缩图像后解压缩/修改自己的代码。

    【讨论】:

    • 我以为这些二进制压缩器只在磁盘上压缩,加载到内存时才解压?我还读过一次,因为它们在加载到内存时被解压缩,所以它们不能被分页到磁盘,所以它们消耗更多的 RAM。不是这样吗?
    • 打包的可执行文件有一个“引导”应用程序,它被加载到内存中并从那里启动。然后加载压缩数据,解压缩并将解压缩的指令附加到它自己的代码中。解压完成后,启动这段代码。分页照常进行。
    • 自解压JavaScript在网页中被大量使用。
    【解决方案4】:

    因为 Commodore 64 没有很多寄存器并且有一个 1Mhz 处理器。当您需要读取一个偏移值的内存地址时,修改源更容易。

    @Reader:
    LDA $C000
    STA $D020
    INC Reader+1
    JMP Reader
    

    那是我最后一次写自修改代码了 :-)

    【讨论】:

      【解决方案5】:

      人工智能?

      【讨论】:

        【解决方案6】:

        因为它真的很酷,有时这就是足够的理由。

        【讨论】:

          【解决方案7】:

          1960 年代的汇编语言使用自修改代码来实现没有堆栈的函数调用。

          Knuth,v1,第 1 版,第 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 寄存器的操作方式,exit 指令将跳转到最初引用 MAX100 的位置之后的位置。

          编辑:可能很难看出发生了什么,即使这里有简短的解释。在MAX100 STJ EXIT 行中,MAX100 是指令的标签(因此也是整个过程的标签),STJ 表示存储跳转寄存器(我们刚刚来自的地方), EXIT 表示标记为“EXIT”的内存位置是 STORE 的目标。 EXIT,我们稍后会看到是最后一条指令的标签。所以它正在覆盖代码!但是,许多指令(包括此处的STJ)隐式地仅覆盖指令字的操作数部分。所以JMP 保持不变,* 是一个虚拟标记,因为放在那里真的没有任何意义,它只会被覆盖。


          自修改代码也用于寄存器间接寻址不可用的情况,但您需要的地址就在寄存器中。 PDP-1 语言:

          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)

          这样的修改是相对安全的,在古董建筑上,它们是必要的。

          【讨论】:

            【解决方案8】:

            原因很多。在我脑海中浮现:

            • 运行时类构造和元编程。例如,拥有一个与 SQL 表建立连接并生成专门用于该表的客户端类的类工厂(具有列的访问器、查找方法等)。

            • 当然还有著名的 bitblt 示例和正则表达式类似物。

            • 基于 RT 信息动态优化和跟踪 JIT

            • ada 风格泛型函数在增值环境中的子类型特化。

            -- 马库斯Q

            【讨论】:

              【解决方案9】:

              动态链接是一种自我修改(修补绝对和/或相对跳转位置)......不过,这通常由操作系统的程序加载器完成。

              【讨论】:

                【解决方案10】:

                Neural networks 是一种自修改代码。

                然后有evolutionary algorithms自己修改。

                【讨论】:

                • 我不确定神经网络会修改代码。我从来不知道。 hoozi.com/Articles/Neural-Networks-Artificial-Neuron.htm
                • 我相信任何必须对神经网络结构做的改变都可以在数据部分完成。为什么要修改代码?
                • 神经网络不是自修改代码。它们只不过是复杂的非线性变换,其权重由训练决定。
                • 它们实际上并没有修改代码本身,但功能发生了变化。进化算法也是如此,它们可以在不更改实际代码的情况下实现。
                • 在代码生成器之上实施以执行其进化的进化算法怎么样?
                【解决方案11】:

                Mike Abrash 不久前为 Dobb 博士的日记描述了 Pixomatic 代码生成器:http://www.ddj.com/architect/184405807。那是软件 3d dx7(?) 兼容的光栅化器。

                【讨论】:

                  【解决方案12】:

                  大声笑 - 我曾两次编写过自修改代码:

                  1. 第一次学习汇编语言时,在我理解间接索引访问之前
                  2. 意外地,作为汇编语言和 C 中的指针错误

                  我可以想象在某些情况下,自修改代码会比替代代码更有效,但没有什么明显的飞跃。一般来说,这是要避免的——调试噩梦等——除非你像上面提到的那样故意试图混淆。

                  【讨论】:

                    【解决方案13】:

                    实现自己的脚本语言的应用程序经常这样做。例如,数据库服务器经常以这种方式编译存储过程(或查询)。

                    【讨论】:

                      【解决方案14】:

                      SwiftShader 中的动态代码生成是一种自我修改代码的形式,可以让它在 CPU 上高效地实现 Direct3D 9。

                      【讨论】:

                        【解决方案15】:

                        现代例子: 我有一个需要 JWT 令牌才能工作的脚本。要请求令牌,需要交互式登录或使用新 JWT 令牌发出的刷新令牌。最好在脚本中存储刷新令牌并在每次执行时更新它

                        【讨论】:

                          猜你喜欢
                          • 2018-06-16
                          • 2014-01-02
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-11-06
                          • 2019-11-14
                          相关资源
                          最近更新 更多