MFC:Win32-Dll及MFC-Dll编写调用

一、win32-dll

1、编写

代码例如以下:

Math.h

#ifdef MATH_EXPORTS
#define MATH_API __declspec(dllexport)
#else
#define MATH_API __declspec(dllimport)
#endif

extern MATH_API double PI;

MATH_API int Add(int a ,int b);

MATH_API int Sub(int a, int b);

MATH_API int Mod(int a, int b);
Math.cpp

#include "stdafx.h"
#include "Math.h"
MATH_API double PI = 3.1415926;
MATH_API int Add(int a,int b)
{
    return a + b;
}
MATH_API int Sub(int a, int b)
{
	return a - b;
}
MATH_API int Mod(int a, int b)
{
	return a % b;
}
Math.def(这个须要自己手动新建项中加入)

LIBRARY "Math"
DESCRIPTION "ADD SUB MOD"
EXPORTS
	Add @1
	Sub @2
	Mod @3
	PI  DATA

2、调用

初始化这些:

	typedef int(*M_add)(int, int);
	typedef int(*M_sub)(int, int);
	typedef int(*M_mod)(int, int);
	M_add myadd;
	M_sub mysub;
	M_mod mymod;

HINSTANCE hinst;

hinst = ::LoadLibrary(_T("Math.dll"));
void CMathTestDlg::OnBnClickedAdd()
{
	ASSERT(hinst);
	myadd = (M_add)::GetProcAddress(hinst,"Add");
	int a = 15, b = 6;
	int res = myadd(a,b);
	CString str;
	str.Format(_T("a+b=%d"), res);
	AfxMessageBox(str);
}
void CMathTestDlg::OnBnClickedSub()
{
	ASSERT(hinst);
	mysub = (M_sub)::GetProcAddress(hinst, "Sub");
	int a = 15, b = 6;
	int res = mysub(a, b);
	CString str;
	str.Format(_T("a-b=%d"), res);
	AfxMessageBox(str);
}
void CMathTestDlg::OnBnClickedMod()
{
	ASSERT(hinst);
	mymod = (M_mod)::GetProcAddress(hinst, "Mod");
	int a = 15, b = 6;
	int res = mymod(a, b);
	CString str;
	str.Format(_T("a求余b=%d"), res);
	AfxMessageBox(str);
}

二、MFC-dll

1、MFC-Dll会在载入的时候,调用InitInstance中的代码,退出载入时,调用ExitInstance中的代码

2、声明部分

//不同Instance共享的该变量hinst
#pragma data_seg("SHARED")
static HINSTANCE hinst = NULL; //本dll的实例句柄 (MFCMath.dll)
#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")

HANDLE hProcess = NULL; //所处进程的句柄
BOOL bHook = FALSE;		//是否Hook了函数
BOOL inject_status = FALSE; //是否对API进行了Hook
BYTE OldCode[5];	//老的系统API入口代码
BYTE NewCode[5];	//要跳转的API代码 (jmp xxxx)
typedef int (*M_add)(int a, int b);		//Math.dll中的Add函数定义
M_add m_add;	//Math.dll中的Add函数
FARPROC pf_add;  //指向Add函数的远指针
			 
void HookOn(); //开启钩子
void HookOff(); //关闭钩子
void Inject(); //详细进行注射,替换入口的函数
int Myadd(int a, int b); //我们定义的新的add()函数

3、InitInstance中的代码,载入时执行

BOOL CMFCMathApp::InitInstance()
{
	hinst = AfxGetInstanceHandle(); //本dll句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,NULL,::GetCurrentProcessId());
	Inject();
	return CWinApp::InitInstance();
}

4、ExitInstance中的代码,退出时执行

int CMFCMathApp::ExitInstance()
{
	if (bHook)
		HookOff();
	return CWinApp::ExitInstance();
}

5、其它代码

