您的当前位置:首页正文

ReadProcessMemory/C++的探索

2024-11-30 来源:个人技术集锦

ReadProcessMemory 函数msdn说明:

BOOL WINAPI ReadProcessMemory(
  _In_   HANDLE hProcess,
  _In_   LPCVOID lpBaseAddress,
  _Out_  LPVOID lpBuffer,
  _In_   SIZE_T nSize,
  _Out_  SIZE_T *lpNumberOfBytesRead
);

Parameters

hProcess [in]

A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.

进程句柄

lpBaseAddress [in]

A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails.

读取内存的基址(关键,因为不是随便取一个就能读出来的)

lpBuffer [out]

A pointer to a buffer that receives the contents from the address space of the specified process.

nSize [in]

The number of bytes to be read from the specified process.

需要读取内存的大小

lpNumberOfBytesRead [out]

A pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.

实际读取内存的大小

Return value

If the function succeeds, the return value is nonzero.

如果成功,返回非0。

If the function fails, the return value is 0 (zero). To get extended error information, call .

如果失败,返回0,错误可通过获得

The function fails if the requested read operation crosses into an area of the process that is inaccessible.

重点:当操作进入了进程不可读取的部分时会失败,大多数人犯的错误。

Remarks

ReadProcessMemory copies the data in the specified address range from the address space of the specified process into the specified buffer of the current process. Any process that has a handle with PROCESS_VM_READ access can call the function.

函数需要进程的PROCESS_VM_READ 权限

The entire area to be read must be accessible, and if it is not accessible, the function fails.

关于探索旅程的废话说一点:

开始按实验报告上的要求基址填了0x,其它查了下msdn函数原型简单写出了程序,运行一下,结果就悲剧的读取失败。

下面是错误的代码:

STARTUPINFO si;
	PROCESS_INFORMATION pi;
	HANDLE hProcess=NULL;
	ZeroMemory( &si, sizeof(si) );
	si.cb = sizeof(si);
	ZeroMemory( &pi, sizeof(pi) );

	if(!CreateProcess(L".\\memoryinfo_child2.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
	{
		printf( "CreateProcess2 failed (%d)\n", GetLastError() );
	}

	WaitForSingleObject( pi.hProcess, 1000 );
	byte *readtemp=new byte[256*16];
	DWORD dwNumberOfBytesRead;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,
		FALSE, pi.dwProcessId );
	if(hProcess !=NULL)
	{
		int i=0x00000000;
		if(!ReadProcessMemory(hProcess,(LPCVOID)i,readtemp,0x10,&dwNumberOfBytesRead)){
			i++;
		}
		printf("readsuccess:");
		for(int i=0;i<dwNumberOfBytesRead;i++){
			printf("\n");
			printf("%X",readtemp[i]);
		}
		printf("\n");
	}
	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );

仅完成部分的 ReadProcessMemory 或 WriteProcessMemory 请求。没啥帮助,不过 至少学会GetLastError(菜鸟一枚,勿喷),,,

对于基址不对,有人说得用CE工具查看(表示CE是神马东东),然后百度了下,原来CE的全称是ChartEngine,大神一般用来游戏作弊,没想到今日居然用来做作业。。。怒下。

居然支持中文版,感动,,,

用ChartEngine查看了子进程的内存,果然基址至少20000以上,还且经常会变。基址换了之后,真的读取成功了,感动得泪流满面。


后来由于基址在程序运行前会变化,所有用了while语句,直到成功时才跳出循环,苦逼,,,这么简单的东西搞了半天,主要基础没打好,,,,

下面是正确的代码:

STARTUPINFO si;
	PROCESS_INFORMATION pi;
	HANDLE hProcess=NULL;
	ZeroMemory( &si, sizeof(si) );
	si.cb = sizeof(si);
	ZeroMemory( &pi, sizeof(pi) );

	if(!CreateProcess(L".\\memoryinfo_child2.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
	{
		printf( "CreateProcess2 failed (%d)\n", GetLastError() );
	}

	WaitForSingleObject( pi.hProcess, 1000 );
	byte *readtemp=new byte[256*16];
	DWORD dwNumberOfBytesRead;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,
		FALSE, pi.dwProcessId );
	if(hProcess !=NULL)
	{
		int i=0x00020000;
		while(!ReadProcessMemory(hProcess,(LPCVOID)i,readtemp,0x10,&dwNumberOfBytesRead)){
			i++;
		}
		printf("readsuccess:");
		for(int i=0;i<dwNumberOfBytesRead;i++){
			printf("\n");
			printf("%X",readtemp[i]);
		}
		printf("\n");
	}
	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );



显示全文