美文网首页
HeapCreate 在进程中创建辅助堆栈 (通过线程调用)

HeapCreate 在进程中创建辅助堆栈 (通过线程调用)

作者: f675b1a02698 | 来源:发表于2017-09-13 08:28 被阅读0次

    参数1:如何在改堆栈执行操作,你可以设定0、HEAP_NO_SERIALIZE、HEAP_GENERATE_EXCEPTIONS、HEAP_CREATE_ENABLE_EXECUTE或者是这些标志的组合。

    HEAP_NO_SERIALIZE:非独占

    HEAP_GENERATE_EXCEPTIONS:分配失败时抛出异常,如果不设置则会返回NULL

    HEAP_CREATE_ENALBE_EXECUTE:堆栈内容是可执行代码,不设置则不是可执行代码

    这里的值是 1 非独占

    参数2: 初始大小 1000 4KB

    参数3: 最大大小,0为不限制? 这里设置为0

    伪代码:

    HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize){

    return API-MS-Win-Core-Heap-L1-1-0.HeapCreate;

    }

    API-MS-Win-Core-Heap-L1-1-0.HeapCreate(){

    return KernelBa.HeapCreate;

    }

    HANDLE KernelBa.HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize){

    DWORD 堆分配选项 = flOptions; c

    SIZE_T 堆的初始大小 = 0x76AF0828; a

    SIZE_T 堆的最大大小 = dwMaximumSize; d

    堆分配选项 = 0x40005 and 堆分配选项;

    堆分配选项 = 0x1000 or 堆分配选项;

    if(堆的最大大小 <= 堆的初始大小){

    if(堆的最大大小 != 0){

    堆的最大大小 = 堆的初始大小;

    }else{

    堆的初始大小 = 堆的初始大小 << 4;

    esi = 堆的初始大小;//10000

    堆分配选项 = 1001 or 2 = 1003;

    }

    }

    堆的最大大小 = 堆的初始大小;

    //这个函数只设置了 堆分配选项 的值(可能)?

    //所以初始大小和默认大小参数都可以为0

    }

    这个函数会最终调用 ntdll.RtlCreateHeap 函数,而这个函数会最终调用 ntdll_1a.76F2DEB4(ZwAllocateVirtualMemory ? -->KiSystemService -->NtAllocateVirtualMemory) 实现

    汇编分析:

    0052D200 /$ 6A 00 push 0x0 ; /MaximumSize = 0x0

    0052D202 |. 68 00100000 push 0x1000 ; |InitialSize = 1000 (4096.)

    0052D207 |. 6A 01 push 0x1 ; |Flags = HEAP_NO_SERIALIZE

    0052D209 |. FF15 D8A67D00 call dword ptr ds:[<&KERNEL32.HeapCreate>] ; \HeapCreate

    &KERNEL32.HeapCreate

    74CE4A2C 90 nop

    74CE4A2D>8BFF mov edi,edi ; 热补丁专用

    74CE4A2F 55 push ebp ;

    74CE4A30 8BEC mov ebp,esp ; 保存当前的esp栈地址

    74CE4A32 5D pop ebp ; 单人游戏.0052D20F,这5行什么都没做啊

    74CE4A33 /EB 05 jmp short

    74CE4A35 |90 nop

    74CE4A36 |90 nop

    74CE4A37 |90 nop

    74CE4A38 |90 nop

    74CE4A39 |90 nop

    74CE4A3A -\FF25 C808CE74 jmp dword ptr ds:[<&API-MS-Win-Core-Heap-L1-1-0.HeapCreate>] ; KernelBa.HeapCreate

    KernelBa.HeapCreate

    76AC4516>8BFF mov edi,edi ; 上面为啥是 int3 而不是 nop

    76AC4518 55 push ebp ; ebp压栈,然后将esp的值移动到ebp

    76AC4519 8BEC mov ebp,esp

    76AC451B 8B4D 08 mov ecx,dword ptr ss:[ebp+0x8] ; 堆栈的第一个参数 1 非独占 赋值给 ecx

    76AC451E 8B55 10 mov edx,dword ptr ss:[ebp+0x10] ; 堆栈的第三个参数 0 最大大小 赋值给 edx

    76AC4521 A1 2808AF76 mov eax,dword ptr ds:[0x76AF0828] ; 从数据段中获得第二个参数,堆栈的初始大小 1000 4KB

    76AC4526 81E1 05000400 and ecx,0x40005 ; 40005 和 00001 进行 and 运算,结果还是 1

    76AC452C 56 push esi ; esi压栈

    76AC452D 81C9 00100000 or ecx,0x1000 ; 1000 和 0001 进行 or 运算,结果为 1001

    76AC4533 33F6 xor esi,esi ; esi 清0

    76AC4535 3BD0 cmp edx,eax ; 判断 第三个参数0 - 1000第二个参数 ,然后修改标志位,结果C=1(借位)S=1(负数)

    76AC4537 73 14 jnb short KernelBa.76AC454D ; edx 不小于 eax 跳转,这里不跳

    76AC4539 85D2 test edx,edx ; 判断第三个参数是不是 0

    76AC453B 75 0A jnz short KernelBa.76AC4547 ; 如果不是0则跳转,这里不跳

    76AC453D C1E0 04 shl eax,0x4 ; eax 左移4位 = 00010000

    76AC4540 8BF0 mov esi,eax ; 将 10000 赋值给 esi

    76AC4542 83C9 02 or ecx,0x2 ; ecx or 2 = 1001 or 2 = 1003

    76AC4545 EB 02 jmp short KernelBa.76AC4549 ; 短跳转到 +4字节处

    76AC4547 8BD0 mov edx,eax ; 如果跳到这里,说明第三个参数不是0

    76AC4549 85F6 test esi,esi ; 判断esi是否是0,也就是判断第二个参数是不是0

    76AC454B 75 08 jnz short KernelBa.76AC4555 ; 如果不是0,短跳到+10字节处

    76AC454D 3955 0C cmp dword ptr ss:[ebp+0xC],edx ; 如果跳到这里,则说明第三个参数大于1000

    76AC4550 76 03 jbe short KernelBa.76AC4555 ; 如果第二个参数小于等于第三个参数 , push 0

    76AC4552 8B55 0C mov edx,dword ptr ss:[ebp+0xC] ; 第二个参数赋值到 edx ,然后 push 0

    76AC4555 6A 00 push 0x0 ; 前面4行的最终归宿都是这里 指向RTL_HEAP_PARAMETERS结构的指针

    76AC4557 6A 00 push 0x0 ; 非独占这里必须为0,lock

    76AC4559 FF75 0C push dword ptr ss:[ebp+0xC] ; 提交大小 1000

    76AC455C 52 push edx ; 保留大小,可为0.保留大小=0,提交大小非0,保留大小设置为16页大小

    76AC455D 6A 00 push 0x0 ; 堆基址,0表示系统分配,非0则分配到该地址为基址

    76AC455F 51 push ecx ; flags访问控制 1003 表示私有,可增加,非独占的heap

    76AC4560 FF15 A813AB76 call dword ptr ds:[<&ntdll.RtlCreateHeap>] ; RtlCreateHeap函数 创建一个可以由调用进程使用的堆对象

    ntdll.RtlCreateHeap

    76F40249>68 9C000000 push 0x9C

    76F4024E 68 F8C7F276 push ntdll_1a.76F2C7F8

    76F40253 E8 5CDCFEFF call ntdll_1a.76F2DEB4 ; 未导出的函数,有两个参数

    这里是第四行

    ntdll_1a.76F2DEB4

    76F2DEC0 8B4424 10 mov eax,dword ptr ss:[esp+0x10] ; 第二个参数 9C

    76F2DEC4 896C24 10 mov dword ptr ss:[esp+0x10],ebp ; ebp寄存器的值 0018FEFC (HeapCreate函数的栈基址) 移到第二个参数处

    76F2DEC8 8D6C24 10 lea ebp,dword ptr ss:[esp+0x10] ; 将esp地址18FEC8+10的地址放入ebp(HeapCreate栈基址)

    76F2DECC 2BE0 sub esp,eax ; 减去9c(156字节)的空间

    76F2DECE 53 push ebx ; 7EFDE000

    76F2DECF 56 push esi ; 10000 提交大小左移4位得到的

    76F2DED0 57 push edi ; 保留大小 0

    76F2DED1 A1 88200077 mov eax,dword ptr ds:[0x77002088] ; 将时间段地址77002088的值64A7F775赋值到eax,可能是一个函数地址

    76F2DED6 3145 FC xor dword ptr ss:[ebp-0x4],eax ; 76F2C7F8 xor 64A7F775 = 1255308D 在之前第二个参数9C处

    76F2DED9 33C5 xor eax,ebp ; 0018FED8 xor 64A7F775 = 64BF09AD eax

    76F2DEDB 50 push eax ; eax的值压栈

    76F2DEDC 8965 E8 mov dword ptr ss:[ebp-0x18],esp ; 将现在的栈指针赋值到当前堆栈的第3个参数位置处

    76F2DEDF FF75 F8 push dword ptr ss:[ebp-0x8]

    76F2DEE2 8B45 FC mov eax,dword ptr ss:[ebp-0x4] ; 将1255308D赋值到eax

    76F2DEE5 C745 FC FEFFFFFF mov dword ptr ss:[ebp-0x4],-0x2 ; 将FFFFFFFE(-2)替换到该位置

    76F2DEEC 8945 F8 mov dword ptr ss:[ebp-0x8],eax ; 将eax的值1255308D赋值到第一个参数处

    76F2DEEF 8D45 F0 lea eax,dword ptr ss:[ebp-0x10] ; 将第四个变量空间的地址0018FEC8赋值到eax

    76F2DEF2 64:A3 00000000 mov dword ptr fs:[0],eax ; 将这个地址作为teb(线程环境块)的基地址

    76F2DEF8 C3 retn ; 返回到 ntdll.RtlCreateHeap的第四行

    这里是第五行

    76F40258 E8 747BFFFF call ntdll_1a.RtlGetNtGlobalFlags ; 获取Nt全局标志?

    相关文章

      网友评论

          本文标题:HeapCreate 在进程中创建辅助堆栈 (通过线程调用)

          本文链接:https://www.haomeiwen.com/subject/ragqsxtx.html