XP上的ReadProcessMemorry读取其他线程导致崩溃

http://voneinem-windbg.blogspot.com/2008/02/shooting-pageguard-flag-with.html

转自这篇链接

XP上存在BUG,当一个线程ReadProcessMemory到另一个线程的内存时,会导致PAGE_GUARD丢失,另一个线程将失去chkstk的能力,会无法扩展堆栈

相关的逻辑制成测试代码如下:

PBYTE g_pStart1Thread = 0;
PBYTE g_pEnd1Thread = 0;


void MyTestProc_inner(HANDLE hWait)
{
	char buffer_hello[4096] = {};
	buffer_hello[0] = 'h';
	buffer_hello[1] = 'e';
	buffer_hello[2] = 'l';
	buffer_hello[3] = 'l';
	buffer_hello[4] = 'o';
	printf("buffer=%s\n", buffer_hello);
	g_pStart1Thread = (BYTE*)buffer_hello - 400000;
	g_pEnd1Thread = (BYTE*)buffer_hello + sizeof(buffer_hello);

	WaitForSingleObject(hWait, INFINITE);
	printf("1 thread goon\n");
	call_test();
	printf("1 thread success end\n");
}

void MyTestProc(void * p)
{
	MyTestProc_inner(reinterpret_cast(p));
	_endthread();
}


int main()
{
	//return _tmain2();

	SetDebugPrivilege(TRUE);
	//一个线程读另一个线程才行
	HANDLE hWaitForMe = CreateEvent(NULL, FALSE, FALSE, NULL);
	uintptr_t hThread = _beginthread(MyTestProc, 0, hWaitForMe);
	// give the thread time to start
	::Sleep(1000);

	//开始读取1线程的内存
 
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
	if (hProcess)
	{
		{
			MEMORY_BASIC_INFORMATION meminfo;
			PBYTE pAddress = g_pStart1Thread;
			//从低到高遍历每个区域
			while (
				pAddress <= g_pEnd1Thread &&
				(VirtualQueryEx(hProcess, pAddress, &meminfo, sizeof(meminfo)) == sizeof(meminfo))
				)
			{
				if (meminfo.State != MEM_FREE)//跳过已经释放的
				{
					MyMemRegion regioninfo;
					regioninfo.addr = (BYTE*)meminfo.BaseAddress;
					regioninfo.sz = meminfo.RegionSize;

					g_vetRegions.push_back(regioninfo);
					printf("%p: %u B, P=%X\n", meminfo.BaseAddress, (DWORD)meminfo.RegionSize, meminfo.Protect);
				}

				pAddress = (PBYTE)meminfo.BaseAddress + meminfo.RegionSize;
			}
		}

		printf("=================================================================ANY KEY\n");
		getchar();
		for (size_t i = 0; i < g_vetRegions.size(); i++)
		{
			BYTE* pbb = (BYTE*)malloc(g_vetRegions[i].sz);
			if (pbb)
			{
				memset(pbb, 0, g_vetRegions[i].sz);
				SIZE_T SZ_Read = 0;
				if (ReadProcessMemory(hProcess, g_vetRegions[i].addr, &pbb[0], g_vetRegions[i].sz, &SZ_Read)) {
					CStringA str((char*)&(pbb[0]), 5);
					printf("read ok sz=%u \"%s\"\n", (DWORD)SZ_Read, (LPCSTR)str);
				}
				else {
					printf("read fail %u\n", GetLastError());
				}
				free(pbb);
			}
			else
			{
				printf("alloc fail %u\n", GetLastError());
			}
		}
		printf("=================================================================\n");

		{
			MEMORY_BASIC_INFORMATION meminfo;
			PBYTE pAddress = g_pStart1Thread;
			//从低到高遍历每个区域
			while (
				pAddress <= g_pEnd1Thread &&
				(VirtualQueryEx(hProcess, pAddress, &meminfo, sizeof(meminfo)) == sizeof(meminfo))
				)
			{
				if (meminfo.State != MEM_FREE)//跳过已经释放的
				{
					printf("%p: %u B, P=%X\n",
						meminfo.BaseAddress, 
						(DWORD)meminfo.RegionSize,
						meminfo.Protect
					);
				}

				pAddress = (PBYTE)meminfo.BaseAddress + meminfo.RegionSize;
			}
		}
		printf("=================================================================\n");
		CloseHandle(hProcess);
	}
	else
	{
		printf("err open proc %u\n", GetLastError());
	}

	//SetEvent 1GOON
	SetEvent(hWaitForMe);


	WaitForSingleObject(reinterpret_cast(hThread), INFINITE);
	printf("success end\n");
	getchar();
	return 0;
}

你可能感兴趣的:(XP,_chkstk)