// OGCAssist.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "OGCAssist.h"
#include <process.h>

namespace Assist
{
	// 全局Call Data;
	CALLDATA _cd_Go;
	CALLDATA _cd_Connect;
	CALLDATA _cd_Disconnect;
	CALLDATA _cd_CheckFW;
	CALLDATA _cd_CheckFW_CommunicationError;
	CALLDATA _cd_SaveAsOutputData;
	CALLDATA _cd_Go_SN;
	CALLDATA _cd_Go_CommunicationError;
	CALLDATA _cd_Go_SetCommunicationError;
	CALLDATA _cd_Initial_failed;
	CALLDATA _cd_ExternalException;
	BOOL bConnectStatus = FALSE;
	BOOL bHijacked = FALSE;

	// 调试耗时值ms;
	DWORD dwElapsed = 0;

	TCHAR g_szGoSN[32] = {0};

	DWORD dwCallAddr = 0;

	// 8组全局寄存器存储;
	DWORD dwEAX = 0;
	DWORD dwEBX = 0;
	DWORD dwECX = 0;
	DWORD dwEDX = 0;
	DWORD dwEBP = 0;
	DWORD dwESP = 0;
	DWORD dwESI = 0;
	DWORD dwEDI = 0;

	void InitCallData();
	BOOL HijackedAllCall();
	BOOL RestoreAllCall();
	BOOL HijackedCall(CALLDATA *pCallData);
	BOOL RecoveryCall(CALLDATA *pCallData);
	// 自定义跳转函数;
	void Call_MyDisconnect();
	void Call_MyConnect();
	void Call_MyGo();
	void Call_MyGoSN();
	void Call_MyCheckFW();
	void Call_MyCheckFWCommunicationError();
	void Call_MySaveAsOutputData();
	void Call_MyInitial_Failed();
	void Call_MyGoCommunicationError();
	void Call_MyGoSetCommunicationError();
	void Call_MyExternalException();

	void InitCallData()
	{
#pragma region 启动时Initial Communication：需要程序启动时注入;
		// 00401EB8 | E8 7BCB0C00 | call demo.4CEA38 |
		_cd_Initial_failed.myCall = Call_MyInitial_Failed;
		// 00401EBD | FF4D CC | dec dword ptr ss:[ebp-34] |
		_cd_Initial_failed.dwBack2Addr = 0x00401EBD;
		// 00401EB8 | E8 7BCB0C00 | call demo.4CEA38 |
		_cd_Initial_failed.dwOriginalAddr = 0x00401EB8;
		_cd_Initial_failed.dwOriginalCallAddr = 0x004CEA38;

		_cd_Initial_failed.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Initial_failed.szMyCallData, 0x90, CALL_LEN);
		_cd_Initial_failed.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Initial_failed.szMyCallData[1]) = (DWORD)_cd_Initial_failed.myCall - _cd_Initial_failed.dwOriginalAddr - JMP_DLEN;
#pragma endregion

#pragma region Connect按钮劫持
		//00415ECB | 0F84 6A040000 | je demo.41633B 
		_cd_Connect.myCall = Call_MyConnect;
		// 00415ED1 | 6A 00                  | push 0 
		_cd_Connect.dwBack2Addr = 0x00415ED1;
		_cd_Connect.dwOriginalAddr = 0x00415ECB;
		_cd_Connect.dwOriginalCallAddr = 0x0041633B;	// 此处是JMP，注意注入时不要调用为Call

		_cd_Connect.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Connect.szMyCallData, 0x90, CALL_LEN);
		_cd_Connect.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Connect.szMyCallData[1]) = (DWORD)_cd_Connect.myCall - _cd_Connect.dwOriginalAddr - JMP_DLEN;
#pragma endregion

