WIN動態庫注入(遠線程注入)

所謂動態庫注入是指,將自己編寫的動態庫,通過自己的程序來注入到別的進程中去,然後運行。

原理:
在目標進程,開闢一段內存,然後寫入要注入的動態庫.dll 。然後讓目標運行加載動態庫函數,將該動態庫載入到到進程中,然後運行指定函數,通常在進程創建一個線程,然後運行指定的代碼。

涉及到的函數如下如果需要更詳細的解釋,請前往MSDN查閱:

/*
\ brief		檢索頂級窗口的句柄,該窗口的類名和窗口名與指定的字符串匹配。
\ param		lpClassName  窗口或控件類名稱
\ param		lpWindowName 窗口名稱(窗口標題)
\ return	返回窗口的句柄,失敗返回NULL
*/
HWND FindWindowW(
  LPCSTR lpClassName,
  LPCSTR lpWindowName
);

/*
\ brief		檢索指定窗口的線程標識符(ID)與進程標識符(ID)
\ param		hWnd	窗口的句柄
\ param		lpdwProcessId 接收進程標識符的指針
\ return	線程標識符
*/
DWORD GetWindowThreadProcessId(
  HWND    hWnd,
  LPDWORD lpdwProcessId
);

/*
\ brief		打開一個現有的本地過程對象
\ param		dwDesiredAccess		進程訪問權限
\ param		bInheritHandle		進程是否繼承句柄
\ param		dwProcessId			進程標識符
\ return	進程的打開句柄,失敗返回NULL
*/
HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);

/*
\ brief		指定進程分配虛擬內存,提交或更改內存區域狀態,並初始化爲NULL
\ param		hProcess	進程的句柄
\ param		lpAddress	分配的頁面區域指定所需的起始地址,NULL則由系統默認
\ param		dwSize		要分配的內存區域的大小,以字節爲單位,NULL則由系統默認認					
\ param		flAllocationType 內存分配的類型
\ param		flProtect	內存保護常量
\ return	頁面分配的基地址(起始地址),失敗返回NULL
*/
LPVOID VirtualAllocEx(
  HANDLE hProcess,		
  LPVOID lpAddress,		
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

/*
\ brief		在指定的進程中將數據寫入內存區域
\ param		hProcess		進程句柄,必須具有PROCESS_VM_WRITE和PROCESS_VM_OPERATION訪問權限
\ param		lpBaseAddress	指向要寫入數據的指定進程中的基地址的指針
\ param		lpBuffer		要寫入數據的緩衝區的指針
\ param		nSize			緩衝區大小
\ param		lpNumberOfBytesWritten	該變量接收傳輸到指定進程中的字節數
\ return	失敗返回,fALSE
*/
BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);

/*
\ brief		創建一個在另一個進程中運行的線程
\ param		hProcess	創建線程的進程的句柄
\ param		lpThreadAttributes	該結構爲新線程指定安全描述符,NULL爲系統默認
\ param		dwStackSize	 	堆棧的初始大小,以字節爲單位,0 則使用系統默認大小
\ param		lpStartAddress	類型爲LPTHREAD_START_ROUTINE函數的指針
\ param		lpParameter		函數的參數指針
\ param		dwCreationFlags	控制線程創建的標誌
\ param		lpThreadId		指向接收線程標識符的變量的指針,NULL則不返回
\ return	新線程句柄,失敗返回NULL
*/
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);

/*
\ brief		關閉打開的句柄
\ param		句柄
\ return	失敗返回FALSE
*/
BOOL CloseHandle(
  HANDLE hObject
);

準備好要注入的,動態庫。
我個人是喜歡將動態庫,直接放置早要注入的程序目錄下。

動態庫注入

注入程序的代碼,項目的字符集使用的Unicode字符

#include<iostream>
#include<Windows.h>			// 引入Windows庫
using namespace std;

int main(int argc, char* argv[])
{
	// 獲取窗口句柄 , 結尾是 W 表示寬字節, A 表示多字節
	HWND hwnd = ::FindWindowW(NULL, TEXT("植物大戰殭屍中文版"));
	if (hwnd == NULL) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 定義一個變量接收 進程標識符
	DWORD pId;
	// 獲取進程與線程 標識符
	DWORD tId = GetWindowThreadProcessId(hwnd, &pId);
	// 獲取進程句柄
	HANDLE pHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
	if (pHandle == NULL) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 定義寬字節數組,接收寬字節字符串
	TCHAR buf[] = TEXT("StaticMfcDll.dll");
	// 在目標進程分配一塊內存區域,使用 baseAddress變量接收,內存地址
	LPVOID baseAddress = ::VirtualAllocEx(pHandle, 
											NULL,
											sizeof(buf),
											MEM_COMMIT, 
											PAGE_EXECUTE_READWRITE);
	// 在目標進程寫入buf數組,也就是 StaticMfcDll.dll  這一串字符串,注意這是寬字節
	if (!::WriteProcessMemory(pHandle, 
								baseAddress,
								buf, 
								sizeof(buf),
								NULL)) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 在目標進程調用 LoadLibrary()函數加載動態庫函數,參數是 baseAddress 地址的字符串。
	if (!::CreateRemoteThread(pHandle,
								NULL,
								0,
								(LPTHREAD_START_ROUTINE)LoadLibrary,
								baseAddress,
								0,
								NULL)) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 關閉句柄
	::CloseHandle(pHandle);

}

