/////////////////////////////////////////////////////////////
// NTWriteProcessMemeory.cpp
//

#include "stdafx.h"
#include "NTWriteProcessMemory.h"

NTSTATUS 
NTAPI
NTWriteProcessMemory(
	IN HANDLE  ProcessHandle,
	IN PVOID   StartAddress,
	IN PVOID   Buffer,
    IN SIZE_T  BytesToWrite,
    OUT SIZE_T *BytesWritten OPTIONAL
    )
{
    NTSTATUS    dwNTStatus;
    ULONG   dwOldProtection = 0;
    ULONG   dwOldProtection2 = 0;
    PVOID   pStartAddress  = StartAddress;
    SIZE_T  dwBytesToWrite = BytesToWrite;
    dwNTStatus = NtProtectVirtualMemory(
        ProcessHandle,
        &pStartAddress,
        &dwBytesToWrite,
        PAGE_EXECUTE_WRITECOPY, // PAGE_WRITECOPY PAGE_READWRITE PAGE_EXECUTE_READWRITE PAGE_EXECUTE_WRITECOPY
        &dwOldProtection
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return dwNTStatus;
    }
    if (dwOldProtection & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY))
    {
        dwNTStatus = NtProtectVirtualMemory(
            ProcessHandle,
            &pStartAddress,
            &dwBytesToWrite,
            dwOldProtection,
            &dwOldProtection2
            );
        dwNTStatus = NtWriteVirtualMemory(
            ProcessHandle,
            StartAddress,
            Buffer,
            BytesToWrite,
            BytesWritten
            );
        if (!NT_SUCCESS(dwNTStatus))
        {
            return dwNTStatus;
        }
        NtFlushInstructionCache(
            ProcessHandle,
            StartAddress,
            BytesToWrite
            );
        return dwNTStatus;
    }
    //if (dwOldProtection & PAGE_NOACCESS)
    //{
    //    NtProtectVirtualMemory(
    //        ProcessHandle,
    //        &pStartAddress,
    //        &dwBytesToWrite,
    //        dwOldProtection,
    //        &dwOldProtection
    //        );
    //    return STATUS_ACCESS_VIOLATION;
    //}
    dwNTStatus = NtWriteVirtualMemory(
        ProcessHandle,
        StartAddress,
        Buffer,
        BytesToWrite,
        BytesWritten
        );
    NtProtectVirtualMemory(
        ProcessHandle,
        &pStartAddress,
        &dwBytesToWrite,
        dwOldProtection,
        &dwOldProtection2
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return dwNTStatus;
    }
    NtFlushInstructionCache(
        ProcessHandle,
        StartAddress,
        BytesToWrite
        );
    return dwNTStatus;
}