#pragma region Disconnect按钮劫持
		// 0043790B | E8 E4C90900 | call demo.4D42F4 | # 此处可能用于SetWindowText之类处理
		// 00437910 | FF4D F4 | dec dword ptr ss:[ebp-C]                 |
		_cd_Disconnect.myCall = Call_MyDisconnect;
		_cd_Disconnect.dwBack2Addr = 0x00437910;
		_cd_Disconnect.dwOriginalAddr = 0x0043790B;
		_cd_Disconnect.dwOriginalCallAddr = 0x004D42F4;

		_cd_Disconnect.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Disconnect.szMyCallData, 0x90, CALL_LEN);
		_cd_Disconnect.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Disconnect.szMyCallData[1]) = (DWORD)_cd_Disconnect.myCall - _cd_Disconnect.dwOriginalAddr - JMP_DLEN;
#pragma endregion

#pragma region ExternalException
		// 必须获取模块地址：ca210ctrl.dll
		HMODULE hModule = GetModuleHandle(_T("Ca210Ctrl.dll"));
		// 044D677C | FF15 78645404 | call dword ptr ds:[<&RaiseException>] |
		_cd_ExternalException.myCall = Call_MyExternalException;
		// 044D6782 | 5F | pop edi |
		_cd_ExternalException.dwBack2Addr = (DWORD)hModule + 0x106782;
		_cd_ExternalException.dwOriginalAddr = (DWORD)hModule + 0x10677C;
		_cd_ExternalException.dwOriginalCallAddr = 0x769F05B0;

		_cd_ExternalException.nMyCallDataLen = JMP_DLEN;
		memset(_cd_ExternalException.szMyCallData, 0x90, CALL_LEN);
		_cd_ExternalException.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_ExternalException.szMyCallData[1]) = (DWORD)_cd_ExternalException.myCall - _cd_ExternalException.dwOriginalAddr - JMP_DLEN;
#pragma endregion

#pragma region Go按钮劫持
		/* 成功执行后的处理 */
		_cd_Go.myCall = Call_MyGo;
		_cd_Go.dwBack2Addr = 0x004376B0;
		// 004376AB | E8 50A30C00 | call demo.501A00 
		_cd_Go.dwOriginalAddr = 0x004376AB;
		_cd_Go.dwOriginalCallAddr = 0x00501A00;

		_cd_Go.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Go.szMyCallData, 0x90, CALL_LEN);
		_cd_Go.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Go.szMyCallData[1]) = (DWORD)_cd_Go.myCall - _cd_Go.dwOriginalAddr - JMP_DLEN;

		// 获取SN字符串;
		// 00417AEC | E8 9BA5FEFF | call demo.40208C |
		// 00417AF1 | E8 722C0700 | call demo.48A768 |
		_cd_Go_SN.myCall = Call_MyGoSN;
		_cd_Go_SN.dwBack2Addr = 0x00417AF1;
		// 004376AB | E8 50A30C00 | call demo.501A00 
		_cd_Go_SN.dwOriginalAddr = 0x00417AEC;
		_cd_Go_SN.dwOriginalCallAddr = 0x0040208C;

		_cd_Go_SN.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Go_SN.szMyCallData, 0x90, CALL_LEN);
		_cd_Go_SN.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Go_SN.szMyCallData[1]) = (DWORD)_cd_Go_SN.myCall - _cd_Go_SN.dwOriginalAddr - JMP_DLEN;

		// 消除 Set Communication Error 弹框;
		// 00417FCD | E8 666A0B00 | call demo.4CEA38 |
		_cd_Go_SetCommunicationError.myCall = Call_MyGoSetCommunicationError;
		_cd_Go_SetCommunicationError.dwBack2Addr = 0x00417FD2;
		// 00417FD2 | FF8D F4E8FFFF| dec dword ptr ss:[ebp-170C]|
		_cd_Go_SetCommunicationError.dwOriginalAddr = 0x00417FCD;
		_cd_Go_SetCommunicationError.dwOriginalCallAddr = 0x004CEA38;

		_cd_Go_SetCommunicationError.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Go_SetCommunicationError.szMyCallData, 0x90, CALL_LEN);
		_cd_Go_SetCommunicationError.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Go_SetCommunicationError.szMyCallData[1]) = (DWORD)_cd_Go_SetCommunicationError.myCall - _cd_Go_SetCommunicationError.dwOriginalAddr - JMP_DLEN;

		// 消除Communication Error弹框;
		// 00404408 | E8 2BA60C00| call demo.4CEA38| 
		_cd_Go_CommunicationError.myCall = Call_MyGoCommunicationError;
		_cd_Go_CommunicationError.dwBack2Addr = 0x0040440D;
		// 0040440D | FF4D BC | dec dword ptr ss:[ebp-44] | 
		_cd_Go_CommunicationError.dwOriginalAddr = 0x00404408;
		_cd_Go_CommunicationError.dwOriginalCallAddr = 0x004CEA38;

		_cd_Go_CommunicationError.nMyCallDataLen = JMP_DLEN;
		memset(_cd_Go_CommunicationError.szMyCallData, 0x90, CALL_LEN);
		_cd_Go_CommunicationError.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_Go_CommunicationError.szMyCallData[1]) = (DWORD)_cd_Go_CommunicationError.myCall - _cd_Go_CommunicationError.dwOriginalAddr - JMP_DLEN;
