Windows內核——直接調用0環函數實現ReadProcessMemory&WriteProcessMemory函數


直接調用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實現函數功能?

  1. Windows所提供給Ring3的API,實質就是對操作系統接口的封裝,其實現部分都是在Ring0實現的。

    觀察上面圖中分析函數就可以很清楚的知道了。

  2. 防止惡意程序會利用鈎子來鈎取這些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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM