翻译
原文地址:https://www.x86matthew.com/view_post?id=windows_no_exec
功能:滥用现有指令,在不分配可执行内存的情况下执行任意代码
这个概念验证允许我们 "重新使用 "ntdll.dll中的现有指令来执行我们自己的代码。目标代码只存在于数据部分,这意味着这种方法规避了非可执行内存的保护。这种方法的一个副作用意味着它很难被调试,并绕过了静态代码分析。
有趣的是,这种技术只需要一个API - RtlAddVectoredExceptionHandler。我的代码还使用了GetModuleHandle来检索ntdll.dll的基本地址,但如果有必要,这也是一个很容易重新创建的函数。如果你有足够的创造力,你也可以通过扫描ntdll.dll来找到vectored异常处理程序列表指针,然后手动添加条目,从而消除RtlAddVectoredExceptionHandler调用。
这个代码的工作原理如下:
1. 创建一个数据结构,包含所有我们要执行的汇编指令。
2. 在ntdll.dll的代码部分搜索上述每条指令,并存储其地址。
3. 使用RtlAddVectoredExceptionHandler在我们的程序中添加一个自定义的异常处理程序。
4. 使用int 3触发一个断点。
5. 现在程序已经进入了我们的自定义异常处理程序。存储原来的线程上下文以备后用。
6. 将EIP寄存器设置为我们列表中的第一个目标指令(在ntdll.dll中)。
7. 如果当前指令是一个 "调用",使用Dr0调试寄存器在调用后的指令上设置一个硬件断点--我们要 "跨过 "调用。否则,用EFlags |= 0x100设置单步标志,在下一条指令上断开。
8. 更新当前指令所需的任何其他寄存器的值。
9. 使用EXCEPTION_CONTINUE_EXECUTION继续执行。下一条指令将引发另一个异常,我们将从第6步继续,直到所有的指令都依次运行完毕。
10. 在所有的目标指令执行完毕后,恢复步骤#5中的原始线程上下文,以继续程序的原始流程。
下面的数据结构将调用MessageBoxA:
该结构头包含以下字段:
pLabel
这个字段仅用于记录/调试的目的。
bInstruction
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!