直接調用0環函數實現ReadProcessMemory&WriteProcessMemory函數
工具
IDA
VC++6.0
步驟
一、實現ring0調用ReadProcessMemory
1、ALT+T 找到ReadProcessMemory
2、找到NtReadVirtualMemory(ntdll.dll)函數
去導入表里面查看這個函數在哪個dll里
發現這個函數也只是間接調用的一個內核函數的地址而已
二、實現ring0調用WriteProcessMemory
1、ALT+T 找到 WriteProcessMemory
2、找到NtProtectVirtualMemory(ntdll.dll)函數
去導入表里面查看這個函數在哪個dll里
發現這個函數也只是間接調用的一個內核函數的地址而已
從上面NtReadVirtualMemory、NtProtectVirtualMemory中的具體實現可以知道,這里調用的知識內核函數的一個地址,換個系統可能這個地址就會不一樣,所以這樣的函數兼容性差。
為啥要直接調用ring0實現函數功能?
-
Windows所提供給Ring3的API,實質就是對操作系統接口的封裝,其實現部分都是在Ring0實現的。
觀察上面圖中分析函數就可以很清楚的知道了。
-
防止惡意程序會利用鈎子來鈎取這些API,從而達到截取內容,修改數據的意圖。
二、實現ring0調用ReadProcessMemory
1、匯編實現
lea eax, [ebp + 0x14]
push eax
push[ebp + 0x14]
push[ebp + 0x10]
push[ebp + 0xc]
push[ebp + 8]
sub esp, 4 //調用NtReadVirtualMemory的是call xxx,實質是 將返回地址壓棧&JMP,所以這里sub 4個byte實現返回地址的壓棧
mov eax, 0x0BA
mov edx, 0X7FFE0300 //不能直接調用內核,間接call函數地址來實現
CALL DWORD PTR[EDX]
add esp, 24 //堆棧平衡 24=6*4
2、測試
#ifdef debug
int main()
{
// HANDLE hProcess = 0;
int t = 0x12345678;
DWORD pBuffer;
// DWORD dwChromeID = GetCurrentProcessId();
//1、不調用dll實現ReadProcessMemory
ReadMemory((HANDLE)-1, (PVOID)&t, &pBuffer, sizeof(int), 0);
printf("%X\n", pBuffer);
//2、調用api實現
ReadProcessMemory((HANDLE)-1, &t, &pBuffer, sizeof(int), 0);
printf("%X\n", pBuffer);
//結果:1 2的結果一致
getchar();
return 0;
}
#endif
第二種方法:
#include<windows.h>
#include<stdio.h>
void __declspec(naked) read(HANDLE hProcess,LPVOID addr,LPVOID buffer,DWORD len)
{
_asm
{
mov eax, 0BAh
mov edx, 7FFE0300h
call dword ptr[edx]
ret
}
}
#ifndef debug
int main() {
int t;
int a[8];
// 依次往 p 指針中寫入數據,再用ReadProcessMemory讀取數據
for (int i = 0; i < 8; i++) {
WriteProcessMemory(INVALID_HANDLE_VALUE, &a[i], &i, sizeof(int),NULL);
}
for (int j = 0; j < 8; j++) {
read(INVALID_HANDLE_VALUE, &a[j], &t, sizeof(int));
printf("%d\n", t);
}
getchar();
return 0;
}
#endif
三、實現ring0調用WriteProcessMemory
1、匯編實現
void WriteMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten)
{
_asm{
push ecx ;Buffer
push ecx
mov eax, [ebp+0x0C] ;lpBaseAddress 2
push ebx
mov ebx, [ebp+0x14] ;OldProtect???
push edi
mov edi, [ebp+8] ;ProcessHandle 1
mov [ebp-8], eax ;BaseAddress
lea eax, [ebp+0x14]
push eax ; OldProtect
push 0x40 ; NewProtect
lea eax, [ebp-4]
push eax ; ProtectSize
lea eax, [ebp-8]
push eax ; BaseAddress
push edi ; ProcessHandle
mov [ebp-4], ebx
sub esp, 4 ;call esi ; NtProtectVirtualMemory
mov eax, 0x89
mov edx, 0x7FFE0300
call dword ptr [edx]
add esp, 0x28
}
}
批注:這個還有些問題沒想明白:這里ecx為什么要push兩次???
2、測試
#ifndef debug
int main() {
int t;
int a[8];
// 依次往 p 指針中寫入數據,再用ReadProcessMemory讀取數據
for (int i = 0; i < 8; i++) {
WriteMemory(INVALID_HANDLE_VALUE, &a[i], &i, sizeof(int),NULL);
}
for (int j = 0; j < 8; j++) {
ReadProcessMemory(INVALID_HANDLE_VALUE, &a[j], &t, sizeof(int), NULL);
printf("%d\n", t);
}
getchar();
return 0;
}
#endif