win32向目標進程注入代碼

下面代碼演示了向“記事本”程序(NOTEPAD.EXE)的進程地址空間中注入我們自己寫的函數代碼,大致原理如下:


1. 提升注入(注意和“被注入”的區別)程序的進程訪問權限

2. 隨便打開一個記事本文件,注意是用NOTEPAD.EXE打開的

3. 查找NOTEPAD.EXE對應的進程ID,即Process ID

4. 以所有權限(包括read/write)打開NOTEPAD.EXE的進程ID

5. 在NOTEPAD.EXE的進程ID地址空間中,申請一塊內存

6. 向剛剛申請的內存中,寫入我們想要寫的任何代碼(注意:注入的代碼中全部都用指針的形式調用相關數據和函數)

7. 我們寫的代碼不會自動執行,需要在被注入的進程中創建一個新的線程,調用注入的代碼


-------------------------------------------------------------------------------------------------------------------------------

相關代碼如下:

//整理:過客  
//郵箱:[email protected]  
//日期:2014.04.01

#pragma once
#include <windows.h>
#include <TlHelp32.h>
#include "stdio.h"

//--------------------------------------------------------
typedef struct tagWNDINFO
{
	DWORD dwProcId;
	HWND hWnd;
} WNDINFO, *LPWNDINFO;

BOOL CALLBACK MyEnumProc(HWND hWnd,LPARAM lParam)
{
	DWORD dwProcId;
	GetWindowThreadProcessId(hWnd, &dwProcId); //獲得hWnd對應的線程ID

	LPWNDINFO pInfo = (LPWNDINFO)lParam;
	if(dwProcId == pInfo->dwProcId) //判斷是否是我們需要尋找的ID
	{
		pInfo->hWnd = hWnd;
		return FALSE;
	}

	return TRUE;
}

HWND GetProcessMainWnd(DWORD dwProcId)
{
	WNDINFO wi;

	wi.dwProcId = dwProcId; //被查詢窗口的進程ID
	wi.hWnd = NULL;

	EnumWindows(MyEnumProc,(LPARAM)&wi); //枚舉窗口

	return wi.hWnd; //返回dwProcId對應的窗口句柄
} 

//--------------------------------------------------------
//線程參數結構體定義
typedef struct tagRemoteParam
{
	char szTitle[60]; // MessageBox函數中窗口標題
	char szMsg[60]; // MessageBox函數中顯示的字符提示
	DWORD dwMessageBox; // MessageBox函數的入口地址
} RemoteParam, *PRemoteParam;

//定義MessageBox類型的函數指針
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);

//線程函數定義
DWORD __stdcall threadProc(LPVOID lParam)
{
	RemoteParam* pRP = (RemoteParam*)lParam;
	PFN_MESSAGEBOX pfnMessageBox;
	pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;
	pfnMessageBox(NULL, pRP->szMsg, pRP->szTitle, 0);
	return 0;
}

//提升進程訪問權限
BOOL enableDebugPriv()
{
	HANDLE hToken;
	LUID sedebugnameValue;
	TOKEN_PRIVILEGES tkp;

	if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		return FALSE;
	}
	if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
	{
		CloseHandle(hToken);
		return FALSE;
	}
	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Luid = sedebugnameValue;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 特權啓用
	if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) // 啓用指定訪問令牌的特權
	{
		CloseHandle(hToken);
		return FALSE;
	}
	return TRUE;
}

