不久前,我偶然发现了 Mariusz Banach佬的
https:
//github.com/mgeeky/ThreadStackSpoofer
的线程堆栈欺骗技术。我想看看是否可以使用汇编 (MASM) 复制该技术,因此我开始着手进行这项工作。对于那些不了解该技术的人,可以使用以下代码从 C 中演示该技术:
void
WINAPI
MySleep
(
DWORD _dwMilliseconds
)
{
[
]
auto overwrite = (PULONG_PTR)_AddressOfReturnAddress();
const
auto origReturnAddress = *overwrite;
*overwrite =
0
;
[
]
*overwrite = origReturnAddress;
}
它将获取当前函数的返回地址并用零覆盖该值,然后在返回之前用其原始值恢复它。这有效地隐藏了上例中函数MySleep之后的任何内容的堆栈框架,并使调用堆栈看起来好像在**MySleep点被截断了。查看 C 代码,我们很可能可以用最少的努力使用汇编来复制它。但首先,我们应该对 64 位 Windows 上的堆栈有所了解。这是一张 64 位 Windows 上标准函数调用的照片。
【64 位 Windows 调用堆栈】
如你所见,在函数开始时,返回地址将位于 RSP 寄存器中。这是 上一个 C 示例中 intrin.h中_AddressOfReturnAddress()*返回的值。现在我们有了要覆盖的目标地址,我们还必须了解,在函数启动后对堆栈所做的任何更改都会使我们离堆栈上的返回地址越来越远。在函数继续执行时,它不会保留在 RSP 寄存器中,因此在汇编函数结束时恢复返回地址值时,必须牢记这个距离。如果我们没有正确地用其原始值恢复返回地址,我们将导致程序崩溃,因此正确的恢复是必要的。实际的实现可能有所不同,但一种方便的方法是将函数开头的 RSP 值复制到非易失性寄存器中以供稍后恢复,用零覆盖 RSP 的值(此时的返回地址),然后在最后从保存寄存器恢复该值。让我们演示一个例子。假设我们的汇编函数将占用 40 字节的堆栈空间,即十六进制的 28 字节。以下是我们的示例:
.CODE
Spoof PROC
mov r12, qword ptr [rsp] ; Preserve the return address in r12
mov qword ptr [rsp], 0 ; Overwrite return address
with
zero
...
40
byte
function
...
mov qword ptr [rsp +
28
h], r12 ;
Restore
the original
value
of
the
return
address
from
r12
before
returning
ret
Spoof ENDP
END
就是这样!这是一种执行线程堆栈欺骗的简单方法,您可以将其合并到用汇编语言编写的函数中。
原文始发于微信公众号(影域实验室):汇编中的简单线程堆栈欺骗
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论