软件用od载入。里面都是jmp是怎么加密的?

曾经在B站见过是异或加密
找不到视频了,如下面这样的,

image.png

阅读 2.3k
1 个回答

关于这个问题,我觉得知识量有点多,因此我打算分段描述。

汇编指令不能异或?

首先给其他(如果是正在学习c提升阶段或者汇编基础的小伙伴)看到这个回答的小伙伴提个醒,jmp正常情况是不会有加密的情况的,原因我们可以很好理解,汇编是一个基础底层的指令,jmp(你可以抽象记忆一下,jump,跳跃,对不对)的目的就是实现程序控制流程的跳转,而跳转的目的地址通常会存储在内存或寄存器中,而不可能是被加密的。

汇编指令可以异或

但是也有特殊的情况,比如楼主的这个问题,这类问题通常软件安全的朋友会遇到,在一些加密的二进制代码中,可能存在一些跳转指令的目的地址被加密的情况,这与 jmp 指令本身并没有直接关系。这种加密方式通常采用编译器插桩的方式,在编译后的二进制文件中,通过在跳转指令的地址值上进行一定的计算和变换,来达到加密的目的。具体加密方式可能会因编译器、加密器或者加密方案的不同而有所不同,但常见的方法包括异或加密、加法加密、基于密钥的混洗等等。
我放个我写的代码来解释下这么大一段文字吧:

#include <stdio.h>
#include <stdint.h>

// 对 JMP 指令的目标地址进行异或加密
uint64_t encode_jump(uint64_t jump_addr, uint64_t key)
{
    uint64_t encoded_addr = jump_addr ^ key; // 异或运算
    return encoded_addr;
}

int main()
{
    uint64_t jump_addr = 0x1000; // 总跳转地址
    uint64_t target_addr = 0x2000; // jmp 指令要跳转到的目标地址
    uint64_t key = 0xabcd1234; // 异或加密使用的密钥

    // 计算跳转到目标地址的相对偏移量
    uint64_t relative_offset = target_addr - jump_addr - sizeof(uint64_t);

    // 对相对偏移量进行异或加密
    uint64_t encoded_offset = encode_jump(relative_offset, key);

    // 把加密后的相对偏移量存入 jmp 指令中
    uint64_t jmp_instruction = 0xff25000000000000 | encoded_offset; // jmp [rip-6] 指令 + 添加偏移量
    printf("JMP 指令: %lx\n", jmp_instruction);

    // 解密 jmp 指令中的相对偏移量,计算出真正的目标地址
    uint64_t decoded_offset = jmp_instruction & 0xffffffffffff; // 取出加密偏移量
    uint64_t decoded_addr = decoded_offset ^ key; // 解密偏移量
    uint64_t target_addr_decoded = jump_addr + sizeof(uint64_t) + decoded_addr; // 计算出真正的目标地址
    printf("跳转到的目标地址: %lx\n", target_addr_decoded);

    return 0;
}

该示例代码中,对 jmp 指令的目标地址进行了异或加密。首先计算跳转到目标地址的相对偏移量,该偏移量将被嵌入 jmp 指令中。然后对相对偏移量进行异或加密,使用一个预设的密钥。紧接着我们把加密后的相对偏移量存入 jmp 指令中,替代原本的目标地址。最后在运行时,解密 jmp 指令中的加密偏移量,计算得到真正的目标地址。

逆向思考

作为一名合格的安全研究员,我们仅仅是通过demo知道还不够,要知其然,知其所以然。毕竟,现实的情况是,不会有谁傻到像上面那样直接把代码这么放出来,告诉你,你看,这就是异或!既然有加密,那么说明一定是有遮遮掩掩,不想让我们看到。所以我们开盲盒的假设。首先,我们需要用 od 工具以二进制形式打开包含该 jmp 指令的可执行文件,假设该 jmp 指令的偏移量是 0x08048080吧,那么偏移量对应的是:

$ od -t x1 myfile | grep '08048080'
08048080 e8 43 78 89 ff e0 ff ff ff ff 00 00 00 00 00 00

上述输出中 e8 43 78 89 ff 是 jmp 指令的二进制码。
0xff 是 jmp 指令的间接寻址操作符。它表示要通过地址跳转到另一段代码。在这个例子中,jmp 指令跳转的地址存储在后面的 6 个 FF 的位置。这 6 个字节是 jmp 指令的第二个操作数,用于存储跳转地址。
根据汇编指令的规则,假设跳转目标地址为 0x08048123。由于 jmp 是通过相对偏移量进行跳转的,所以需要计算 jmp 的相对偏移量(以跳转目标地址为起点)。由于 jmp 指令占用了 5 个字节的空间,因此相对偏移量应为 0x08048080 - 0x08048123 - 5 = 0xffffffc4。
接下来,根据代码的设计,要对跳转目标地址进行异或加密。加密算法为:encoded_target = jump_target ^ key,其中 key 为给定的密钥。
假设给定的密钥是 0xaabbccdd。则经过异或加密后,加密后的目标地址为 0x6e7b01968154122c。
根据上图中,跳转目标地址在 jmp 指令中存储的字节顺序,将加密后的异或值写入对应的位置。如下所示:

$ printf '\x6e\x7b\x01\x96\x81\x54\x12\x2c' | od -t x1
0000000 6e 7b 01 96 81 54 12 2c
0000010

可以看到 ff 之后的 6 个字节被修改为 6e 7b 01 96 81 54 12 2c。这是加密后的异或值。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题