6) kernel32!HeapCreate() 用IDA Pro 4.6.0.785反汇编kernel32!HeapCreate: -------------------------------------------------------------------------- 77E695F0 HeapCreate_0: ; 在这里检查第二、三形参的大小关系,修正一下 77E695F0 cmp [ebp+dwInitialSize], edx ; 77E695F0 ; if ( dwInitialSize <= dwMaximumSize ) 77E695F0 ; { 77E695F0 ; goto HeapCreate_3 77E695F0 ; } 77E695F3 jbe HeapCreate_3 77E695F3 77E695F9 jmp HeapCreate_4 77E695FE 77E695FE HeapCreate_1: ; 此时( dwMaximumSize < PageSize )且 77E695FE mov edx, ecx ; ( 0 != dwMaximumSize ) 77E695FE ; 77E695FE ; dwMaximumSize = PageSize 77E69600 jmp HeapCreate_2 77E7E2D2 ; __stdcall HeapCreate(x,x,x) 77E7E2D2 public _HeapCreate@12 77E7E2D2 _HeapCreate@12 proc near 77E7E2D2 77E7E2D2 flOptions= dword ptr 8 77E7E2D2 dwInitialSize= dword ptr 0Ch 77E7E2D2 dwMaximumSize= dword ptr 10h 77E7E2D2 77E7E2D2 push ebp ; HANDLE HeapCreate 77E7E2D2 ; ( 77E7E2D2 ; DWORD flOptions, // heap allocation attributes 77E7E2D2 ; SIZE_T dwInitialSize, // initial heap size 77E7E2D2 ; SIZE_T dwMaximumSize // maximum heap size 77E7E2D2 ; ); 77E7E2D3 mov ebp, esp 77E7E2D5 mov eax, [ebp+flOptions] ; EAX现在等于第一形参flOptions 77E7E2D8 mov ecx, _BaseStaticServerData ; 指向一个结构,这个结构定义不明 77E7E2DE mov ecx, [ecx+12Ch] ; ECX现在等于页大小 77E7E2DE ; 77E7E2DE ; > dd poi(kernel32!BaseStaticServerData)+0x12c L1 77E7E2DE ; 7f6f07cc 00001000 77E7E2DE ; 0x1000即4096,也就是一页,对于IA-32架构,这是固定值。 77E7E2DE ; 这里实际上是访问BaseStaticServerData->PageSize。 77E7E2E4 mov edx, [ebp+dwMaximumSize] ; EDX现在等于第三形参dwMaximumSize 77E7E2E7 and eax, 5 ; flOptions & ( HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS ) 77E7E2E7 ; 77E7E2E7 ; from winnt.h 77E7E2E7 ; 77E7E2E7 ; #define HEAP_NO_SERIALIZE 0x00000001 77E7E2E7 ; #define HEAP_GROWABLE 0x00000002 77E7E2E7 ; #define HEAP_GENERATE_EXCEPTIONS 0x00000004 77E7E2E7 ; #define HEAP_ZERO_MEMORY 0x00000008 77E7E2E7 ; #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 77E7E2E7 ; #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 77E7E2E7 ; #define HEAP_FREE_CHECKING_ENABLED 0x00000040 77E7E2E7 ; #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 77E7E2E7 ; #define HEAP_CREATE_ALIGN_16 0x00010000 77E7E2E7 ; #define HEAP_CREATE_ENABLE_TRACING 0x00020000 77E7E2EA push esi 77E7E2EB or eax, 1000h ; !!! 77E7E2F0 xor esi, esi 77E7E2F2 cmp edx, ecx ; if ( dwMaximumSize >= PageSize ) 77E7E2F2 ; { 77E7E2F2 ; goto HeapCreate_0 77E7E2F2 ; } 77E7E2F4 jnb HeapCreate_0 77E7E2F4 77E7E2FA test edx, edx ; if ( 0 != dwMaximumSize ) 77E7E2FA ; { 77E7E2FA ; goto HeapCreate_1 77E7E2FA ; } 77E7E2FC jnz HeapCreate_1 77E7E2FC 77E7E302 shl ecx, 4 ; 此时( 0 == dwMaximumSize ) 77E7E305 mov esi, ecx ; ECX、ESI等于PageSize * 16,但这个结果并未传递给 77E7E305 ; ntdll!RtlCreateHeap 77E7E307 or eax, 2 ; 设置HEAP_GROWABLE 77E7E30A 77E7E30A HeapCreate_2: ; 表面看来是判断ESI,往回查看,实际是这个比较 77E7E30A test esi, esi ; 77E7E30A ; if ( 0 < dwMaximumSize < PageSize ) 77E7E30A ; { 77E7E30A ; goto HeapCreate_0 77E7E30A ; } 77E7E30C jz HeapCreate_0 77E7E30C 77E7E312 77E7E312 HeapCreate_3: ; 指针型变量 77E7E312 push 0 77E7E314 push 0 ; 指针型变量 77E7E316 push [ebp+dwInitialSize] ; 原第二形参 77E7E319 push edx ; 修正过的第三形参 77E7E31A push 0 ; 指针型变量 77E7E31C push eax ; 修正过的第一形参 77E7E31D call ds:__imp__RtlCreateHeap@24 ; 调用ntdll!RtlCreateHeap(x,x,x,x,x,x) 77E7E31D 77E7E323 mov esi, eax 77E7E325 test esi, esi ; if ( NULL == RtlCreateHeap(x,x,x,x,x,x) ) 77E7E325 ; { 77E7E325 ; goto HeapCreate_5 77E7E325 ; } 77E7E327 jz HeapCreate_5 77E7E327 77E7E32D 77E7E32D HeapCreate_exit: ; 流程到达此处时要求ESI等于堆句柄或者NULL 77E7E32D mov eax, esi 77E7E32F pop esi 77E7E330 pop ebp 77E7E331 retn 0Ch 77E7E331 77E7E331 _HeapCreate@12 endp 77E9DA3C HeapCreate_4: ; dwMaximumSize = dwInitialSize 77E9DA3C mov edx, [ebp+dwInitialSize] 77E9DA3F jmp HeapCreate_3 77E9DA3F 77E9DA44 HeapCreate_5: ; ERROR_NOT_ENOUGH_MEMORY 77E9DA44 push 8 77E9DA46 call _SetLastError@4 ; SetLastError( ERROR_NOT_ENOUGH_MEMORY ) 77E9DA46 77E9DA4B jmp HeapCreate_exit -------------------------------------------------------------------------- 下面是C风格的伪代码: -------------------------------------------------------------------------- /* * 这是kernel32.dll中定义的一个全局变量,结构指针,但struct xxx是什么结构 * 呢 */ extern struct xxx *BaseStaticServerData; HANDLE HeapCreate ( DWORD flOptions, // heap allocation attributes SIZE_T dwInitialSize, // initial heap size SIZE_T dwMaximumSize // maximum heap size ) { HANDLE ret; DWORD PageSize, Options; SIZE_T MaximumSize; Options = flOptions; /* * +0x12c DWORD PageSize; * * 对于IA-32架构,这是固定值,4096/0x1000字节。 */ PageSize = BaseStaticServerData->PageSize; MaximumSize = dwMaximumSize; /* * 做为Win32 API,只允许设置这两个标志。 */ Options &= ( HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS ); /* * !!! */ Options |= 0x00001000; if ( MaximumSize >= PageSize ) { /* * 在这里检查第二、三形参的大小关系,修正一下 */ if ( dwInitialSize > MaximumSize ) { MaximumSize = dwInitialSize; } } else { /* * 0 < MaximumSize < PageSize */ if ( 0 != MaximumSize ) { MaximumSize = PageSize; if ( dwInitialSize > MaximumSize ) { MaximumSize = dwInitialSize; } } /* * 0 == MaximumSize,可增长的堆 */ else { Options |= HEAP_GROWABLE; } } /* * 调用ntdll!RtlCreateHeap() */ ret = RtlCreateHeap ( Options, NULL, MaximumSize, dwInitialSize, NULL, NULL ); if ( NULL == ret ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); } return( ret ); } /* end of HeapCreate */ -------------------------------------------------------------------------- 在汇编指令中出现过"PageSize * 16"这样的值,但这个值并未影响最终分配,是否 属于微软程序员的低级错误。