#pragma endregion

#pragma region CheckFW按钮处理
		// 00404458 | E8 E7F70400       | call demo.453C44 | # 此处应该是执行I2CReadEx
		_cd_CheckFW.myCall = Call_MyCheckFW;	// 成功获取版本后跳转处理;
		// 0040445D | 83C4 1C           | add esp,1C                    |
		_cd_CheckFW.dwBack2Addr = 0x0040445D;
		_cd_CheckFW.dwOriginalAddr = 0x00404458;
		_cd_CheckFW.dwOriginalCallAddr = 0x453C44;

		_cd_CheckFW.nMyCallDataLen = JMP_DLEN;
		memset(_cd_CheckFW.szMyCallData, 0x90, CALL_LEN);
		_cd_CheckFW.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_CheckFW.szMyCallData[1]) = (DWORD)_cd_CheckFW.myCall - _cd_CheckFW.dwOriginalAddr - JMP_DLEN;

		/* 针对弹框Communication Error的消除处理 */
		// 00404408 | E8 2BA60C00       | call demo.4CEA38 | # Dailogs::ShowMessage(string) 弹出提示框：Communication Error
		_cd_CheckFW_CommunicationError.myCall = Call_MyCheckFWCommunicationError;	// 成功获取版本后跳转处理;
		// 0040440D | FF4D BC           | dec dword ptr ss:[ebp-44]     | [ebp-44]:&"脥I"
		_cd_CheckFW_CommunicationError.dwBack2Addr = 0x0040440D;
		_cd_CheckFW_CommunicationError.dwOriginalAddr = 0x00404408;
		_cd_CheckFW_CommunicationError.dwOriginalCallAddr = 0x4CEA38;

		_cd_CheckFW_CommunicationError.nMyCallDataLen = JMP_DLEN;
		memset(_cd_CheckFW_CommunicationError.szMyCallData, 0x90, CALL_LEN);
		_cd_CheckFW_CommunicationError.szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&_cd_CheckFW_CommunicationError.szMyCallData[1]) = (DWORD)_cd_CheckFW_CommunicationError.myCall - _cd_CheckFW_CommunicationError.dwOriginalAddr - JMP_DLEN;
#pragma endregion
	}

	BOOL HijackedAllCall()
	{
		BOOL bHijack=FALSE;
		if ( !(bHijack = HijackedCall(&_cd_Connect)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_Disconnect)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_Go)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_Go_SN)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_Go_CommunicationError)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_Go_SetCommunicationError)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_ExternalException)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_CheckFW)) )
			goto end;

		if ( !(bHijack = HijackedCall(&_cd_CheckFW_CommunicationError)) )
			goto end;

