MetaTrader软件的功能扩展(关于程序补丁制作的一个例子)

MetaTrader是一款外汇业务在线交易平台软件,个人感觉其界面非常人性化,操作起来也很方便。在国内其有很多种版本,如RBS MetaTrader,MetaTrader4,IBFSMetaTrader4等,刚好有一朋友需要扩展功能,因此就好好研究了下。

朋友在一证券公司上班,需用MetaTrader实现功能如下:

1,共有10台机器,其中一台为服务器,另9台为客户机。

2,当服务器切换币种汇率或图表等窗口时,客户机也需相应地切换。

3,服务器可设定每隔几分钟在几种选定的币种中切换窗口或更换图表,此时客户机也需相应操作。

简单说说实现方法:

1,用ollydbg和IDA逆出MetaTrader的大概工作流程,发现当切换窗口或更换图表是运用发送消息的方式。截取对应的消息值和消息句柄。

2,简单地利用UDP通信实现服务器与客户机的同步。

3,当拦截到服务器有切换窗口或更换图表的操作时,即拦截其操作,把拦截到的参数值作为参数用UDP协议传送到客户机,客户机接到相应命令后即实行相应操作。

简单地摘出程序分析:


UINT PatchProcess(LPVOID ThreadParam)
{
CEmbededWizardPatchDlg* wndProgress = (CEmbededWizardPatchDlg *) ThreadParam;//把它变成CSCommTestDlg这个类的指针
ASSERT(wndProgress);
ASSERT(wndProgress->IsKindOf(RUNTIME_CLASS(CEmbededWizardPatchDlg)));
HWND hwnd;
CString strTemp=_T(""),strTitle=_T("NULL");


CString strWindowName[21] =
{
"EURUSD",//0
"USDJPY",//1
"GBPUSD",//2
"AUDUSD",//3
"USDCHF",//4
"USDCAD",//5
"NZDUSD",//6
"EURAUD",//7
"EURCHF",//8
"EURGBP",//9
"EURJPY",//10
"GBPCHF",//11
"GBPJPY",//12
"GOLD",//13
"SILVER",//14
"CL",//15
"USDX",//16
"DJI",//17
"NASDAQ",//18
"HSI",//19
"S&P500"//20
};


STARTUPINFO si ;
PROCESS_INFORMATION pi ;
ZeroMemory(&si, sizeof(STARTUPINFO)) ;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)) ;
si.cb = sizeof(STARTUPINFO) ;

BOOL WhileDoFlag=TRUE;
BYTE ReadBuffer[MAX_PATH]={0};
BYTE dwINT3code[1]={0xCC};
BYTE dwWindowBreadPointOldbyte[1]={0};
BYTE dwTemplateBreadPointOldbyte[1]={0};

if( !CreateProcess(SZFILENAME,
NULL,
NULL,
NULL,
FALSE,
DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS,
NULL,
NULL,
&si,
&pi )
)
{
MessageBox(NULL, "CreateProcess Failed.", "ERROR", MB_OK);
return FALSE;
}


DEBUG_EVENT DBEvent ;
CONTEXT Regs ;
DWORD dwState,Oldpp;


Regs.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS ;

while (WhileDoFlag) {
WaitForDebugEvent (&DBEvent, INFINITE);
dwState = DBG_EXCEPTION_NOT_HANDLED ;
switch (DBEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
//如果进程开始,则将断点地址的代码改为INT3中断,同时备份原机器码
ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_NEWWINDOW), &dwWindowBreadPointOldbyte, sizeof(dwWindowBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW,&dwINT3code, 1,NULL); //打补丁

ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_TEMPLATE), &dwTemplateBreadPointOldbyte, sizeof(dwTemplateBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE,&dwINT3code, 1,NULL); //打补丁

dwState = DBG_CONTINUE ;
break;

case EXIT_PROCESS_DEBUG_EVENT :
WhileDoFlag=FALSE;
wndProgress->PostMessage(WM_CLOSE,NULL,NULL );//关闭整个程序
break ;

