ufrisk / pcileech

Direct Memory Access (DMA) Attack Software
GNU Affero General Public License v3.0
5.04k stars 735 forks source link

PCILeech_VmmWrite #74

Closed hrt closed 5 years ago

hrt commented 5 years ago

I've decided to move away from my own work and begin using the dll.

Is the signature of this function correct? BOOL PCILeech_VmmWrite(In DWORD dwPID, In ULONG64 qwVA, Out PBYTE pb, In DWORD cb);

My first impression is that pb should be the input buffer from which the function should be writing from rather than being some sort of output? And cb is the size to write (from the buffer, pb)?

With all of that being said, I can't get it to write a 64bit value

    DWORD64 lock = 0;
    if (!PCILeech_VmmWrite(dwPID, targetLock, &lock, sizeof(DWORD64)))
    {
        printf("lock err\n");
    }

targetLock address is fine since I've printed it and checked on the target PC. dwPID is fine too

ufrisk commented 5 years ago

Nice, for your information the Vmm functions of PCILeech will be removed in the next major release since they are already supported by the Memory Process File System project (which integrates fully with PCILeech). If doing new work I recommend looking into Memory Process File System vmm.dll linked to pcileech.dll instead.

You are right that the annotation is messed up, pb is an input buffer in this case. Thanks for reporting this. I'll fix this in the Memory Process File System project. (I'll fix this in the next major PCILeech release by removing the API). I'll check the VmmWrite to see if I get the same problem though. Or please let me know if you experience the same problem with the Memory Process File System vmm.dll implementation.

hrt commented 5 years ago

thanks! Appears like the annotation is fine in vmmdll BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);

However, I am experiencing the same issue with vmmdll. Maybe worth noting that VMMDLL_MemReadEx works fine

ufrisk commented 5 years ago

I'm unable to replicate this with FPGA hardware. A couple of questions:

  1. What hardware are you using? FPGA hardware? PCIeScreamer or Xilinx dev board?

  2. are you checking the return value of the pcbReadOpt parameter from VMMDLL_MemReadEx. The read function will return TRUE even though only a partial read or no read was possible - you have to check the number of read bytes i the pcbReadOpt output parameter to be sure your read was completely successful.

  3. what address are you reading/writing to, any special offsets, does the read cross page bounds, not DWORD aligned 32/64-bit address? just giving a sample address that's not working should be enough for me right now.

  4. target OS, I assume Win10 64-bit?

  5. at last I plan to release a new version of vmm.dll tomorrow with a bunch of bug-fixes included, it would be aswesome if you could try that one out as well after the relase. mbe the problem isn't existing in the new version.

hrt commented 5 years ago

Unfortunately I won't be able to play around today since I have two exams today. But I can give you info I already know.

First of all lets clarify that reading memory works fine it's only write memory that fails (100% of the time). I have used the pcbreadoutput param (in the read function) to print the hex ascii and it prints a lot of lines out which are correct to what's in memory

  1. PCIEscreamer
  2. Although I haven't checked this parameter (and it's an input for vmm write), the value at the address is not changed on the target PC (I attached debugger on target process)
  3. Unfortunately can't check this right now but I've also tried writing to addresses that I've read from (vmm mem read ex) and it fails. But I wouldn't be suprised if both addresses were not aligned since the lockaddress is essentially just a specific dll module base + unaligned offset. The write should not be crossing any bounds.
  4. Win10 64bit
ufrisk commented 5 years ago

I just pushed some very minor bugfixes to the Memory Process File System (vmm.dll). It would be awesome if you could re-check if your issue still exists.

hrt commented 5 years ago

I just checked with the new dll and lib and still cannot write. An example address I am using is 0x7ffca4ddce0c . On the target process the value at the address doesn't change and VMMDLL_MemWrite returns false. cbWrite is 0 and cb is 8 within VmmWrite .

image

Related virtual memory region on target process: image

Also, I don't run the code under _INITIALIZE_FROM_FPGA since it fails

