VirtualFree函数逆向分析
函数说明
将内存状态从“已提交的”变为“保留的”,或将“保留的”变为“空闲的”,或同时进行,此函数用于进行 VirtualAlloc 的反向工作。
函数签名如下:
BOOL __stdcall VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)****
参数说明
lpAddress:输入参数,需要改变状态的内存区域的起始地址。
dwSize:输入参数,需要改变状态的内存区域的大小,以字节为单位。
dwFreeType:输入参数,如果此参数设置为 MEM__ DECOMMIT,则将内存变为保留状态,当 dwSize 参数为 0,则 lpAddress 参数必须为内存区域的起始地址(VirtualAlloc 的返回值),将整个区域设置为保留状态。如果此参数设置为 MEM RELEASE,则释放内存,将内存直接变为空闲状态,不管当前是处理保留状态还是已提交状态。如果设置为 MEM_RELEASE,dwSize 参数必须为 0,则 lpAddress 参数必须为内存区域的起始地址(Virtual_Alloc 的返回值)。两个值不能一起使用。
◇返回值
返回 BOOL 类型的值,表示执行是否成功。如果表示失败。可使用 GetLastError 函数获取错误信息。
Kernel32.dll中的代码分析
代码如下:
; BOOL __stdcall VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
.text:77E59E34 public VirtualFree
.text:77E59E34 VirtualFree proc near ; CODE XREF: FreeVirtualBuffer+D↓p
.text:77E59E34 ; CreateVirtualBuffer+2389D↓p ...
.text:77E59E34
.text:77E59E34 lpAddress = dword ptr 8
.text:77E59E34 dwSize = dword ptr 0Ch
.text:77E59E34 dwFreeType = dword ptr 10h
.text:77E59E34
.text:77E59E34 push ebp
.text:77E59E35 mov ebp, esp
.text:77E59E37 push [ebp+dwFreeType] ; dwFreeType
.text:77E59E3A push [ebp+dwSize] ; dwSize
.text:77E59E3D push [ebp+lpAddress] ; lpAddress
.text:77E59E40 push 0FFFFFFFFh ; hProcess
.text:77E59E42 call VirtualFreeEx
.text:77E59E47 pop ebp
.text:77E59E48 retn 0Ch
.text:77E59E48 VirtualFree endp
通过上述代码可以看出virtualfree的流程和virtualalloc的流程似乎大致相同也是调用的他的扩展函数virtualfreeex并传入自身进程句柄
下面看一下virtualfreeex函数代码
; BOOL __stdcall VirtualFreeEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
.text:77E59E4B public VirtualFreeEx
.text:77E59E4B VirtualFreeEx proc near ; CODE XREF: VirtualFree+E↑p
.text:77E59E4B ; DATA XREF: .text:off_77E62168↓o
.text:77E59E4B
.text:77E59E4B hProcess = dword ptr 8
.text:77E59E4B lpAddress = dword ptr 0Ch
.text:77E59E4B dwSize = dword ptr 10h
.text:77E59E4B arg_D = byte ptr 15h
.text:77E59E4B
.text:77E59E4B ; FUNCTION CHUNK AT .text:77E4D5FA SIZE 00000025 BYTES
.text:77E59E4B ; FUNCTION CHUNK AT .text:77E82756 SIZE 00000042 BYTES
.text:77E59E4B
.text:77E59E4B push ebp
.text:77E59E4C mov ebp, esp
.text:77E59E4E test [ebp+arg_D], 80h
.text:77E59E52 jz short loc_77E59E5E
.text:77E59E54 cmp [ebp+dwSize], 0
.text:77E59E58 jnz loc_77E82756
.text:77E59E5E
.text:77E59E5E loc_77E59E5E: ; CODE XREF: VirtualFreeEx+7↑j
.text:77E59E5E push esi
.text:77E59E5F mov esi, ds:NtFreeVirtualMemory
.text:77E59E65 push edi
.text:77E59E66 push dword ptr [ebp+14h] ; FreeType
.text:77E59E69 lea eax, [ebp+dwSize]
.text:77E59E6C push eax ; RegionSize
.text:77E59E6D lea eax, [ebp+lpAddress]
.text:77E59E70 push eax ; BaseAddress
.text:77E59E71 push [ebp+hProcess] ; ProcessHandle
.text:77E59E74 call esi ; NtFreeVirtualMemory
.text:77E59E76 mov edi, eax
.text:77E59E78 test edi, edi
.text:77E59E7A jl loc_77E4D5FA
.text:77E59E80
.text:77E59E80 loc_77E59E80: ; CODE XREF: VirtualFreeEx-C834↑j
.text:77E59E80 xor eax, eax
.text:77E59E82 inc eax
.text:77E59E83
.text:77E59E83 loc_77E59E83: ; CODE XREF: VirtualFreeEx-C83D↑j
.text:77E59E83 pop edi
.text:77E59E84 pop esi
.text:77E59E85
.text:77E59E85 loc_77E59E85: ; CODE XREF: VirtualFreeEx+28917↓j
.text:77E59E85 pop ebp
.text:77E59E86 retn 10h
.text:77E59E86 VirtualFreeEx endp
virtualfreeex的代码稍微多了一点,不够流程却很简单
- 校验hprocess参数是否传入,如果没有传入则直接返回失败
- 压入参数并调用NtFreeVirtualMemory函数
ntdll.dll中的代码分析
跟分析virtualalloc时候一样,通过导入表可以看到NtFreeVirtualMemory函数依旧是来自ntdell.dll并通过ntdll.dll的导出表找到这个函数的具体实现:
7E8E3 public ZwFreeVirtualMemory
.text:77F7E8E3 ZwFreeVirtualMemory proc near ; CODE XREF: sub_77F53D31+14↑p
.text:77F7E8E3 ; RtlDestroyEnvironment+1E↑p ...
.text:77F7E8E3 mov eax, 53h ; 'S' ; NtFreeVirtualMemory
.text:77F7E8E8 mov edx, 7FFE0300h
.text:77F7E8ED call edx
.text:77F7E8EF retn 10h
.text:77F7E8EF ZwFreeVirtualMemory endp
这次调用的系统服务号为53,依旧通过**_KUSER_SHARED_DATA**内核数据结构+300偏移的位置通过快速调用进入具体的内核实现(具体0环到3环以及保存现场的原理在我其他的笔记中有详细描述)
我们直接通过ssdt表来找到内核实现
kd> dd KeServiceDescriptorTable
80545c00 804fd624 00000000 0000011c 804fda98
80545c10 00000000 00000000 00000000 00000000
80545c20 00000000 00000000 00000000 00000000
80545c30 00000000 00000000 00000000 00000000
80545c40 00002710 bf87e0dc 00000000 00000000
80545c50 81dbc0f0 806c6720 00000000 00000000
80545c60 cd3513a3 00000003 a96cc3e3 01d8f354
80545c70 00000000 00000000 00000000 00000000
我们直接看第一个数据结构(第一个为内核函数的服务表导出结构)
804fd624 00000000 0000011c 804fda98 对应:函数地址表,null,函数个数,函数参数表
函数地址表中存储的地址每个占用4个byte所以 所要找的函数地址=函数地址表的首地址+4*函数调用号
804fd624+4*11h
通过windbg查看可以得出如下结果
kd> dd KeServiceDescriptorTable
80545c00 804fd624 00000000 0000011c 804fda98
80545c10 00000000 00000000 00000000 00000000
80545c20 00000000 00000000 00000000 00000000
80545c30 00000000 00000000 00000000 00000000
80545c40 00002710 00000000 00000000 00000000
80545c50 806c6720 806c6720 00000000 00000000
80545c60 00000000 00000000 e9ad72c0 01d8f402
80545c70 00000000 00000000 00000000 00000000
kd> dd 804fd624+4*53
804fd770 8057f36e 8057d130 805a7880 80606081
804fd780 8054d018 80528855 8055835f 80565477
804fd790 805608ef 805a44ad 80605e8a 80608b14
804fd7a0 80606073 805a41ae 805a84a9 805a0701
804fd7b0 805a0713 8056045e 805a1434 8059defc
804fd7c0 805acb4b 805b7da3 805b7cc1 80601438
804fd7d0 806019d2 8057748d 8061c934 80560ca7
804fd7e0 80558b10 80564aa0 8057ebd7 8056835c
kd> u 8057f36e
nt!NtFreeVirtualMemory:
8057f36e 6880000000 push 80h
8057f373 6858e84f80 push offset nt!FsRtlLegalAnsiCharacterArray+0xca0 (804fe858)
8057f378 e8d706f9ff call nt!strstr+0x80 (8050fa54)
8057f37d 8b4d14 mov ecx,dword ptr [ebp+14h]
8057f380 f7c1ff3fffff test ecx,0FFFF3FFFh
8057f386 0f8564ba0100 jne nt!IoInitializeRemoveLockEx+0x601 (8059adf0)
8057f38c b800c00000 mov eax,0C000h
8057f391 23c8 and ecx,eax
ntoskrn.exe中的代码分析
NtFreeVirtualMemory的签名如下:
__kernel_entry NTSYSCALLAPI NTSTATUS NtFreeVirtualMemory(
[in] HANDLE ProcessHandle,
[in, out] PVOID *BaseAddress,
[in, out] PSIZE_T RegionSize,
[in] ULONG FreeType
);
看上去好像参数列表和我们在用户层调用的virtualfreeex是一样的
在看内核具体实现之前先来根据前一篇笔记对virtualalloc函数内核实现分析的经验猜测一下这个函数的流程:
- 首先依旧应该是参数校验
- 其次因为Windows内存管理的结构可以猜测依旧是根据processhandle来找到具体的内核_EPROCESS对象
- 用EPROCESS中的vadroot查找到baseaddress所对应的树节点修改其中的信息
- 如果是release属性的话就应该要我们要考虑一下是内核是立马到teb中删除页并且在物理内存管理的list中将对应的物理内存改为可用还是仅仅只到第3步的修改虚拟内存管理的树中的信息就反回其余的后续在做
具体的内核代码如下:
PAGE:004AE36E
PAGE:004AE36E
PAGE:004AE36E ; NTSTATUS __stdcall NtFreeVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize, ULONG FreeType)
PAGE:004AE36E public NtFreeVirtualMemory
PAGE:004AE36E NtFreeVirtualMemory proc near ; DATA XREF: .text:0042C770↑o
PAGE:004AE36E ; .edata:off_5823A8↓o
PAGE:004AE36E
PAGE:004AE36E ProcessHandle = dword ptr 4
PAGE:004AE36E BaseAddress = dword ptr 8
PAGE:004AE36E RegionSize = dword ptr 0Ch
PAGE:004AE36E FreeType = dword ptr 10h
PAGE:004AE36E
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:0047DC3B SIZE 0000000C BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:004842E0 SIZE 00000024 BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:0048432B SIZE 00000014 BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:00485211 SIZE 0000000C BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:0049DAFA SIZE 0000002F BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:0049E606 SIZE 0000010E BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:004B2DD2 SIZE 00000008 BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:004C9CA9 SIZE 0000002E BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:004C9DA9 SIZE 0000012E BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:004DA8F0 SIZE 0000000B BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:005011D4 SIZE 000000A4 BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:0050127D SIZE 0000006E BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:005012F1 SIZE 00000039 BYTES
PAGE:004AE36E ; FUNCTION CHUNK AT PAGE:00501336 SIZE 0000001A BYTES
PAGE:004AE36E
PAGE:004AE36E push 80h ; '€'
PAGE:004AE373 push offset dword_42D858
PAGE:004AE378 call sub_43EA54
PAGE:004AE37D mov ecx, [ebp+14h]
PAGE:004AE380 test ecx, 0FFFF3FFFh
PAGE:004AE386 jnz loc_4C9DF0
PAGE:004AE38C mov eax, 0C000h
PAGE:004AE391 and ecx, eax
PAGE:004AE393 jz loc_4C9DF0
PAGE:004AE399 cmp ecx, eax
PAGE:004AE39B jz loc_4C9DF0
PAGE:004AE3A1 mov eax, large fs:124h
PAGE:004AE3A7 mov esi, [eax+44h]
PAGE:004AE3AA mov [ebp-1Ch], esi
PAGE:004AE3AD mov al, [eax+140h]
PAGE:004AE3B3 mov [ebp-20h], al
PAGE:004AE3B6 xor ebx, ebx
PAGE:004AE3B8 mov [ebp-4], ebx
PAGE:004AE3BB test al, al
PAGE:004AE3BD mov eax, [ebp+0Ch]
PAGE:004AE3C0 jz loc_4B2DD2
PAGE:004AE3C6 mov ecx, MmUserProbeAddress
PAGE:004AE3CC cmp eax, ecx
PAGE:004AE3CE jnb loc_5011D4
PAGE:004AE3D4
PAGE:004AE3D4 loc_4AE3D4: ; CODE XREF: NtFreeVirtualMemory+52E68↓j
PAGE:004AE3D4 mov ecx, [eax]
PAGE:004AE3D6 mov [eax], ecx
PAGE:004AE3D8 mov edx, [ebp+10h]
PAGE:004AE3DB mov ecx, MmUserProbeAddress
PAGE:004AE3E1 cmp edx, ecx
PAGE:004AE3E3 jnb loc_5011DB
PAGE:004AE3E9
PAGE:004AE3E9 loc_4AE3E9: ; CODE XREF: NtFreeVirtualMemory+52E6F↓j
PAGE:004AE3E9 mov ecx, [edx]
PAGE:004AE3EB mov [edx], ecx
PAGE:004AE3ED
PAGE:004AE3ED loc_4AE3ED: ; CODE XREF: NtFreeVirtualMemory+4A67↓j
PAGE:004AE3ED mov eax, [eax]
PAGE:004AE3EF mov [ebp-24h], eax
PAGE:004AE3F2 mov edi, [edx]
PAGE:004AE3F4 mov [ebp-28h], edi
PAGE:004AE3F7 or dword ptr [ebp-4], 0FFFFFFFFh
PAGE:004AE3FB mov ecx, MmHighestUserAddress
PAGE:004AE401 cmp eax, ecx
PAGE:004AE403 ja loc_5011E2
PAGE:004AE409 sub ecx, eax
PAGE:004AE40B cmp ecx, edi
PAGE:004AE40D jb loc_5011EC
PAGE:004AE413 lea edi, [edi+eax-1]
PAGE:004AE417 or edi, 0FFFh
PAGE:004AE41D mov [ebp-2Ch], edi
PAGE:004AE420 and eax, 0FFFFF000h
PAGE:004AE425 mov [ebp-30h], eax
PAGE:004AE428 mov [ebp-34h], ebx
PAGE:004AE42B cmp dword ptr [ebp+8], 0FFFFFFFFh
PAGE:004AE42F jnz loc_5011F6
PAGE:004AE435 mov [ebp-38h], esi
PAGE:004AE438
PAGE:004AE438 loc_4AE438: ; CODE XREF: NtFreeVirtualMemory+52EB1↓j
PAGE:004AE438 ; NtFreeVirtualMemory+52EC8↓j
PAGE:004AE438 mov [ebp-58h], ebx
PAGE:004AE43B lea ecx, [esi+0F0h] ; FastMutex
PAGE:004AE441 mov [ebp-5Ch], ecx
PAGE:004AE444 call ds:ExAcquireFastMutex
PAGE:004AE44A test byte ptr [esi+248h], 20h
PAGE:004AE451 jnz loc_50123B
PAGE:004AE457 mov ecx, [ebp-30h]
PAGE:004AE45A call sub_41E647
PAGE:004AE45F mov ebx, eax
PAGE:004AE461 test ebx, ebx
PAGE:004AE463 jz loc_49DAFA
PAGE:004AE469 mov [ebp-64h], edi
PAGE:004AE46C shr dword ptr [ebp-64h], 0Ch
PAGE:004AE470 mov ecx, [ebx+4]
PAGE:004AE473 cmp ecx, [ebp-64h]
PAGE:004AE476 jb loc_501247
PAGE:004AE47C mov eax, [ebx+14h]
PAGE:004AE47F test eax, eax
PAGE:004AE481 jns loc_47DC3B
PAGE:004AE487 test eax, 80000h
PAGE:004AE48C jnz loc_47DC3B
PAGE:004AE492 test eax, offset __ImageBase
PAGE:004AE497 jnz loc_4842E0
PAGE:004AE49D
PAGE:004AE49D loc_4AE49D: ; CODE XREF: NtFreeVirtualMemory-2A06F↑j
PAGE:004AE49D and dword ptr [ebp-68h], 0
PAGE:004AE4A1 mov ecx, ebx
PAGE:004AE4A3 call sub_4A35E8
PAGE:004AE4A8 mov [ebp-6Ch], eax
PAGE:004AE4AB mov ecx, ebx
PAGE:004AE4AD call sub_4A6DEB
PAGE:004AE4B2 mov [ebp-70h], eax
PAGE:004AE4B5 test byte ptr [ebp+15h], 80h
PAGE:004AE4B9 jz loc_49E606
PAGE:004AE4BF cmp dword ptr [ebp-28h], 0
PAGE:004AE4C3 jnz loc_4AE5BA
PAGE:004AE4C9 mov eax, [ebx]
PAGE:004AE4CB mov ecx, [ebp-24h]
PAGE:004AE4CE shr ecx, 0Ch
PAGE:004AE4D1 cmp ecx, eax
PAGE:004AE4D3 jnz loc_485211
PAGE:004AE4D9 shl eax, 0Ch
PAGE:004AE4DC mov [ebp-30h], eax
PAGE:004AE4DF mov edi, [ebx+4]
PAGE:004AE4E2 shl edi, 0Ch
PAGE:004AE4E5 or edi, 0FFFh
PAGE:004AE4EB
PAGE:004AE4EB loc_4AE4EB: ; CODE XREF: NtFreeVirtualMemory+260↓j
PAGE:004AE4EB lea ecx, [esi+0CCh]
PAGE:004AE4F1 mov [ebp-74h], ecx
PAGE:004AE4F4 call ExAcquireFastMutexUnsafe
PAGE:004AE4F9 mov byte ptr [esi+255h], 88h
PAGE:004AE500 mov eax, [ebx+14h]
PAGE:004AE503 test eax, 200000h
PAGE:004AE508 jnz loc_501253
PAGE:004AE50E test eax, 800000h
PAGE:004AE513 jnz loc_50126C
PAGE:004AE519
PAGE:004AE519 loc_4AE519: ; CODE XREF: NtFreeVirtualMemory+52EF9↓j
PAGE:004AE519 ; NtFreeVirtualMemory+52F05↓j
PAGE:004AE519 push ebx
PAGE:004AE51A call sub_4A6E15
PAGE:004AE51F
PAGE:004AE51F loc_4AE51F: ; CODE XREF: NtFreeVirtualMemory+2B5↓j
PAGE:004AE51F ; PAGE:00501278↓j
PAGE:004AE51F push dword ptr [ebp-70h]
PAGE:004AE522 push dword ptr [ebp-6Ch]
PAGE:004AE525 push esi
PAGE:004AE526 push edi
PAGE:004AE527 push dword ptr [ebp-30h]
PAGE:004AE52A call sub_4A6EDA
PAGE:004AE52F push edi ; NewIrql
PAGE:004AE530 push dword ptr [ebp-30h] ; int
PAGE:004AE533 cmp dword ptr [ebp-68h], 1
PAGE:004AE537 jz loc_5012BC
PAGE:004AE53D call sub_424A3E
PAGE:004AE542
PAGE:004AE542 loc_4AE542: ; CODE XREF: NtFreeVirtualMemory+52F53↓j
PAGE:004AE542 and byte ptr [esi+255h], 0
PAGE:004AE549 mov ecx, [ebp-74h]
PAGE:004AE54C call ExReleaseFastMutexUnsafe
PAGE:004AE551 sub edi, [ebp-30h]
PAGE:004AE554 inc edi
PAGE:004AE555 sub [esi+0B0h], edi
PAGE:004AE55B mov eax, [ebp-58h]
PAGE:004AE55E sub [esi+0A8h], eax
PAGE:004AE564 lea ecx, [esi+0F0h] ; FastMutex
PAGE:004AE56A call ds:ExReleaseFastMutex
PAGE:004AE570 cmp dword ptr [ebp-58h], 0
PAGE:004AE574 jnz loc_4C9CA9
PAGE:004AE57A test ebx, ebx
PAGE:004AE57C jz short loc_4AE586
PAGE:004AE57E push 0 ; Tag
PAGE:004AE580 push ebx ; P
PAGE:004AE581 call ExFreePoolWithTag
PAGE:004AE586
PAGE:004AE586 loc_4AE586: ; CODE XREF: NtFreeVirtualMemory+20E↑j
PAGE:004AE586 ; NtFreeVirtualMemory+1B95E↓j ...
PAGE:004AE586 xor ebx, ebx
PAGE:004AE588 inc ebx
PAGE:004AE589 cmp [ebp-34h], ebx
PAGE:004AE58C jz loc_5012D1
PAGE:004AE592
PAGE:004AE592 loc_4AE592: ; CODE XREF: NtFreeVirtualMemory+52F6C↓j
PAGE:004AE592 cmp dword ptr [ebp+8], 0FFFFFFFFh
PAGE:004AE596 jnz loc_5012DF
PAGE:004AE59C
PAGE:004AE59C loc_4AE59C: ; CODE XREF: NtFreeVirtualMemory+52F78↓j
PAGE:004AE59C mov [ebp-4], ebx
PAGE:004AE59F mov eax, [ebp+10h]
PAGE:004AE5A2 mov [eax], edi
PAGE:004AE5A4 mov eax, [ebp-30h]
PAGE:004AE5A7
PAGE:004AE5A7 loc_4AE5A7: ; CODE XREF: NtFreeVirtualMemory-FC5F↑j
PAGE:004AE5A7 mov ecx, [ebp+0Ch]
PAGE:004AE5AA mov [ecx], eax
PAGE:004AE5AC
PAGE:004AE5AC loc_4AE5AC: ; CODE XREF: sub_5012EF+42↓j
PAGE:004AE5AC or dword ptr [ebp-4], 0FFFFFFFFh
PAGE:004AE5B0 xor eax, eax
PAGE:004AE5B2
PAGE:004AE5B2 loc_4AE5B2: ; CODE XREF: NtFreeVirtualMemory-1084A↑j
PAGE:004AE5B2 ; NtFreeVirtualMemory+1BA87↓j ...
PAGE:004AE5B2 call sub_43EA8D
PAGE:004AE5B7 retn 10h
PAGE:004AE5BA ; ---------------------------------------------------------------------------
PAGE:004AE5BA
PAGE:004AE5BA loc_4AE5BA: ; CODE XREF: NtFreeVirtualMemory+155↑j
PAGE:004AE5BA mov eax, [ebp-30h]
PAGE:004AE5BD shr eax, 0Ch
PAGE:004AE5C0 cmp eax, [ebx]
PAGE:004AE5C2 jnz loc_4C9DFA
PAGE:004AE5C8 mov eax, [ebp-64h]
PAGE:004AE5CB cmp eax, [ebx+4]
PAGE:004AE5CE jz loc_4AE4EB
PAGE:004AE5D4 test byte ptr [ebx+16h], 0A0h
PAGE:004AE5D8 jnz loc_485211
PAGE:004AE5DE lea ecx, [esi+0CCh]
PAGE:004AE5E4 mov [ebp-74h], ecx
PAGE:004AE5E7 call ExAcquireFastMutexUnsafe
PAGE:004AE5EC mov byte ptr [esi+255h], 88h
PAGE:004AE5F3 push esi
PAGE:004AE5F4 push ebx
PAGE:004AE5F5 push edi
PAGE:004AE5F6 push dword ptr [ebp-30h]
PAGE:004AE5F9 call sub_4C9D0F
PAGE:004AE5FE mov [ebp-58h], eax
PAGE:004AE601 lea eax, [edi+1]
PAGE:004AE604 shr eax, 0Ch
PAGE:004AE607 mov [ebx], eax
PAGE:004AE609 mov eax, [ebx+14h]
PAGE:004AE60C mov ecx, eax
PAGE:004AE60E sub ecx, [ebp-58h]
PAGE:004AE611 xor ecx, eax
PAGE:004AE613 and ecx, 7FFFFh
PAGE:004AE619 xor ecx, eax
PAGE:004AE61B mov [ebx+14h], ecx
PAGE:004AE61E mov [ebp-70h], ebx
PAGE:004AE621
PAGE:004AE621 loc_4AE621: ; CODE XREF: NtFreeVirtualMemory+1BB64↓j
PAGE:004AE621 xor ebx, ebx
PAGE:004AE623 jmp loc_4AE51F
这里先不做分析,明天下班后在把分析贴上来