case EXCEPTION_DEBUG_EVENT:
switch (DBEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
{
GetThreadContext(pi.hThread, &Regs) ;
if(Regs.Eip==BREAK_POINT_NEWWINDOW+1){//0x7C92120F BREAK_POINT_NEWWINDOW+1
//中断触发异常事件,这个是真正需要的中断。先恢复原机器码
Regs.Eip--;
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW,&dwWindowBreadPointOldbyte, 1,NULL);

进行真正需要的操作,把对应的栈地址写成需要的数据/
hwnd = ::FindWindow("MetaQuotes::MetaTrader::4.00",NULL);//第一个参数为类名,返回找到窗口的句柄
GetWindowText(hwnd,strTemp.GetBuffer(MAX_PATH),MAX_PATH);
if(strTemp.Find(strTitle)<0) //没有找到,表示可能跟之前菜单不一样
{
strTemp.ReleaseBuffer();
// int length1 = strTemp.GetLength();//注意,在GetLength前一定要先ReleaseBuffer。
int index1 = strTemp.Find("-");
int index2 = strTemp.Find(",");
if(index1 > 0 && index2 >0)//表示这个标题栏有相应信息
{

strTemp = strTemp.Mid(index1 + 2,index2 - index1 - 2);
index1 =strTemp.Find("-");
if(index1 > 0)
{
if(strTemp.Find("[")>0)
strTemp = strTemp.Right(strTemp.GetLength() - index1 - 3);
else
strTemp = strTemp.Right(strTemp.GetLength() - index1 - 2);
}else
{
if(strTemp.Find("[")>=0)
strTemp = strTemp.Right(strTemp.GetLength()-1);

}

if(strTemp != strTitle)
{
strTitle = strTemp;
strTemp = "WINDOW="+strTemp;
wndProgress->SendUDPMessage(strTemp);
}
}

}
/
//---------------------------设置另一个临时断点BREAK_POINT_NEWWINDOW_TEMP,相互设置,用来每次都能中断------------------
ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_NEWWINDOW_TEMP), &dwWindowBreadPointOldbyte, sizeof(dwWindowBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW_TEMP, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW_TEMP,&dwINT3code, 1,NULL); //设置成INT3中断
SetThreadContext(pi.hThread, &Regs) ;
}
else if(Regs.Eip==BREAK_POINT_NEWWINDOW_TEMP+1){
//中断触发异常事件,这个中断仅仅是为了能设下面这个中断
Regs.Eip--;
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW_TEMP,&dwWindowBreadPointOldbyte, 1,NULL);//恢复操作
//---------------------------进行真正需要的操作,把对应的栈地址写成需要的数据

//---------------------------设置另一个临时断点,相互设置,用来每次都能中断------------------
ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_NEWWINDOW), &dwWindowBreadPointOldbyte, sizeof(dwWindowBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_NEWWINDOW,&dwINT3code, 1,NULL); //设置成INT3中断

SetThreadContext(pi.hThread, &Regs) ;

}

else if(Regs.Eip==BREAK_POINT_TEMPLATE+1){
//中断触发异常事件,这个中断仅仅是为了能设下面这个中断
Regs.Eip--;
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE,&dwTemplateBreadPointOldbyte, 1,NULL);//恢复操作
//---------------------------进行真正需要的操作,把对应的栈地址写成需要的数据
strTemp.Format("%d",Regs.Edx);
strTemp = "TEMPLATE="+strTemp;
wndProgress->SendUDPMessage(strTemp);

//---------------------------设置另一个临时断点,相互设置,用来每次都能中断------------------
ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_TEMPLATE_TEMP), &dwTemplateBreadPointOldbyte, sizeof(dwTemplateBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE_TEMP, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE_TEMP,&dwINT3code, 1,NULL); //设置成INT3中断

SetThreadContext(pi.hThread, &Regs) ;

}
else if(Regs.Eip==BREAK_POINT_TEMPLATE_TEMP+1){
//中断触发异常事件,这个中断仅仅是为了能设下面这个中断
Regs.Eip--;
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE_TEMP,&dwTemplateBreadPointOldbyte, 1,NULL);//恢复操作
//---------------------------设置另一个临时断点,相互设置,用来每次都能中断------------------
ReadProcessMemory(pi.hProcess, (LPCVOID)(BREAK_POINT_TEMPLATE), &dwTemplateBreadPointOldbyte, sizeof(dwTemplateBreadPointOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)BREAK_POINT_TEMPLATE,&dwINT3code, 1,NULL); //设置成INT3中断

SetThreadContext(pi.hThread, &Regs) ;

}

dwState = DBG_CONTINUE ;
break;
}
}
break;
}


ContinueDebugEvent(pi.dwProcessId, DBEvent.dwThreadId, dwState) ;
} //.end while
CloseHandle(pi.hProcess) ;
CloseHandle(pi.hThread) ;
AfxGetMainWnd()->SendMessage(WM_CLOSE);
return TRUE;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值