end:
		return (bHijacked = bHijack);
	}

	BOOL RestoreAllCall()
	{
		BOOL bRestor = FALSE;
		if ( !(bRestor = RecoveryCall(&_cd_Connect)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_Disconnect)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_Go)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_Go_SN)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_Go_CommunicationError)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_Go_SetCommunicationError)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_ExternalException)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_CheckFW)) )
			goto end;

		if ( !(bRestor = RecoveryCall(&_cd_CheckFW_CommunicationError)) )
			goto end;

end:
		return ( bHijacked = !bRestor );
	}

	// 劫持原始地址;
	BOOL HijackedCall(CALLDATA *pCallData)
	{
		if ( !pCallData )
			return FALSE;

		memset(pCallData->szMyCallData, 0, CALL_LEN);
		pCallData->szMyCallData[0] = 0xE9; // 汇编硬编码：jmp [4字节地址];
		*(LPDWORD)(&pCallData->szMyCallData[1]) = (DWORD)pCallData->myCall - pCallData->dwOriginalAddr - CALL_LEN;

		HANDLE hProc = GetCurrentProcess();
		// 将要劫持的地址指令备份下来;
		memset(pCallData->szOriginalAddrData, 0, CALL_LEN);
		if ( !ReadProcessMemory(hProc, (LPVOID)pCallData->dwOriginalAddr, pCallData->szOriginalAddrData, CALL_LEN, NULL) )
		{
			//MessageBox(NULL, _T("读取内存失败"), _T("提示"),MB_OK);
			return FALSE;
		}

		// 将我们的Call地址指令写入目标地址;
		if ( !WriteProcessMemory(hProc, (LPVOID)pCallData->dwOriginalAddr, pCallData->szMyCallData, CALL_LEN, NULL) )
		{
			//MessageBox(NULL, _T("写入内存失败"), _T("提示"),MB_OK);
			return FALSE;
		}

		return TRUE;
	}

	BOOL RecoveryCall(CALLDATA *pCallData)
	{
		if ( !pCallData )
			return FALSE;

		// 将我们的Call地址指令写入目标地址;
		if ( !WriteProcessMemory(GetCurrentProcess(), (LPVOID)pCallData->dwOriginalAddr, pCallData->szOriginalAddrData, CALL_LEN, NULL) )
		{
			//MessageBox(NULL, _T("写入内存失败"), _T("提示"),MB_OK);
			return FALSE;
		}

		return TRUE;
	}

};

// MyCall处理;
namespace Assist
{
	void MyInitialFailed()
	{
		//MessageBox(NULL, _T("MyInitialFailed"), _T("MyInitialFailed"), MB_OK);
		// 向服务端发送消息;
	}

	void __declspec(naked) Call_MyInitial_Failed()
	{
		__asm pushad;
		MyInitialFailed();
		__asm popad;
		// 不执行原call:原Call是Messagebox弹框，需要消除掉它;
		// __asm call _cd_Initial_failed.dwOriginalCallAddr;
		__asm jmp _cd_Initial_failed.dwBack2Addr;
	}

	void __declspec(naked) Call_MySaveAsOutputData()
	{

	}

	void MyGo()
	{   
		CHAR szMsg[MAX_PATH];
		DWORD dwElapsedAddr = 0x0052DF54;
		DWORD dwSNAddr = dwEBP - 0x5D0;
		sprintf_s(szMsg, "MyGo耗时:%ldms, SN:%08X, %s", *(LPDWORD)dwElapsedAddr, dwSNAddr, (CHAR*)(*(LPDWORD)dwSNAddr));
		MessageBoxA(NULL, szMsg, "MyGo", MB_OK);
		// 向服务器发送消息;
	}

	void __declspec(naked) Call_MyGo()
	{
		// 备份寄存器;
		__asm{
			// 保存寄存器;
			mov dwEAX, EAX;
			mov dwEBX, EBX;
			mov dwECX, ECX;
			mov dwEDX, EDX;
			mov dwEBP, EBP;
			mov dwESP, ESP;
			mov dwESI, ESI;
			mov dwEDI, EDI;
		}

		MyGo();

		__asm{
			// 恢复寄存器; 
			mov EAX, dwEAX;
			mov EBX, dwEBX;
			mov ECX, dwECX;
			mov EDX, dwEDX;
			mov EBP, dwEBP;
			mov ESP, dwESP;
			mov ESI, dwESI;
			mov EDI, dwEDI;
			// 执行原Call;
			call _cd_Go.dwOriginalCallAddr;
			// 返回劫持地址下一行;
			jmp _cd_Go.dwBack2Addr
		}
	}

