What is the last parameter in VirtualProtect used for?

I want to use both VirtualAlloc and VirtualProtect to inject a shellcode into the local process but I can't figure out what is the last argument (lpflOldProtect) and how do I declare it.

void fun()
{
    size_t dwSize = 511; // size of shellcode 
    LPVOID base_add = VirtualAlloc(NULL , dwSize , MEM_RESERVE, PAGE_NOACCESS); 
    if (base_add == NULL )
    {
        cout << "Failed to allocate space " << endl;
        return ;
    }

    LPVOID end_add = base_add + dwSize; 
    // change mem protection option
    PDWORD lpflOldProtect = 0;
    bool change_protection = VirtualProtect(base_add,dwSize,PAGE_EXECUTE_READWRITE, lpflOldProtect );
    if (change_protection)
    {
        cout << "Successfully changed protection" << endl;
    }
    else
    {
        cout << " Failed" << endl;
    }
}

According to Microsoft documentation, the last parameter in VirtualProtect is:

A pointer to a variable that receives the previous access protection value of the first page in the specified region of pages. If this parameter is NULL or does not point to a valid variable, the function fails.

What do they mean by this? What is the value of the first page in the specified region? Isn't that the base address?


Solution 1:

The fourth (last) argument to the VirtualProtect function should be the address of a DWORD variable in which to receive the value of the previous protection flags for the memory block (or, to be exact, the first page of that block). You can use this, should you desire, to 'reset' that protection level when you're done doing whatever it is for which you need to change that protection.

In your code, you are declaring a pointer in the PDWORD lpflOldProtect = 0; line and assigning that pointer a NULL (zero) value – so, as per the document you linked, your call to VirtualProtect will fail.

Instead, you should declare an actual DWORD variable and pass the address of that variable as the last argument. In your case, the modified code will look something like this:

DWORD flOldProtect = 0;
BOOL change_protection = VirtualProtect(base_add, dwSize, PAGE_EXECUTE_READWRITE, &flOldProtect);
                                            // Pass address of the DWORD variable ^
if (change_protection)
{
    //...

Note that, in the linked document, the last argument is marked as [out] – which means that its value before the call is not used by the function, so you don't really need to initialize it; however, some compilers and/or code analysers may complain about using an uninitialized value, which is why I set it to zero.

Also note that the return value of the function is of type BOOL (declared in the Windows system headers as typedef int BOOL;), not bool; in most cases, the implicit cast your code makes won't cause any problems but, again, some compilers may issue a warning about that conversion.