crummie5 / FreshyCalls

FreshyCalls tries to make the use of syscalls comfortable and simple, without generating too much boilerplate and in modern C++17!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

VirtualWriteMemory Address Issue when greater than 27352

IppSec opened this issue · comments

Hey,

I'm trying to use FreshyCalls to do Process Injection and when the size of data I am trying to write with NtWriteVirtualMemory is greater than 27,352 the syscall returns AccessDenied. I've confirmed it allocates enough memory for this to fit (and double checked via ProcesHacker), so am assuming its an issue within the call trampoline and am not sure how to debug it.

Below is code that can be placed in the POC to replicate the issue.

int main(int argc, char *argv[]) {
  HANDLE process_handle;
  HANDLE file_handle;
  //const uint32_t process_id = GetPID(argc, argv);
  PVOID* mem = NULL;

  std::cout << "FreshyCalls' PoC dumper" << std::endl << std::endl;

  try {
    HANDLE hProcess;
    const char* sc = "\xc0\xd3";
    // Used in NtAllocateVirtualMemory
    SIZE_T fSize = ((sizeof(sc) + 780000 + 0x1000 - 1) & ~(0x1000 - 1));
    // Used in NtWriteVirtualMemory, when greater than 27,352 - fails to write
    SIZE_T wtf = 27353;

    std::cout << "[+] Grabbing handle to process...";
    hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
      PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
      PROCESS_VM_READ, FALSE, 11368);
    if (hProcess)
        std::cout << " OK!" << std::endl;

    std::cout << "[+] Trying NtAllocateVirtualMemory...";
    syscall.CallSyscall("NtAllocateVirtualMemory", hProcess, &mem, 0, (PULONG)&fSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)
        .OrDie("NtAllocateVirtualMemory: {{result_as_hex}}");
    std::cout << " OK!" << std::endl;
    
    std::cout << "[+] Trying NtWriteVirtualMemory...";

    syscall.CallSyscall("NtWriteVirtualMemory", hProcess, mem, sc, wtf, NULL)
        .OrDie("NtWriteVirtualMemory: {{result_as_hex}}");

    std::cout << " OK!" << std::endl;

  }
  catch (const std::runtime_error &e) {
    std::cerr << std::endl << e.what() << std::endl;
    exit(-1);
  }

  return 0;
}

Actually, I may just have overlooked something stupid simple... May be working sorry for the spam.

No worries, that is not spam at all. It always makes me happy to see folks using FreshyCalls. Feel free to ask any question Mr Ippsec. May I close this issue? Cheers

Closing the issue - The sample code above, I was writing a memory leak and hitting protected memory most likely... Still have some issues with using FreshyCalls within my project versus a stand alone demo, but I don't think its easily reproducible since I can't explain it.

Can't explain why but in my project the following will fail.:

syscall.CallSyscall("NtAllocateVirtualMemory", hProcess, &remoteBuffer, 0, (PULONG)&fSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)
  .OrDie("NtAllocateVirtualMemory: {{result_as_hex}}");

syscall.CallSyscall("NtWriteVirtualMemory", hProcess, remoteBuffer, scpointer, (SIZE_T)finalSize, NULL)
  .OrDie("NtWriteVirtualMemory: {{result_as_hex}}");

//syscall.CallSyscall("NtWriteVirtualMemory", hProcess, remoteBuffer, scpointer, (SIZE_T)finalSize, NULL)
//  .OrDie("NtWriteVirtualMemory: {{result_as_hex}}");

syscall.CallSyscall("NtProtectVirtualMemory", hProcess, &remoteBuffer, &uVProtectSz, PAGE_EXECUTE_READ, &oldProtect)
  .OrDie("NtProtectVirtualMemory: {{result_as_hex}}");

If the only thing I do is remove the comments on the second NtWriteVirtualMemory call, both of them work and everything else goes as expected. My only guess is compiler optimization.

So if you're here trying to figure out why something is crashing, I guess try to duplicate the syscall thats crashing and see what happens.

I see what the problem is. FreshyCalls does not know the types of the parameters of the original stub. NumberOfBytesWritten is a pointer and therefore in x64 it has a size of 8 bytes. You are passing NULL which is simply an int of value 0, so its size is 4 bytes and the rest of the memory is left uninitialized so it generates UB. Try using nullptr instead. I should add a warning about that, sorry.