gadgets 为小装置它代表着链上所需要的各个组成部分,ROP_chains 是利用栈与 RETN 的特性工作的,但有一点就是说用于攻击目的 rop_chains 里面的各个小装置,攻击者会想办法的从各个版本的操作系统已知公共的DLL库中提出来(指向代码的公共基址几乎是等同的),这个东西你可以称呼它为 “返回导向”
refer-originl:https://blog.csdn.net/liulilittle/article/details/80959798
下面的 demo 代码演示了具体的过程,但显然这个与真实应用到攻击上是不完全的,同时由于是自定义的程序代码它主要是用于表明 ROP_chinas 攻击是如何进行工作的,但它并不起到实际的攻击目的。
注运行以下的代码,最好是调试环境下会比较直观另一点就是说,DEP(执行数据保护)的开关是可以忽略的,ROP_chains 最大的优点就是绕过 DEP,显然你关闭了 DEP 那么测试以下代码的意义就不存在了。
同时这个 ROP_chains 比较简单,它仅仅只是调用一个 MessageBoxA 的函数打印一个 “bac” 的字符串,当客户关闭了信息框时调用 exit 函数,退出当前的进程(当然在真实攻击的情况下都会想办法的让受攻击程序不被中止,调用 ShellExecuteA 这一类函数运行 net user xxx 的类似命名改掉目标主机的登陆用户密码,或者编写重量级的 shellcode 在目标的程序中侦听端口或者注入木马后门)当然本人不是在教你搞坏事,因为我只是一名菜鸟,我们了解这些东西仅仅只是为了让我们在设计系统的时候尽可能兼顾考量这些问题。
#include <stdio.h>
#include <windows.h>void def_gadgets_1(void)
{
_asm
{
pop esi
ret
}
}void def_gadgets_2(void)
{
_asm
{
mov eax,esp
add eax,4
ret
}
}void def_gadgets_3(void)
{
_asm
{
push '\0'
push eax
push eax
push '\0'
call esi
pop esi
ret
}
}char* get_gadgets_ptr(void* f)
{
unsigned char* p = f;
if (*p == 0xE9)
{
p += (5 + *(int*)(p + 1));
}
while (1)
{
if (*p++ == 0xC3) return p;
}
}int main(int argc, char* argv[])
{
void* gadgets[] =
{
get_gadgets_ptr(&def_gadgets_1) - 0x02,
get_gadgets_ptr(&def_gadgets_2) - 0x06,
get_gadgets_ptr(&def_gadgets_3) - 0x0A,
};
void* ebpplus4addr = NULL;
_asm
{
lea eax,dword ptr[ebp+4]
mov dword ptr[ebpplus4addr],eax
}
UINT32 shellcode[5];
shellcode[0] = gadgets[0];
shellcode[1] = &MessageBoxA;
shellcode[2] = gadgets[1];
shellcode[3] = gadgets[2];
shellcode[4] = '\0' << 0x18 | 'c' << 0x10 | 'a' << 0x08 | 'b';
shellcode[5] = &exit;memcpy(ebpplus4addr, shellcode, sizeof(shellcode));
}