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
", pBuffer);
	
	//2、调用api实现
    ReadProcessMemory((HANDLE)-1, &t, &pBuffer, sizeof(int), 0);
    printf("%X
", 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
", 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
", t);
    }
    getchar();
    return 0;
}
#endif
原文地址:https://www.cnblogs.com/Erma/p/12917399.html