	void MyGoSN()
	{
		CHAR szMsg[MAX_PATH];
		DWORD dwSNAddr = dwEBP - 0x5D0;
		//_stprintf_s(szMsg, _T("MyGo %08X, %08X, %08X, %s"), dwEAX, dwSNAddr, DWORD(*(LPDWORD)dwSNAddr), (TCHAR*)(*(LPDWORD)dwSNAddr));
		sprintf_s(szMsg, "MyGo %08X, %08X, %08X, %s", dwEAX, dwSNAddr, DWORD(*(LPDWORD)dwSNAddr), (CHAR*)(*(LPDWORD)dwSNAddr));
		MessageBoxA(NULL, szMsg, "MyGoSN", MB_OK);
		// 向服务器发送消息;
	}

	void __declspec(naked) Call_MyGoSN()
	{
		// 备份寄存器;
		__asm{
			// 保存寄存器;
			mov dwEAX, EAX;
			mov dwEBX, EBX;
			mov dwECX, ECX;
			mov dwEDX, EDX;
			mov dwEBP, EBP;
			mov dwESP, ESP;
			mov dwESI, ESI;
			mov dwEDI, EDI;
		}

		MyGoSN();

		__asm{
			// 恢复寄存器; 
			mov EAX, dwEAX;
			mov EBX, dwEBX;
			mov ECX, dwECX;
			mov EDX, dwEDX;
			mov EBP, dwEBP;
			mov ESP, dwESP;
			mov ESI, dwESI;
			mov EDI, dwEDI;
			// 执行原Call;
			call _cd_Go_SN.dwOriginalCallAddr;
			// 返回劫持地址下一行;
			jmp _cd_Go_SN.dwBack2Addr
		}
	}

	void MyGoSetCommunicationError()
	{
		MessageBox(NULL, _T("MyGoSetCommunicationError"), _T("劫持"), MB_OK);
		// 向服务器发送消息;
	}

	void __declspec(naked) Call_MyGoSetCommunicationError()
	{
		// 备份寄存器;
		__asm{
			// 保存寄存器;
			mov dwEAX, EAX;
			mov dwEBX, EBX;
			mov dwECX, ECX;
			mov dwEDX, EDX;
			mov dwEBP, EBP;
			mov dwESP, ESP;
			mov dwESI, ESI;
			mov dwEDI, EDI;
		}

		MyGoSetCommunicationError();

		__asm{
			// 恢复寄存器; 
			mov EAX, dwEAX;
			mov EBX, dwEBX;
			mov ECX, dwECX;
			mov EDX, dwEDX;
			mov EBP, dwEBP;
			mov ESP, dwESP;
			mov ESI, dwESI;
			mov EDI, dwEDI;
			// 执行原Call;
			//call _cd_Go_SetCommunicationError.dwOriginalCallAddr	// 经验证,即使不执行原call，也会弹异常框;
			// 返回劫持地址下一行;
			jmp _cd_Go_SetCommunicationError.dwBack2Addr
		}
	}

	void MyGoCommunicationError()
	{
		MessageBox(NULL, _T("MyGoCommunicationError"), _T("劫持"), MB_OK);
		// 向服务器发送消息;
	}

