Hook自定义MessageBox

// HookMsgBox.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include 
#include 
using namespace std;

// MessageBoxW函数原型
// int WINAPI MessageBoxW(__in_opt HWND hWnd,__in_opt LPCWSTR lpText,__in_opt LPCWSTR lpCaption,__in UINT uType);

typedef int (WINAPI* MsgBox)(HWND, LPCWSTR, LPCWSTR, UINT);

MsgBox SysMsgBox = NULL; // 指向user32下的MessageBox
FARPROC fpSysMsgBox = NULL; // FARPROC 是一个4字节指针,指向一个函数的内存地址

BYTE byteSysMsgOEP[5]; // 系统MessageBox入口代码
BYTE byteMyMsgOEP[5]; // 自定义MessageBox入口代码

HANDLE hProcess = NULL; // 本应用程序句柄
HINSTANCE hInstance = NULL; // dll文件句柄


							// 初始化得到本应用程序句柄
void Init()
{
	DWORD dPid = GetCurrentProcessId();
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dPid);
}

/// 开始hook
void StartHook();

/// 停止hook
void StopHook();

/// 获得系统MessageBox入口代码
void GetSysMsgBoxOEP();

/// 获得自定义MessageBox入口代码
void GetMySmgBoxOEP();

wchar_t* ANSIToUnicode(const string& str)
{
	int len = 0;
	len = str.length();
	int unicodeLen = ::MultiByteToWideChar(CP_ACP,
		0,
		str.c_str(),
		-1,
		NULL,
		0);
	wchar_t * pUnicode;
	pUnicode = new wchar_t[unicodeLen + 1];
	memset(pUnicode, 0, (unicodeLen + 1)*sizeof(wchar_t));
	::MultiByteToWideChar(CP_ACP,
		0,
		str.c_str(),
		-1,
		(LPWSTR)pUnicode,
		unicodeLen);
	//wstring rt;
	//rt = (wchar_t*)pUnicode;
	return pUnicode;
	//return rt;//注意内存泄漏
}

LPCWSTR stringToLPCWSTR(string orig)
{
	size_t origsize = orig.length();
	wchar_t* tTarget = new wchar_t[origsize + 1];
	//const size_t newsize = 100;
	//size_t convertedChars = 0;
	//wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t) *(orig.length() - 1));
	//mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);

	MultiByteToWideChar(CP_ACP, 0, orig.c_str(), origsize, tTarget, origsize*sizeof(wchar_t));
	return tTarget;
	// 抽出来比较好,不然会内存泄漏
	//return wcstring;
}

int WINAPI MyMsgBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
	StopHook();
	int nRet = MessageBox(hWnd, _T("hook成功"), _T("hook测试"), 0);
	StartHook();
	return nRet;
}

int main()
{
	cout << "请输入编号:1(开启hook) 2.(关闭hook) 3.退出" << endl;


	// 1.初始化得到本应用程序句柄
	Init();

	// 2.得到系统MessageBox入口代码
	GetSysMsgBoxOEP();

	// 3.得到自定义MessageBox入口代码
	GetMySmgBoxOEP();

	int n;
	while (cin >> n)
	{
		switch (n)
		{
		case 1:
			StartHook();
			break;
		case 2:
			StopHook();
			break;
		default:
			return 0;
			break;
		}

		cout << "请输入你期待的弹出框显示的内容" << endl;
		string sText;
		cin >> sText;
		LPCWSTR lpText = ANSIToUnicode(sText);
		MessageBox(0, lpText, _T("hook测试"), 0);
		cout << endl << "请输入编号:1(开启hook) 2.(关闭hook) 3.退出" << endl;
	}

	return 0;
}


void StartHook()
{
	DWORD dOldProtect;
	DWORD dTmpprotect;
	// VirtualProtectEx函数可以改变在特定进程中内存区域的保护属性
	/*
	BOOL VirtualProtectEx(
	HANDLE hProcess, // 要修改内存的进程句柄
	LPVOID lpAddress, // 要修改内存的起始地址
	DWORD dwSize, // 页区域大小
	DWORD flNewProtect, // 新访问方式
	PDWORD lpflOldProtect // 原访问方式 用于保存改变前的保护属性 易语言要传址
	);
	*/
	/*
	BOOL WriteProcessMemory(
	HANDLE hProcess,
	LPVOID lpBaseAddress,
	LPVOID lpBuffer,
	DWORD nSize,
	LPDWORD lpNumberOfBytesWritten
	);
	参数:
	hProcess
	由OpenProcess返回的进程句柄。
	如参数传数据为 INVALID_HANDLE_VALUE 【即-1】目标进程为自身进程
	lpBaseAddress
	要写的内存首地址
	再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。
	lpBuffer
	指向要写的数据的指针。
	nSize
	要写入的字节数。
	返回值
	非零值代表成功。
	*/
	VirtualProtectEx(hProcess, fpSysMsgBox, 5, PAGE_READWRITE, &dOldProtect);
	WriteProcessMemory(hProcess, fpSysMsgBox, byteMyMsgOEP, 5, NULL);
	VirtualProtectEx(hProcess, fpSysMsgBox, 5, dOldProtect, &dTmpprotect);
}

void StopHook()
{
	DWORD dOldProtect;
	DWORD dTmpprotect;

	VirtualProtectEx(hProcess, fpSysMsgBox, 5, PAGE_READWRITE, &dOldProtect);
	WriteProcessMemory(hProcess, fpSysMsgBox, byteSysMsgOEP, 5, NULL);
	VirtualProtectEx(hProcess, fpSysMsgBox, 5, dOldProtect, &dTmpprotect);
}

void GetSysMsgBoxOEP()
{
	// 获得基地址
	HMODULE hBaseAddr = LoadLibrary(_T("user32.dll"));

	// 获得系统MsgBox的偏移地址
	SysMsgBox = (MsgBox)GetProcAddress(hBaseAddr, ("MessageBoxW"));

	fpSysMsgBox = (FARPROC)SysMsgBox;

	if (fpSysMsgBox != NULL)
	{
		_asm
		{
			lea edi, byteSysMsgOEP // 获取保存系统msgbox的数组地址
			mov esi, fpSysMsgBox // 得到系统msgbox函数地址
				cld // 方向标记位,控制数据的流向
				movsd // 复制从esi所指地址处的前dword4字节数据到edi所指地址中
				movsb // 复制从esi所指地址处的第5个字节数据到edi所指地址中
		}
	}
}

void GetMySmgBoxOEP()
{
	// 使用jmp近跳,跳的是偏移地址
	// 偏移量 = 自定义函数地址 - 系统函数地址 - jmp命令的5字节(jmp指令为1字节,地址为4字节)
	byteMyMsgOEP[0] = 0XE9; // jmp指令
	_asm
	{
		lea eax, MyMsgBox // 得到自定义函数的地址
		mov ebx, fpSysMsgBox // 得到系统msgbox函数地址
			sub eax, ebx
			sub eax, 5
			mov dword ptr[byteMyMsgOEP + 1], eax
	}

}


你可能感兴趣的:(木马)