//根據進程名稱得到進程ID,如果有多個運行實例的話,返回第一個枚舉到的進程的ID
DWORD processNameToId(LPCTSTR lpszProcessName)
{
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	PROCESSENTRY32 pe;
	pe.dwSize = sizeof(PROCESSENTRY32);
	if(!Process32First(hSnapshot, &pe))
	{
		MessageBox(NULL, "The frist entry of the process list has not been copyied to the buffer", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}
	while(Process32Next(hSnapshot, &pe)) // 循環查找下一個進程
	{
		if(!strcmp(lpszProcessName, pe.szExeFile)) // 找到了
		{
			return pe.th32ProcessID;
		}
	}

	return 0;
}

//-----------------------------------------------------------
int main(int argc, char* argv[])
{
	//定義線程體的大小,實際分配的內存大小是頁內存大小的整數倍
	const DWORD dwThreadSize = 4096;
	DWORD dwWriteBytes;

	//提升進程訪問權限
	enableDebugPriv();
    
	//等待輸入進程名稱,注意大小寫匹配
	char szExeName[MAX_PATH] = { 0 };
//	cout << "Please input the name of target process !" << endl;
//	cin >> szExeName; //接收命令行輸入的字符串
//	cout << szExeName << endl;
//	strcpy(szExeName,"notepad.exe");
//	scanf("%s",szExeName);
	sprintf(szExeName,"NOTEPAD.EXE");
 
	DWORD dwProcessId = processNameToId(szExeName); //Name轉換成ID
	if(dwProcessId == 0)
	{
		MessageBox(NULL, "The target process have not been found !", "Notice", MB_ICONINFORMATION | MB_OK);
		return -1;
	}

	HWND hWnd=GetProcessMainWnd(dwProcessId);
	char szTile[MAX_PATH];
	::GetWindowText(hWnd, szTile, MAX_PATH); //獲得已經打開的記事本窗口的標題

	//根據進程ID得到進程句柄
	HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
 
	if(!hTargetProcess)
	{
		MessageBox(NULL, "Open target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	//在宿主進程中爲線程體開闢一塊存儲區域
	//在這裏需要注意 MEM_COMMIT | MEM_RESERVE 內存分配類型以及PAGE_EXECUTE_READWRITE內存保護類型
	//其具體含義請參考MSDN中關於VirtualAllocEx函數的說明。
	void* pRemoteThread = VirtualAllocEx(hTargetProcess, 0, dwThreadSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if(!pRemoteThread)
	{
		MessageBox(NULL, "Alloc memory in target process failed !", "notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	//將線程體拷貝到宿主進程中
	if(!WriteProcessMemory(hTargetProcess, pRemoteThread, &threadProc, dwThreadSize, 0))
	{
		MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	//定義線程參數結構體變量
	RemoteParam remoteData;
	ZeroMemory(&remoteData, sizeof(RemoteParam)); //初始化

	//填充結構體變量中的成員
	HINSTANCE hUser32 = LoadLibrary("User32.dll");
	remoteData.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxA"); //取得MessageBox API的地址
//	strcat(remoteData.szTitle, "新建文本文檔");
	int len=strlen(szTile);
	szTile[len]='\0';
	strcat(remoteData.szTitle, szTile); //MessageBox的標題
	strcat(remoteData.szMsg, "Hello 你好嗎?\\(^o^)/~"); //MessageBox的內容

    //爲線程參數在宿主進程中開闢存儲區域
	RemoteParam* pRemoteParam = (RemoteParam*)VirtualAllocEx(hTargetProcess , 0, sizeof(RemoteParam), MEM_COMMIT, PAGE_READWRITE);
	if(!pRemoteParam)
	{
		MessageBox(NULL, "Alloc memory failed !", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	//將線程參數拷貝到宿主進程地址空間中
	if(!WriteProcessMemory(hTargetProcess , pRemoteParam, &remoteData, sizeof(remoteData), 0))
	{
		MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	//在宿主進程中創建線程
	HANDLE hRemoteThread = CreateRemoteThread(hTargetProcess, NULL, 0, (DWORD (__stdcall *)(void *))pRemoteThread, pRemoteParam, 0, &dwWriteBytes);
	if(!hRemoteThread)
	{
		MessageBox(NULL, "Create remote thread failed !", "Notice",  MB_ICONINFORMATION | MB_OK);
		return 0;
	}

	CloseHandle(hRemoteThread);
	FreeLibrary(hUser32);
	return 0;
}

---------------------------------------------------------------------

測試運行結果如下:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章