	void __declspec(naked) Call_MyGoCommunicationError()
	{
		// 备份寄存器;
		__asm{
			// 保存寄存器;
			mov dwEAX, EAX;
			mov dwEBX, EBX;
			mov dwECX, ECX;
			mov dwEDX, EDX;
			mov dwEBP, EBP;
			mov dwESP, ESP;
			mov dwESI, ESI;
			mov dwEDI, EDI;
		}

		MyGoCommunicationError();

		__asm{
			// 恢复寄存器; 
			mov EAX, dwEAX;
			mov EBX, dwEBX;
			mov ECX, dwECX;
			mov EDX, dwEDX;
			mov EBP, dwEBP;
			mov ESP, dwESP;
			mov ESI, dwESI;
			mov EDI, dwEDI;
			// 执行原Call;
			//call _cd_Go_CommunicationError.dwOriginalCallAddr
			// 返回劫持地址下一行;
			jmp _cd_Go_CommunicationError.dwBack2Addr
		}
	}

	BOOL MyConnect()
	{
		// 读取AL的值; 0表示Connect失败;1表示成功;
		BYTE AL = LOBYTE(LOWORD(dwEAX));
		if ( AL == 0 )
		{
			bConnectStatus = FALSE;
			MessageBox(NULL, _T("连接失败"), _T("连接提示"), MB_OK);
			return FALSE;
		}
		else
		{
			bConnectStatus = TRUE;
			MessageBox(NULL, _T("连接成功"), _T("连接提示"), MB_OK);
		}

		// 向服务器发送消息;

		return TRUE;
	}

	void __declspec(naked) Call_MyConnect()
	{
		// 备份寄存器;
		__asm mov dwEAX, eax;
		__asm pushad;

		if ( MyConnect() )
		{
			__asm{
				// 恢复寄存器; 
				popad;
				// 成功：则继续正常的流程;
				jmp _cd_Connect.dwBack2Addr;
			}

		}
		else
		{
			__asm{
				// 恢复寄存器; 
				popad;
				// 失败：JMP到出错处理;
				jmp _cd_Connect.dwOriginalCallAddr;
			}
		}   
	}

	void MyExternalException()
	{
		// 产生异常,设置为未连接;
		bConnectStatus = FALSE;
		MessageBox(NULL, _T("MyExternalExceptionE06D7363，重启异常待重启"), _T("提示"), MB_OK);
		// 向服务器发送消息;
		::exit(0);
	}

	void __declspec(naked) Call_MyExternalException()
	{
		// 备份寄存器;
		__asm {
			pushad;
		}

		MyExternalException();

		__asm
		{
			// 恢复寄存器; 
			popad;
			// 失败：JMP到出错处理;
			call _cd_ExternalException.dwOriginalCallAddr;
			jmp _cd_ExternalException.dwBack2Addr;
		} 
	}

	void MyDisconnect()
	{
		bConnectStatus = FALSE;
		MessageBox(NULL, _T("MyDisconnect Function"), _T("MyDisconnect"), MB_OK);
		// 向服务器发送消息;
	}

	void __declspec(naked) Call_MyDisconnect()
	{
		__asm pushad;
		MyDisconnect();
		__asm
		{
			popad;
			call _cd_Disconnect.dwOriginalCallAddr;
			jmp _cd_Disconnect.dwBack2Addr;
		}
	}

	void __declspec(naked) Call_MyCheckFW()
	{
		// 备份寄存器;
		__asm pushad;

		MessageBox(NULL, _T("Call_MyCheckFW"), _T("MyCheckFW"), MB_OK);

		__asm{
			// 恢复寄存器; 
			popad;
			// 执行原call;
			call _cd_CheckFW.dwOriginalCallAddr;
			// 最后返回原Call地址下一行;
			jmp _cd_CheckFW.dwBack2Addr;
		}
	}

	void __declspec(naked) Call_MyCheckFWCommunicationError()
	{
		// 备份寄存器;
		__asm pushad;

		MessageBox(NULL, _T("Call_MyCheckFWCommunicationError"), _T("MyCheckFWCommunicationError"), MB_OK);

		__asm{
			// 恢复寄存器; 
			popad;
			// 消除原call;
			// call _cd_CheckFW.dwOriginalCallAddr;
			// 最后返回原Call地址下一行;
			jmp _cd_CheckFW_CommunicationError.dwBack2Addr;
		}
	}
};