x86 二进制混淆的基本前提是否准确? (只有系统调用及其参数对程序的结果有影响)

Is this fundamental premise for x86 binary obfuscation accurate? (That only system calls and their arguments matter to the outcome of the program)

这与用户模式下的代码 运行 有关。为了简单起见,假设我们采用了程序调用的任何共享库/OS API,并将它们静态链接到内存中,因此我们不调用任何抽象层,只使用系统调用直接。

我正在做一个实验,通过识别某些非可变状态(我 认为 系统调用和跳转)来实现二进制混淆,而无需构建相对高级的混淆方法。基本上,我模拟程序为每条执行的指令存储状态变化。当我到达系统调用或跳转时,我将其标记为边界,并且在两个边界之间执行的每条指令都作为“函数”。我的理论是,在用户模式程序中,系统调用是唯一具有“效果“在程序之外。换句话说,无论您希望您的程序在用户模式下对系统进行什么更改,系统调用都是唯一的方式。

如果我错了,请停在这里。

因此,基于这种理解,我假设我可以以几乎无限多种方式改变这些函数中的每一个,只要生成的指令在函数末尾导致相同的状态,以便系统调用参数保持不变。当然,控制流也需要保留,所以我也将跳转视为保留状态。我通过使用 Monte Carlo 树搜索从突变状态中求解所需状态来实现此目的。换句话说,如果我遵循这些规则并将变异程序修补在一起并更新所有跳转以达到它们之前指向的相同 函数 ,我的程序应该在外部执行相同的目标它最初是这样做的,但是通过不同的指令。

这是一个可视化图表。如果放大,它是清晰的,但 SO 的压缩使它有点模糊。

这个概念只是为了混淆内存、寄存器和指令序列分析通道(如果没有进一步的规范,不会混淆它们'entirely')

我的前提有问题吗?

mmap(MAP_SHARED, PROT_READ|PROT_WRITE)之后,写入内存最终会影响磁盘上文件的内容,and/or对读取共享内存区域的其他进程可见。 (进程间通信的共享内存的大部分使用不是通过磁盘文件,而是匿名 SHM,如 shmat(2)shm_open(3)

许多程序不会对任何文件执行此操作,但为 IPC(尤其是 X 服务器)使用共享内存有些常见。

不过,它可能并没有完全否定你关于 reg/mem 状态的论点 before/after 系统调用是大多数时候唯一相关的东西。

多线程程序通过内存自身通信;线程共享它们的整个地址 - space,并且 load/store 指令的顺序对于内存排序可能很重要。对于原子性,是用一个双字 mov 完成 4 字节加载还是稍后合并的四字节加载。 Atomic pure-load 和 pure-store 只是简单的指令,只有 atomic RMW 需要一个 lock 前缀(假设你在多核机器上编译为 运行,否则 lock前缀可以省略。)