void Inject()
{
	if (inject_status == FALSE) {
		inject_status = TRUE;
		HMODULE hmod = ::LoadLibrary(_T("Math.dll"));//加载原Math.dll
		m_add = (M_add)::GetProcAddress(hmod, "Add");
		pf_add = (FARPROC)m_add;
		if (pf_add == NULL) {
			AfxMessageBox(L"注入失败");
		}
		_asm
		{
			lea edi, OldCode
			mov esi, pf_add
				cld
				movsd
				movsb
		}

		NewCode[0] = 0xe9;//第一个字节0xe9相当于jmp指令
						  //获取Myadd()的相对地址
		_asm
		{
			lea eax, Myadd
			mov ebx, pf_add
				sub eax, ebx
				sub eax, 5
				mov dword ptr[NewCode + 1], eax
		}
		HookOn();
		AfxMessageBox(L"注入成功");
	}
}
void HookOn()
{
	ASSERT(hProcess != NULL);
	DWORD dwTemp = 0;
	DWORD dwOldProtect;

	//将内存保护模式改为可写,老模式保存入dwOldProtect
	VirtualProtectEx(hProcess, pf_add, 5, PAGE_READWRITE, &dwOldProtect);
	//将所属进程中add的前5个字节改为Jmp Myadd 
	WriteProcessMemory(hProcess, pf_add, NewCode, 5, 0);
	//将内存保护模式改回为dwOldProtect
	VirtualProtectEx(hProcess, pf_add, 5, dwOldProtect, &dwTemp);

	bHook = TRUE;
}
//将所属进程中add()的入口代码恢复
void HookOff()
{
	ASSERT(hProcess != NULL);
	DWORD dwTemp = 0;
	DWORD dwOldProtect;

	VirtualProtectEx(hProcess, pf_add, 5, PAGE_READWRITE, &dwOldProtect);
	WriteProcessMemory(hProcess, pf_add, OldCode, 5, 0);
	VirtualProtectEx(hProcess, pf_add, 5, dwOldProtect, &dwTemp);
	bHook = FALSE;
}
int Myadd(int a, int b)
{
	//截获了对add()的调用,我们给a,b都加1
	a = a + 1;
	b = b + 1;
	HookOff();//关掉Myadd()钩子防止死循环
	int ret = m_add(a, b);
	HookOn();//开启Myadd()钩子
	return ret;
}

6、调用的方法

::LoadLibrary(_T("MFCMath.dll"));
此时会把Math.dll的入口替换Myadd的入口

假设在Myadd中使用了Math.dll中的Add函数,记住把入口再换回来,就是HookOff。调用完以后,再HookOn换回来。

::FreeLibrary()。能够释放掉在载入的dll


三、恶搞MessageBoxW函数

//不同Instance共享的该变量hinst
#pragma data_seg("SHARED")
static HINSTANCE hinst = NULL; //本dll的实例句柄 (MFCMath.dll)
#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")

HANDLE hProcess = NULL; //所处进程的句柄
BOOL bHook = FALSE;		//是否Hook了函数
BOOL inject_status = FALSE; //是否对API进行了Hook
BYTE OldCode[5];	//老的系统API入口代码
BYTE NewCode[5];	//要跳转的API代码 (jmp xxxx)
typedef int (WINAPI *MyMsg)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);		//Math.dll中的Add函数定义

MyMsg m_msg;	//Math.dll中的Add函数
FARPROC pf_add;  //指向Add函数的远指针
			 
void HookOn(); //开启钩子
void HookOff(); //关闭钩子
void Inject(); //详细进行注射,替换入口的函数
int WINAPI Myadd(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); //我们定义的新的add()函数

BOOL CMFCMathApp::InitInstance()
{
	hinst = AfxGetInstanceHandle(); //本dll句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,NULL,::GetCurrentProcessId());
	Inject();
	return CWinApp::InitInstance();
}
int CMFCMathApp::ExitInstance()
{
	if (bHook)
		HookOff();
	return CWinApp::ExitInstance();
}

