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

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

    朋友在一证券公司上班,需用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
    评论
很抱歉,作为AI语言模型,我无法编写并执行代码。但是,我可以为您提供一些基本的步骤和建议,帮助您开始编写一个obv量化交易程序。 首先,您需要了解OBV指标。OBV(On Balance Volume)是一种基于成交量和价格变化之间的关系计算出来的技术指标。OBV指标可以用来确认价格趋势、预测价格趋势的转折点等。 接下来,您需要选择一个编程语言和交易平台。常用的编程语言包括Python、C++、Java等。常用的交易平台包括MetaTrader、TradeStation、NinjaTrader等。 然后,您需要编写代码来计算OBV指标。这可以通过读取历史交易数据来完成,例如开盘价、收盘价、最高价、最低价和成交量等数据。您可以使用Python中的pandas库或其他适合您所选编程语言的库来处理数据。 接下来,您需要编写代码来执行交易。这可以通过设置交易规则和条件来完成。例如,当OBV指标上升时,您可以设置程序执行买入操作,当OBV指标下降时,您可以设置程序执行卖出操作。您可以使用交易平台提供的API或其他适合您所选编程语言的库来执行交易。 最后,您需要测试您的程序并进行优化。您可以使用历史交易数据来测试您的程序,找出其中的漏洞和问题,并进行调整和优化。您还可以使用模拟交易平台来测试您的程序,在实际交易之前进行充分的测试和优化。 需要注意的是,编写量化交易程序需要充分的专业知识和经验,并且需要考虑到市场波动、交易成本、风险管理等因素。因此,建议您寻求专业人士的帮助和指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值