這個動態庫是 MFC庫,重點配置是,可以用vs直接創建出來
MFC配置

動態庫的核心代碼

// CStaticMfcDllApp 初始化
// .h  頭文件定義的一個  線程指針
private:
	std::unique_ptr<std::thread> tPtr;

/*
\ breif		線程運行的函數
*/
void CStaticMfcDllApp::ThreadFunciton()
{
	// 定義 植物變量
	Plant p;	
	// 模態顯示 植物對話框
	p.DoModal();
}

/*
\brief	當加載該庫的時候,會調用到這個重載函數。
*/
BOOL CStaticMfcDllApp::InitInstance()
{
	CWinApp::InitInstance();
	// 開啓一個線程,運行 成員函數
	tPtr = std::make_unique<std::thread>(&CStaticMfcDllApp::ThreadFunciton, this);
	return TRUE;
}

/*
\ brief		析構函數
*/
CStaticMfcDllApp::~CStaticMfcDllApp()
{
// 銷燬時,阻塞等待線程退出
	tPtr->join();
}

/*
\ brief		這個是修改陽光
*/
void Plant::OnBnClickedBtnSum()
{
	// TODO: 在此添加控件通知處理程序代碼
	UpdateData(TRUE);
	int sum = _wtoi(editSum.GetBuffer());
	// 陽光基址 [[006A9EC0]+768]+5560
	size_t * pointer = (size_t*)((*(size_t*)((*(size_t*)0x006A9EC0) + 0x768)) + 0x5560);
	*pointer = sum;
}

/*
\ brief		這個是修改金幣
*/
void Plant::OnBnClickedBtnMenory()
{
	// TODO: 在此添加控件通知處理程序代碼
	UpdateData(TRUE);
	int menory = _wtoi(editMenory.GetBuffer());
	// 金幣基址 [[006A9EC0] + 82C] + 28
	size_t* pointer = (size_t*)((*(size_t*)((*(size_t*)0x006A9EC0) + 0x82C)) + 0x28);
	*pointer = menory;
}

/*
\ brief		這個是修改植物的CD冷卻邏輯代碼,直接修改程序運行代碼
*/
void Plant::OnBnClickedPlant()
{
	// TODO: 在此添加控件通知處理程序代碼
	// 將00487296 | 7E 14  | jle plantsvszombies.4872AC  處代碼 修改成 9090
	UpdateData(TRUE);
	UCHAR buf[2] = {};
	if (plantCD) {
		buf[0] = 0x90;
		buf[1] = 0x90;
	}
	else {
		buf[0] = 0x7E;
		buf[1] = 0x14;
	}
	// 只能使用這個 函數來進行代碼段的修改,直接 使用指針會使程序崩潰,哪怕是在同一個進程
	::WriteProcessMemory(::GetCurrentProcess(), 
							 LPVOID(0x00487296),
							 buf, 
							 sizeof(buf),
							 NULL);
}


/*
\ brief		這個是修改大嘴花的吞噬冷卻邏輯
*/
void Plant::OnBnClickedFlower()
{
	// TODO: 在此添加控件通知處理程序代碼
	//  將 0046324C 處代碼 0046324C | 83C0 FF | add eax,FFFFFFFF  
	//  修改成 0046324C | 33C0 90 | 		 xor eax,eax  nop	
	UpdateData(TRUE);
	UCHAR buf[3] = {};
	if (flowerCd) {
		buf[0] = 0x33;
		buf[1] = 0xC0;
		buf[2] = 0x90;
	}
	else {
		buf[0] = 0x83;
		buf[1] = 0xC0;
		buf[2] = 0xFF;
	}
	// 只能使用這個 函數來進行代碼段的修改,直接 使用指針會使程序崩潰,哪怕是在同一個進程
	::WriteProcessMemory(::GetCurrentProcess(), 
							 LPVOID(0x0046324C),
							 buf, 
							 sizeof(buf),
							 NULL);
}

/*
\ brief		按放櫻花炸彈
\ param		x 軸座標 0-8
\ param		y 軸座標 0-8
*/
void Plant::Bom(int x, int y)
{
// 這個是彙編代碼,調用 遊戲的植物按放call
	_asm
	{
		pushad	
		push 0xFFFFFFFF
		push 2
		mov eax, y
		push x
		mov ebx, ds: [0x6A9EC0]
		mov ebx, ds : [ebx + 0x768]
		push ebx
		mov edx, 0x40D120;
		call edx	
		popad
	}
}
/*
\ brief		滿屏櫻花炸彈
*/
void Plant::OnBnClickedBtnBom()
{
	// TODO: 在此添加控件通知處理程序代碼
	for (int i = 0; i < 9; ++i) {
		for (int j = 0; j < 9; ++j) {
			Bom(i, j);
		}
	}
}


看一下實際運行測試:

先啓動,植物大戰殭屍遊戲程序(PlantsVsZombies.exe),然後啓動注入程序(Grammar.exe)。
運行效果
運行效果
我們可以使用工具查看一下,是否成功注入到植物大戰殭屍進程中
pe
已經成功注入到,植物大戰殭屍進程中了。

接下來就是測試下,動態庫效果。

測試
可以看到,陽關的數量,和金幣的數量已經修改了,植物的冷卻已已經完畢,是沒有問題的。

接下來測試,櫻花炸彈 全屏轟炸效果
櫻花炸彈

沒有問題。
文章時間2019年12月20日15:41:54

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