void Inject()
{
	if (inject_status == FALSE) {
		inject_status = TRUE;
		HMODULE hmod = ::LoadLibrary(_T("User32.dll"));//加载原Math.dll
		m_msg = (MyMsg)::GetProcAddress(hmod, "MessageBoxW");
		pf_add = (FARPROC)m_msg;
		_asm
		{
			lea edi, OldCode
			mov esi, pf_add
				cld
				movsd
				movsb
		}

		NewCode[0] = 0xe9;//第一个字节0xe9相当于jmp指令
						  //获取Myadd()的相对地址
		_asm
		{
			lea eax, Myadd
			mov ebx, pf_add
				sub eax, ebx
				sub eax, 5
				mov dword ptr[NewCode + 1], eax
		}
		HookOn();
	}
}
void HookOn()
{
	ASSERT(hProcess != NULL);
	DWORD dwTemp = 0;
	DWORD dwOldProtect;

	//将内存保护模式改为可写,老模式保存入dwOldProtect
	VirtualProtectEx(hProcess, pf_add, 5, PAGE_READWRITE, &dwOldProtect);
	//将所属进程中add的前5个字节改为Jmp Myadd 
	WriteProcessMemory(hProcess, pf_add, NewCode, 5, 0);
	//将内存保护模式改回为dwOldProtect
	VirtualProtectEx(hProcess, pf_add, 5, dwOldProtect, &dwTemp);

	bHook = TRUE;
}
//将所属进程中add()的入口代码恢复
void HookOff()
{
	ASSERT(hProcess != NULL);
	DWORD dwTemp = 0;
	DWORD dwOldProtect;

	VirtualProtectEx(hProcess, pf_add, 5, PAGE_READWRITE, &dwOldProtect);
	WriteProcessMemory(hProcess, pf_add, OldCode, 5, 0);
	VirtualProtectEx(hProcess, pf_add, 5, dwOldProtect, &dwTemp);
	bHook = FALSE;
}
int WINAPI Myadd(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
	lpText =  _T("被掉包了,哈哈");
	HookOff();//关掉Myadd()钩子防止死循环
	int ret = m_msg(hWnd, lpText, lpCaption, uType);
	HookOn();//开启Myadd()钩子
	return ret;
}


转载于:https://www.cnblogs.com/wzzkaifa/p/7105903.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC调用win32窗口显示调试信息,使用AllocConsole 函数(2010-11-16 15:33:25)转载标签: 调试win32mfc杂谈 分类: 编译器 AllocConsole Function 为主调进程分配一个新的控制台。 语法 C++ : BOOL WINAPI AllocConsole(void); 参数: 无 返回值:如果函数成功,返回值是非零值;如果函数失败,返回值是零值。 备注: 一个进程仅能关联一个控制台,所以该函数在主调进程已经具有控制台时将会失败。 一个进程可以使用 FreeConsole 函数来释放与之关联的控制台,之后它就可以调用该函数来创建一个新的控制台或使用 AttachConsole 函数来关联另一个控制台。 如果主调进程创建了一个子进程,则子进程也将继承这个新创建的控制台。 该函数为新的控制台初始化标准输入、输出、错误句柄等。 标准输入句柄是一个控制台输入缓冲的句柄,标准输出和标准错误句柄则是控制台屏幕缓冲的句柄。为了获得这些句柄,可以使用 GetStdHandle 函数。 该函数主要用于GUI应用程序来创建一个控制台窗口。 GUI应用程序初始化时时没有控制台的,而控制台应用程序则以控制台来初始化的。 要求 : Minimum supported client Windows 2000 Professional Minimum supported server Windows 2000 Server Header: Wincon.h (include Windows.h) Library: Kernel32.lib DLL Kernel32.dll ---------------------------------------------------------------------------------------- 虽然WIN32时代是图形界面时代,但偶尔程序中还需要用到命令行模式,比如批处理,这时再搞个图形界面出来显得似乎就不那么专业了。但客户还需要在正常状态下(对于命令行模式,我认为用户是非正常状态,比如脑子进水。)使用图形界面,这决定我们不能开一个控制台工程,而需要使用MFC exe程序。 OK,理所当然的,通过条件控制,命令行下我关掉对话框界面的调用代码,再使用 cout << "Hello world!" << endl; 来向这个友好的世界打个招呼,并坚持认为这句问候应该显示在CMD那个漆黑的窗口里。 很沮丧地说,事实给我与痛击。cmd窗口里仍然漆黑一片,系统完全不理会我的友好。 邓爷爷说,改革开放好!也许,我也需要个改革。 在同事mr. zhang的指导下,我找到一组API:Console Functions!正是这组API,最终让我的友好得以正当地表达。 一。创建一个Console,AllocConsole 直接使用 AllocConsole(); 马上,若是进程内第一次调用这个函数,一个空的cmd窗口会蹦出来。需要注意,一个进程只能创建一个console,多次调用会返回FALSE;而且,这个窗口是个独立的控制台窗口。 MSDN的解释:A process can be associated with only one console, so the AllocConsole function fails if the calling process already has a console. 还有段:If the calling process creates a child process, the child inherits the new console. 二。显示Hello World,WriteConsole 有了console,我们还需要获取它的句柄HANDLE,然后才能在上面显示。方法是 GetStdHandle,它会获取前面我们AllocConsole得到的cmd窗口的句柄;若未调用AllocConsole,将获取标准的输入输出窗口句柄。 MSDN的解释:The GetStdHandle function returns a handle for the standard input, standard output, or standard error device. HANDLE hdlWrite = GetStd
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值