CALL:    VMMDLL_InitializeFPGA
FAIL:    VMMDLL_InitializeFPGA
hrt commented 5 years ago

So I did some printing and I think I'm missing something. Perhaps I'm not able to write because I don't run VMMDLL_InitializeFPGA (since it fails due to MemProcFS: Failed to connect to memory acquisition device)?

ctxVmm->fReadOnly is true in VmmWriteScatterVirtual I commented that line out to ignore this flag.

ctxMain->dev.pfnWriteMEM is NULL in DeviceWriteMEM

update: I'll stick to my old ways for now (no dll and cr3 specific)

BOOL _WVM(_Inout_ PPCILEECH_CONTEXT ctx, QWORD virtualAddress, PBYTE buffer, SIZE_T size)
{
    QWORD physicalAddress = VirtualToPhysical(ctx, virtualAddress);

    if (!physicalAddress)
        return FALSE;

    SIZE_T pageSize = 0x1000;
    PBYTE pageBuffer = LocalAlloc(0, pageSize);
    QWORD physicalAddressBase = physicalAddress & 0xfffffffff000;
    QWORD physicalAddressOffset = physicalAddress & 0xfff;

    // we need to first read the page
    if (!DeviceReadDMA(ctx, physicalAddressBase, pageBuffer, pageSize, PCILEECH_MEM_FLAG_RETRYONFAIL))
        return FALSE;

    // overwite the pageBuffer with what we want to write
    SIZE_T sizeToWrite = MIN(size, pageSize - physicalAddressOffset);
    memcpy(&(pageBuffer[physicalAddressOffset]), buffer, sizeToWrite);

    // write modified page back to target
    if (!DeviceWriteDMA(ctx, physicalAddressBase, pageBuffer, pageSize, PCILEECH_MEM_FLAG_RETRYONFAIL))
        return FALSE;

    LocalFree(pageBuffer);

    if (sizeToWrite < size)

    {
        if (!_WVM(ctx, virtualAddress + sizeToWrite, &(buffer[sizeToWrite]), size - sizeToWrite))
            return FALSE;
    }

    return TRUE;
}
ufrisk commented 5 years ago

When you say you aren't running the VMMDLL_InitializeFPGA are you by any chance initializing a file instead? The ReadOnly flag is only set if the device type is set to file (which doesn't allow writing).

image

When you say VMMDLL_InitializeFPGA fail, have you made sure both pcileech.dll and FTD3XX.dll is put in the same directory as vmm.dll ?

You can enable the verbose output to see why the FPGA init fails in the initialization stage by calling (instead of the InitializeFPGA function): VMMDLL_InitializeReserved(6, (LPSTR[]) {"", "-device", "fpga", "-vdll", "-v", "-vv"});

hrt commented 5 years ago

Yes I do initialize with a file. Are the cr3's found some other way instead of through a dump file? Also I was not aware of FTD3XX.dll will have a look

hrt commented 5 years ago

Update, it all works good. I'm surprised it finds all the cr3s so quickly. Very convenient

Are there any limits on VMMDLL_MemWrite? e.g. max size, aligned address currently having trouble writing a size of 1024 bytes edit: this might be because I am writing across memory regions - will check edit2: can't find an issue with crossing memory regions

ufrisk commented 5 years ago

Thanks for the update and for clearing up the misunderstanding about the file not being read/write. I'll update the documentation in the next release.

Also, if running against a live FPGA the vmm.dll does refreshes of the process list which may lead to small hickups in access times. There are options that will let you fine tune or disable this behavior.

The MemWrite should be able to write across memory pages and 1024 bytes shouldn't be problematic. But the write parts aren't as well tested as the read parts so I cannot guarantee that it's completely bug free - even though I haven't had a problem in my tests. I'll look into it.

hrt commented 5 years ago

Thanks, I don't think it's an issue with size - I've tried reducing it. The write to that specific address never works. But when I actively look at the memory on cheat engine on the target pc the write works. I suspect it's because the virtual address (region) I want to write to doesn't have an active physical address since it isn't used at all by the process

but the writes to other addresses work fine