朋友在一证券公司上班,需用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;
}