讓我們繼續在《內核讀寫記憶體浮點數》的基礎之上做一個簡單的延申,如何實作多級偏移讀寫,其實很簡單,讀寫函式無需改變,只是在讀寫之前提前做好計算作業,以此來得到一個記憶體偏移值,并通過呼叫記憶體寫入原函式實作寫出資料的目的,
以讀取偏移記憶體為例,如下代碼同樣來源于本人的LyMemory讀寫驅動專案,其中核心函式為WIN10_ReadDeviationIntMemory()該函式的主要作用是通過用戶傳入的基地址與偏移值,動態計算出當前的動態地址,
函式首先將基地址指向要讀取的變數,并將其轉換為LPCVOID型別的指標,然后將指向變數值的緩沖區轉換為LPVOID型別的指標,接下來,函式使用PsLookupProcessByProcessId函式查找目標行程并回傳其PEPROCESS結構體,隨后,函式從偏移地址陣列的最后一個元素開始迭代,每次回圈都從目標行程中讀取4位元組整數型資料,并將其存盤在Value變數中,然后,函式將基地址指向Value和偏移地址的和,以便在下一次回圈中讀取更深層次的變數,最后,函式將基地址指向最終變數的地址,讀取變數的值,并回傳,
如下案例所示,用戶傳入行程基址以及offset偏移值時,只需要動態計算出該偏移地址,并與基址相加即可得到動態地址,
#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>
// 普通Ke記憶體讀取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = Process;
PEPROCESS TargetProcess = PsGetCurrentProcess();
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
// 讀取整數記憶體多級偏移
/*
Pid: 目標行程的行程ID,
Base: 變數的基地址,
offset: 相對基地址的多級偏移地址,用于定位變數,
len: 偏移地址的數量,
*/
INT64 WIN10_ReadDeviationIntMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len)
{
INT64 Value = https://www.cnblogs.com/LyShark/p/0;
LPCVOID pbase = (LPCVOID)Base;
LPVOID rbuffer = (LPVOID)&Value;
PEPROCESS Process;
PsLookupProcessByProcessId((HANDLE)Pid, &Process);
for (int x = len - 1; x >= 0; x--)
{
__try
{
KeReadProcessMemory(Process, pbase, rbuffer, 4);
pbase = (LPCVOID)(Value + offset[x]);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
}
__try
{
DbgPrint("讀取基址:%x \n", pbase);
KeReadProcessMemory(Process, pbase, rbuffer, 4);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
return Value;
}
// 驅動卸載例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver \n");
}
// 驅動入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("Hello LyShark \n");
DWORD PID = 4884;
LONG PBase = 0x6566e0;
LONG Size = 4;
DWORD Offset[32] = { 0 };
Offset[0] = 0x18;
Offset[1] = 0x0;
Offset[2] = 0x14;
Offset[3] = 0x0c;
// 讀取記憶體資料
INT64 read = WIN10_ReadDeviationIntMemory(PID, PBase, Offset, Size);
DbgPrint("PID: %d 基址: %p 偏移長度: %d \n", PID, PBase, Size);
DbgPrint("[+] 1級偏移: %x \n", Offset[0]);
DbgPrint("[+] 2級偏移: %x \n", Offset[1]);
DbgPrint("[+] 3級偏移: %x \n", Offset[2]);
DbgPrint("[+] 4級偏移: %x \n", Offset[3]);
DbgPrint("[ReadMemory] 讀取偏移資料: %d \n", read);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
編譯并運行如上這段代碼,則可獲取到PID=4884的PBase的動態地址中的資料,如下圖所示;

至于如何將資料寫出四級偏移的基址上面,則只需要取出pbase里面的基址,并通過原函式WIN10_WriteProcessMemory直接寫出資料即可,此出的原函式在《內核MDL讀寫行程記憶體》中已經做了詳細介紹,實作寫出代碼如下所示;
#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>
// 普通Ke記憶體讀取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = Process;
PEPROCESS TargetProcess = PsGetCurrentProcess();
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
// Win10 記憶體寫入函式
BOOLEAN WIN10_WriteProcessMemory(HANDLE Pid, PVOID Address, SIZE_T BYTE_size, PVOID VirtualAddress)
{
PVOID buff1;
VOID *buff2;
int MemoryNumerical = 0;
KAPC_STATE KAPC = { 0 };
PEPROCESS Process;
PsLookupProcessByProcessId((HANDLE)Pid, &Process);
__try
{
//分配記憶體
buff1 = ExAllocatePoolWithTag((POOL_TYPE)0, BYTE_size, 1997);
buff2 = buff1;
*(int*)buff1 = 1;
if (MmIsAddressValid((PVOID)VirtualAddress))
{
// 復制記憶體
memcpy(buff2, VirtualAddress, BYTE_size);
}
else
{
return FALSE;
}
// 附加到要讀寫的行程
KeStackAttachProcess((PRKPROCESS)Process, &KAPC);
if (MmIsAddressValid((PVOID)Address))
{
// 判斷地址是否可寫
ProbeForWrite(Address, BYTE_size, 1);
// 復制記憶體
memcpy(Address, buff2, BYTE_size);
}
else
{
return FALSE;
}
// 剝離附加的行程
KeUnstackDetachProcess(&KAPC);
ExFreePoolWithTag(buff2, 1997);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
}
return FALSE;
}
// 寫入整數記憶體多級偏移
INT64 WIN10_WriteDeviationIntMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len, INT64 SetValue)
{
INT64 Value = https://www.cnblogs.com/LyShark/p/0;
LPCVOID pbase = (LPCVOID)Base;
LPVOID rbuffer = (LPVOID)&Value;
PEPROCESS Process;
PsLookupProcessByProcessId((HANDLE)Pid, &Process);
for (int x = len - 1; x >= 0; x--)
{
__try
{
KeReadProcessMemory(Process, pbase, rbuffer, 4);
pbase = (LPCVOID)(Value + offset[x]);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
}
__try
{
KeReadProcessMemory(Process, pbase, rbuffer, 4);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
// 使用原函式寫入
BOOLEAN ref = WIN10_WriteProcessMemory(Pid, (void *)pbase, 4, &SetValue);
if (ref == TRUE)
{
DbgPrint("[內核寫成功] # 寫入地址: %x \n", pbase);
return 1;
}
return 0;
}
// 驅動卸載例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver \n");
}
// 驅動入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("Hello LyShark \n");
DWORD PID = 4884;
LONG PBase = 0x6566e0;
LONG Size = 4;
INT64 SetValue = https://www.cnblogs.com/LyShark/p/100;
DWORD Offset[32] = { 0 };
Offset[0] = 0x18;
Offset[1] = 0x0;
Offset[2] = 0x14;
Offset[3] = 0x0c;
// 寫出記憶體資料
INT64 write = WIN10_WriteDeviationIntMemory(PID, PBase, Offset, Size, SetValue);
DbgPrint("PID: %d 基址: %p 偏移長度: %d \n", PID, PBase, Size);
DbgPrint("[+] 1級偏移: %x \n", Offset[0]);
DbgPrint("[+] 2級偏移: %x \n", Offset[1]);
DbgPrint("[+] 3級偏移: %x \n", Offset[2]);
DbgPrint("[+] 4級偏移: %x \n", Offset[3]);
DbgPrint("[WriteMemory] 寫出偏移資料: %d \n", SetValue);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
運行如上代碼將在0x6566e0所在的基址上,將資料替換為100,實作效果圖如下所示;

那么如何實作讀寫記憶體浮點數,位元組集等多級偏移呢?
其實我們可以封裝一個WIN10_ReadDeviationMemory函式,讓其只計算得出偏移地址,而所需要寫出的型別則根據自己的實際需求配合不同的寫入函式完成,也就是將兩者分離開,如下則是一段實作計算偏移的代碼片段,該代碼同樣來自于本人的LyMemory驅動讀寫專案;
#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>
// 普通Ke記憶體讀取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = Process;
PEPROCESS TargetProcess = PsGetCurrentProcess();
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
// 讀取多級偏移記憶體動態地址
DWORD64 WIN10_ReadDeviationMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len)
{
INT64 Value = https://www.cnblogs.com/LyShark/p/0;
LPCVOID pbase = (LPCVOID)Base;
LPVOID rbuffer = (LPVOID)&Value;
PEPROCESS Process;
PsLookupProcessByProcessId((HANDLE)Pid, &Process);
for (int x = len - 1; x >= 0; x--)
{
__try
{
KeReadProcessMemory(Process, pbase, rbuffer, 4);
pbase = (LPCVOID)(Value + offset[x]);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
}
return pbase;
}
// 驅動卸載例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver \n");
}
// 驅動入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("Hello LyShark \n");
DWORD PID = 4884;
LONG PBase = 0x6566e0;
LONG Size = 4;
DWORD Offset[32] = { 0 };
Offset[0] = 0x18;
Offset[1] = 0x0;
Offset[2] = 0x14;
Offset[3] = 0x0c;
// 寫出記憶體資料
DWORD64 offsets = WIN10_ReadDeviationMemory(PID, PBase, Offset, Size);
DbgPrint("PID: %d 基址: %p 偏移長度: %d \n", PID, PBase, Size);
DbgPrint("[+] 1級偏移: %x \n", Offset[0]);
DbgPrint("[+] 2級偏移: %x \n", Offset[1]);
DbgPrint("[+] 3級偏移: %x \n", Offset[2]);
DbgPrint("[+] 4級偏移: %x \n", Offset[3]);
DbgPrint("[CheckMemory] 計算偏移地址: %x \n", offsets);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
運行如上代碼將動態計算出目前偏移地址的pbase實際地址,實作效果圖如下所示;

文章出處:https://www.cnblogs.com/LyShark/p/17507776.html
本博客所有文章除特別宣告外,均采用 BY-NC-SA 許可協議,轉載請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/556091.html
標籤:訊息安全
上一篇:uniapp-chatgpt跨端仿ChatGPT實體|uniapp+vue3+pinia多端聊天模板
下一篇:返回列表
