Reverse Engineering VirtualAlloc 04-19-2019, 10:51 AM
#1
Didn't find any sections for reverse engineering, I hope here is ok.
The tools you are gonna need is a text editor and debugger or disassembler. I'm gonna use WINDBG.
First we need to find out where is VirtualAllocal
Default conversation for WIN32 is STDCALL defined as WINAPI, STDCALL arguments are pushed from right to left, witch means the they are stored backwards
We see one function (_imp__NtAllocateVirtualMemory) from the Nt* family, The functions from Nt* and Zw* are NTAPI witch on x86 are STDCALL and on x64 are FASTCALL, we are wokring on x86 so we are gonna ignore FASTCALL.
VirtualAlloc takes 4 arguments, after the call this is how the stack should look
ESP + 0 RETURN ADDRESS
ESP + 4 lpAddress
ESP + 8 dwSize
EPP + C flAllocationType
ESP + 10 flProtect
The first instructions we see are the stack frame setting up, witch will move our arguments by 4 bytes
This is our new arguments offsets
EBP + 4 RETURN ADDRESS
EBP + 8 lpAddress
EBP + C dwSize
EBP + 10 flAllocationType
EBP + 14 flProtect
After this we see
Might be to align the stack, not sure. ignore it
Lets just look the code and see what is happending, I recommend disassembling sections of the code by splitting them by JMP. If that makes sence.
KERNELBASE!SysInfo is unknown, but looking up KERNELBASE!SysInfo+0x18 we see 0x0010000, this has to be the minimal address that can be allocated
If lpAddress is 0 or is greater or equal to 0x0010000
This is what we got
Since the error code is passed to ECX, we can see that KERNELBASE!BaseSetLastNTError is FASTCALL, arguments are passed this way: ECX, EDX and the rest are pushed to the stack from right to left
Ok! We are done! Now we can create a prototype
If there are some errors or question ask
The tools you are gonna need is a text editor and debugger or disassembler. I'm gonna use WINDBG.
First we need to find out where is VirtualAllocal
Code:
0:000> x kernel32!VirtualAlloc
0:000> x kernelbase!VirtualAlloc
76277060 KERNELBASE!VirtualAlloc (void)
Code:
KERNELBASE!VirtualAlloc:
76277060 8bff mov edi,edi
76277062 55 push ebp
76277063 8bec mov ebp,esp
76277065 51 push ecx
76277066 51 push ecx
76277067 8b450c mov eax,dword ptr [ebp+0Ch]
7627706a 8945f8 mov dword ptr [ebp-8],eax
7627706d 8b4508 mov eax,dword ptr [ebp+8]
76277070 8945fc mov dword ptr [ebp-4],eax
76277073 56 push esi
76277074 85c0 test eax,eax
76277076 740c je KERNELBASE!VirtualAlloc+0x24 (76277084)
76277078 3b05b8573276 cmp eax,dword ptr [KERNELBASE!SysInfo+0x18 (763257b8)]
7627707e 0f829aa00200 jb KERNELBASE!VirtualAlloc+0x2a0be (762a111e)
76277084 ff7514 push dword ptr [ebp+14h]
76277087 8b4510 mov eax,dword ptr [ebp+10h]
7627708a 33f6 xor esi,esi
7627708c 83e0c0 and eax,0FFFFFFC0h
7627708f 50 push eax
76277090 8d45f8 lea eax,[ebp-8]
76277093 50 push eax
76277094 56 push esi
76277095 8d45fc lea eax,[ebp-4]
76277098 50 push eax
76277099 6aff push 0FFFFFFFFh
7627709b ff153c873276 call dword ptr [KERNELBASE!_imp__NtAllocateVirtualMemory (7632873c)]
762770a1 85c0 test eax,eax
762770a3 780c js KERNELBASE!VirtualAlloc+0x51 (762770b1)
762770a5 8b75fc mov esi,dword ptr [ebp-4]
762770a8 8bc6 mov eax,esi
762770aa 5e pop esi
762770ab 8be5 mov esp,ebp
762770ad 5d pop ebp
762770ae c21000 ret 10h
762770b1 8bc8 mov ecx,eax
762770b3 e86854ffff call KERNELBASE!BaseSetLastNTError (7626c520)
762770b8 ebee jmp KERNELBASE!VirtualAlloc+0x48 (762770a8)
762770ba cc int 3
762770bb cc int 3
762770bc cc int 3
762770bd cc int 3
762770be cc int 3
762770bf cc int 3
KERNELBASE!VirtualAlloc+0x2a0be:
762a111e 6a57 push 57h
762a1120 ff15c8803276 call dword ptr [KERNELBASE!_imp__RtlSetLastWin32Error (763280c8)]
762a1126 33f6 xor esi,esi
762a1128 e97b5ffdff jmp KERNELBASE!VirtualAlloc+0x48 (762770a8) Branch
Default conversation for WIN32 is STDCALL defined as WINAPI, STDCALL arguments are pushed from right to left, witch means the they are stored backwards
We see one function (_imp__NtAllocateVirtualMemory) from the Nt* family, The functions from Nt* and Zw* are NTAPI witch on x86 are STDCALL and on x64 are FASTCALL, we are wokring on x86 so we are gonna ignore FASTCALL.
VirtualAlloc takes 4 arguments, after the call this is how the stack should look
ESP + 0 RETURN ADDRESS
ESP + 4 lpAddress
ESP + 8 dwSize
EPP + C flAllocationType
ESP + 10 flProtect
The first instructions we see are the stack frame setting up, witch will move our arguments by 4 bytes
Code:
76277062 55 push ebp
76277063 8bec mov ebp,esp
EBP + 4 RETURN ADDRESS
EBP + 8 lpAddress
EBP + C dwSize
EBP + 10 flAllocationType
EBP + 14 flProtect
After this we see
Code:
76277065 51 push ecx
76277066 51 push ecx
Lets just look the code and see what is happending, I recommend disassembling sections of the code by splitting them by JMP. If that makes sence.
Code:
76277067 8b450c mov eax,dword ptr [ebp+0Ch] // eax = parameter dwSize
7627706a 8945f8 mov dword ptr [ebp-8],eax // store dwSize in local
7627706d 8b4508 mov eax,dword ptr [ebp+8] // eax = parameter lpAddress
76277070 8945fc mov dword ptr [ebp-4],eax // store lpAddress in local
76277073 56 push esi // saves ESI so it cannot be destroyed
76277074 85c0 test eax,eax // eax (lpAddress) == NULL
76277076 740c je lpAddress_geq_0010000_or_eq_0
Code:
lpAddress_neq_null
76277078 3b05b8573276 cmp eax,dword ptr [KERNELBASE!SysInfo+0x18 (763257b8)] // Minimal base address
7627707e 0f829aa00200 jb lpAddress_IS_null_error // lpAddress < 0x10000
lpAddress_neq_null_error:
762a111e 6a57 push 57h // ERROR_INVALID_PARAMETER
762a1120 ff15c8803276 call dword ptr [KERNELBASE!_imp__RtlSetLastWin32Error (763280c8)]
762a1126 33f6 xor esi,esi // return value
762a1128 e97b5ffdff jmp return_from_function
Code:
lpAddress_geq_0010000_or_eq_0:
76277084 ff7514 push dword ptr [ebp+14h] // passing argument flProtect
76277087 8b4510 mov eax,dword ptr [ebp+10h] // flAllocationType
7627708a 33f6 xor esi,esi // esi = 0
7627708c 83e0c0 and eax,0FFFFFFC0h
7627708f 50 push eax // passing argument flAllocationType & 0xFFFFFFC0
76277090 8d45f8 lea eax,[ebp-8]
76277093 50 push eax // passing argument the address of our local dwSize
76277094 56 push esi // passing argument 0
76277095 8d45fc lea eax,[ebp-4]
76277098 50 push eax // passing argument the address of our local lpAddress
76277099 6aff push 0FFFFFFFFh // passing argument -1 is NtCurrentProcess()
7627709b ff153c873276 call dword ptr [KERNELBASE!_imp__NtAllocateVirtualMemory (7632873c)]
Code:
NtAllocateVirtualMemory(
NtCurrentProcess(),
&lpAddressLocal,
0,
&dwSizeLocal,
flAllocationType & 0xFFFFFFC0,
flProtect
)
Code:
7627709b ff153c873276 call dword ptr [KERNELBASE!_imp__NtAllocateVirtualMemory (7632873c)]
762770a1 85c0 test eax,eax
762770a3 780c js NtAllocateVirtualMemory_failed // is bit 31 set, !NT_SUCCESS(X)
NtAllocateVirtualMemory_success:
762770a5 8b75fc mov esi,dword ptr [ebp-4] // lpAddress in local // return value
return_from_function:
762770a8 8bc6 mov eax,esi
762770aa 5e pop esi
762770ab 8be5 mov esp,ebp
762770ad 5d pop ebp
762770ae c21000 ret 10h // arguments size
Code:
NtAllocateVirtualMemory_failed:
762770b1 8bc8 mov ecx,eax // ecx = error code
762770b3 e86854ffff call KERNELBASE!BaseSetLastNTError (7626c520)
762770b8 ebee jmp return_from_function
Code:
PVOID
WINPAI
VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
)
{
dwSizeLocal = dwSize;
lpAddressLocal = lpAddress;
if (lpAddressLocal) {
if (lpAddressLocal < SysInfo.MinimalAlloAddress) {
RtlSetLastWin32Error(ERROR_INVALID_PARAMETER);
return NULL;
}
}
dwErrorCode = NtAllocateVirtualMemory(
NtCurrentProcess(),
&lpAddressLocal,
0,
&dwSizeLocal,
flAllocationType & 0xFFFFFFC0,
flpProtect
);
if (!NT_SUCCESS(dwErrorCode)) {
BaseSetLastNTError(dwErrorCode);
return NULL;
}
return lpAddressLocal
}
If there are some errors or question ask
(This post was last modified: 04-19-2019, 11:31 AM by IsBadWritePtr.)