再使用,然后我们可以随意修改拷贝后的调用表。(4)攻击系统中断表。攻击者可改变中断 表中的记录,并伪造一个处理例程。此类攻击比较繁琐,攻击者需构建自己的处理函数,而 且中断子系统很接近计算机体系架构,可参考文献 phrack-59“Handling Interrupt Descriptor Table for fun and profit”.(5)攻击 idtr 寄存器。中断表的定位需借助 idtr 寄存器,对应的值可通过 sidt 指令修改。攻击者可实施方法(3)的诡计,即拷贝一 份中断表,然后改变idtr寄存器值,使其指向复制的中断表。 攻击新策略 下面,我们将会关注如何在函数实现体中间位置改变程序的执行流,这种思想源于攻击 系统调用函数策略,即用JMP 指令替换函数体前几条指令,实现函数偷换。我们将尽力推广 此技术,使其能够在函数体中间位置发挥作用,以躲避某些针对函数体头尾部几条指令的特 征值校验。若想在一个现有函数中间位置劫持程序执行流,重写函数代码是必然。但最大的 问题是,如何在修改后的函数体内确保原行为,主要归结为以下三点。 (1)七字节空间。为了劫持程序执行流,我们必须重写原函数部分代码,即用JMP或CALL 指令替换部分指令。最简单方式即将目标函数地址填充到一个CPU寄存器中如$eax,然后执 行一个绝对JMP命令,如:movl $0, $eax, jmp %eax, 这两条指令编译后的机器码 (\xb8\x00\x00\x00\x00\xff\xe0),共7字节大小,即我们需要至少重写两条指令。 (2)保护合法代码。在重写后,必须保证代码的有效性。若我们构造了一个无效指令, CPU会捕获到一个异常,并立即终止进程执行。故,必须确保指令的开始和结束部分不被修 改,即每个标签体内部指令不被修改。 (3)保持原有语义。即在函数体内改变程序执行流后,当执行完HACK函数后,需要在 不改变原有函数语义的情况下,继续执行原函数指令。下面我们针对一个特定的系统调用例 程给出解决上述三个问题的策略。 3.1 如何选择位置劫持程序执行流 调用例程是一个底层子系统,汇编代码实现 :
system_call:
函数调用开始之前,会暂存系统调用号以及所有CPU寄存器值到堆栈中,然后计算当前
最佳位置。前两个字节主要用来暂存用户空间数据,显然不可重写,否则有可能丢失部分数
系统调用例程执行上面两个测试。其一,校验当前运行进程是否被跟踪,若已设置跟踪 |