RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 927959
Accepted
nick_n_a
nick_n_a
Asked:2020-01-03 18:39:45 +0000 UTC2020-01-03 18:39:45 +0000 UTC 2020-01-03 18:39:45 +0000 UTC

c#和调试模式

  • 772

是否可以在“跟踪”模式下运行 C# CLR 代码?有什么方法可以拦截 Invoke 调用吗?如何为 c# 代码编写调试器?目前唯一想到的就是模拟CLR代码的执行,但是这里需要模拟器上一大堆代码,然后……截取现成库的代码,因为有CLR- Native-CLR 桥接,所以模拟器没那么简单。我с++-cli认为实现这个奇迹是现实的……但是……我认为有某种特殊的模式可以很容易地开启。看到已经有 VS 的“弯曲”类似物......如何在其他项目中解决这个问题?

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    nick_n_a
    2020-01-11T20:02:27Z2020-01-11T20:02:27Z

    如何编写调试器,或者更确切地说是跟踪器。

    1. 从哪里开始
    2. 创建 ICorDebug 和 ICorProcess
    3. 创建处理程序
    4. 处理程序升级

    本文假设您具有 c++ 的基本知识。调试器可以用 C++ 编写,甚至可以用 C# 编写,但我更喜欢 C++。我将展示基础 - 如何编写示踪剂。

    1. 从哪里开始。让我们创建一个简单的c#

      using System;
      public class Demo {
         public static void Main(string[] args) {
           Console.WriteLine("Hello world");
           }
      }
      

      让我们把它捡起来c:\windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /platform:x86 /target:1.exe 1.cs /pdb:1.pdb /debug

    该工作室有一个 SDK 文件夹,您可以在其中找到必要的标头。我这里有SDK\v2.0\include。您将需要以下库

        #include <windows.h>
        #include "COR\CorHdr.h"
        #include "COR\cor.h"
        #include "COR\cordebug.h"
    
        ICorDebug* dbg; // Библиотека дебаггера
        ICorProcess* process;//Процесс для отладки. Будет для одного процесса
    

    起初我想——我会创建 CoCreateIntance,有一个 CreateProcess 函数——一切都会好起来的,但没有。

    1. 创建 ICorDebug 和 ICorProcess。如果创建了第一个,则可以轻松创建第二个。有几种方法可以创建它,我将展示其中一种。如果 mscoree.dll 链接失败,请通过 LoadLibrary 和 GetProcAddress 进行连接。有两个函数,一个检查版本,另一个创建 ICorDebug。

      void main(){
        wchar_t* module = "c:\\yourdebug\\1.exe";
        wchar_t ver[20];
        GetRequestedRuntimeVersion(module,ver,sizeof(ver),&dw);//mscoree.dll
        hr=CreateDebugginInterfaceFromVersion(CorDebugVersion_2_0,ver,&dbg);
        // hr=CreateDebugginInterfaceFromVersion(CorDebugVersion_2_0+1,ver,&dbg); // для .NET 4
        // Если не подходит версия - пробуйте менять первый аргумент
        //TODO: проверка hr
        hr = dbg->Initialize();
        STARTUPINFOW si = {sizeof(STARTUPINFOW),0,};
        PROCESS_INFORMATION pi = {0,};
        // dbg->SetUnmanagedHandler           
        dbg->SetManagedHandler(MgrHandler); // ниже будет
        // TODO: параметры запуска можно будет доделать
        hr =  dbg->CreateProcess(module,module,0,0,true,
          CREATE_NEW_CONSOLE, L"\0\0\0\0", L".", &si, &pi,0,&process);
        // TODO: цикл ожидания конца работы дебагера
        for (int i=0;i<100;i++)
          WaitForSingleObject(pi.hProcess,1000);
        }
      

      嗯……快完成了。或者几乎不算。我用SetManagedHandler受了很长时间,如果该功能不起作用,那么您还没有描述所有处理程序。现在让我们继续...

    2. 创建一个处理程序。在 FrameWork 2.0 版本中,事实证明需要支持两个回调。好吧,......在处理程序中写一些东西。有必要在您可以编写的任何地方将其pAppDomain->Continue();输入到每个处理程序中。我不会给出整个代码,我会给出主要内容。此外,我们只讨论这个处理程序。

      class MGRHandler:public ICorDebugManagedCallback,ICorDebugManagedCallback2{
         // 1 Рассказать какие у нас калбеки
         HRESULT __stdcall QueryInterface(REFIID riid,void**ppvObject){
            if (riid==IID_ICorDebugManagedCallback){
                   *ppvObject=(ICorDebugManagedCallback*)this;//Первый
                    return 0;
                    }
            if (riid==IID_ICorDebugManagedCallback2){
                    *ppvObject=(ICorDebugManagedCallback2*)this;//Второй
                    return 0;
                    }
            return (HRESULT)-1;
            }
         // 2 Вначале нас бросит сюда
         HRESULT __stdcall CreateProcess(ICorDebugProcess* pProcess){
           pProcess->Continue(0);
           }
         // 3 Потом будет создан "домен"
         HRESULT __stdcall CreateAppDomain(ICorDebugProcess *pProcess,
         ICorDebugAppDomain *pAppDomain) {
             pAppDomain->Attach(); // Переводим домен в дебаг режим
             pProcess->Continue(0);
             return 0;};
         // 4 Ставим Continue тут обязательно, желательно везде
         HRESULT __stdcall LoadAssembly(ICorDebugAppDomain *pAppDomain,
          ICorDebugAssembly *pAssembly)  {           
          pAppDomain->Continue(0);return 0;
          }
         HRESULT __stdcall CreateThread(ICorDebugAppDomain *pAppDomain,
          ICorDebugThread *thread) {          
             pAppDomain->Continue(0);return 0;
             };
      

      类似地 f-tionBreakpoint等NameChange。函数拦截应该在一个模块中完成,如下所示:

      HRESULT __stdcall LoadModule(ICorDebugAppDomain *pAppDomain,
      ICorDebugModule *pModule) {
          ICorDebugFunction* fn=0;//ф-ция номер 1 имеет такой код 6000001
          pModule->GetFunctionFromToken(0x6000001,&fn);
          if (fn!=0) fn->CreateBreakpoint(&bp1);
          // TODO: очистить bp1  
          pAppDomain->Continue(0);          
          return 0;
          }
      

      并添加一个 BreakPoint 处理程序

       HRESULT __stdcall Breakpoint(ICorDebugAppDomain *pAppDomain,
       ICorDebugThread *pThread,
       ICorDebugBreakpoint *pBreakpoint) {            
           ICorDebugFrame * f = 0;
           pThread->GetActiveFrame(&f);
           ICorDebugStepper * step = 0;
           f->CreateStepper(&step);
           step->Step(0); // Заставляем работать в шаговом режиме
           // TODO: step освободить когда не нужен будет
           f->Release();
           pAppDomain->Continue(0);  
           return 0;
           }
      

      是的,MGRHandler MgrHandler;当您完成编写处理程序时,在处理程序下方添加。如果编译器发誓,它会写 words abstract,error这意味着不是所有的功能都实现了。您需要添加所有内容(现代编译器可以自己实现抽象类,如果您另外在正确的位置单击两三次)。

    现在调试器可以以某种方式调试程序。面对这个……哦,我的ip在哪里……

    1. 处理器升级。有一个接口ICorDebugILFrame——它有很多用处,局部变量、参数和ip。程序的最后一次“触摸”,我们在处理程序中编辑函数:

      HRESULT __stdcall StepComplete(
           ICorDebugAppDomain *pAppDomain,
           ICorDebugThread *pThread,
           ICorDebugStepper *pStepper,
           CorDebugStepReason reason) {
               ICorDebugFrame * f = 0;
               ICorDebugILFrame * ff = 0;
               unsigned ip,tok;
               pThread->GetActiveFrame(&f);
               f->QueryInterface(IID_ICorDebugILFrame , &ff);
               ff->GetIP(&ip);
               f->GetFunctionToken(&tok);
               char buf[30];
               wsprintfA("tok:%x ip:%x\r\n",tok,buf);
               // TODO: вывод на екран
               pStepper->Step(0); // пусть ещё шагает
               pAppDomain->Continue(0);
               return 0;
               }
      

    现在我们有了一个“跟踪器”,可以让您逐步执行该功能。我没有提到IMetaDataImport——通过它你可以得到所有函数和参数的名称,其余的必要信息相对容易找到。我试图展示我不太容易找到的 4 个步骤。显示了一个纯粹的“骨架”。

    PS 测试。

    该模块是用 borland c++ x86 构建的。

    win2003 x86 - 模块工作(工作室 2005)

    win7 x64 - 该模块可以工作,但您需要创建正在调试的程序的 32 位程序集,即 添加到csc.exe参数/platform:x86(否则我们会捕获错误DebuggerError 0x80131C30)

    有用的链接

    • MS 调试 API http://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/debugging/
    • 创建 ICorDebug http://lowleveldesign.org/2010/10/11/writing-a-net-debugger-part-1-starting-the-debugging-session/ 第 2 部分 第 3 部分 第 4 部分
    • HRESULT错误代码http://github.com/mrfearless/UASM-with-RadASM/blob/master/UASM64/ErrorCodes.dat有一个文件有错误代码,corerror.h但是……不方便。
    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5