How to make .NET and IDA Pro friends (about C # and C ++ friendship)



Greetings,



First, about the problem / task:

Having started writing another debugger plugin for the retro platform under IDA Pro (secretly: it will be SNES), I came across the following set that needed to be friends:



  1. The emulator kernel is written in C ++ and compiled into a DLL
  2. The emulator GUI is written in C # and uses a kernel DLL to control the emulation.
  3. IDA Pro, , C++ DLL ( C++)


- IDA ( , , ..) , IDA .



( ), :



1) LoadLibrary("emu_core.dll"), GetProcAddress(core, "Pause") pause(), , , .



: — ( , GUI )! , , , , DLL-, , , UI, .



, DLL- IDA, . .



2) - -, , — GUI, RPC-.



, :



  • IDA (, , reset), .. , , , .
  • . , , , , RPC .




COM. , , RPC . , , WinAPI (.. C/C++) — C#.



.. GUI , . COM-.



:



1) , COM, [ComVisible(true)]. , - , ( , , )



2) , , ( IDA). ( ComVisible):



[Guid("7710855F-D37B-464B-B645-972BAB2706D4")]  // Visual Studio    GUID-  
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IDebugApi


3) , DebugCOM:



[Guid("6AF9F5DD-6626-4E35-BEF4-29A73E18A739")]
[ComVisible(true)]
public class DebugCOM : IDebugApi


4) ( ) (Class Library), . DebugCOM.dll



5) tlbexp.exe Visual Studio ( Developer Command Prompt) DLL TLB. , ..



:



tlbexp DebugCOM.dll /out:DebugCOM.tlb


COM, :



Assembly exported to 'DebugCOM.tlb'


, . :



TlbExp
TlbExp : warning TX801311B0 : Type library exporter warning processing 'AddressInfo.Type, DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'InteropBreakpoint.MemoryType, DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemorySize(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryValue(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryValue(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryValues(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryState(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryState(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryAccessCounts(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.
TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryAccessCounts2(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.


, SnesMemoryType ComVisible(true). .



6) TLB- (File->View TypeLib...) ComView. :



c:\Windows\Microsoft.NET\Framework\v4.0.30319\ComView.exe


IDL:





File->Save as... IDL-.



7) IDL- C++ , , , DebugCOM:







8) IDL- Compile Ctrl+F7. , : DebugCOM_h.h DebugCOM_i.c. ( ), .





, C# , . C/C++. C#.



9) - .h .c , , . :



COM C++
#include <atlbase.h>
#include <iostream>

#include "DebugCOM_h.h"
#include "DebugCOM_i.c"

int main(int argc, char* argv[]) {
    HRESULT hr;

    hr = ::CoInitializeEx(0, COINITBASE_MULTITHREADED);
    if (FAILED(hr))
    {
        std::cout << "CoInitializeEx failure: " << std::hex << std::showbase << hr << std::endl;
        return EXIT_FAILURE;
    }

    CLSID CLSID_server;
    hr = ::CLSIDFromString(L"{6AF9F5DD-6626-4E35-BEF4-29A73E18A739}", &CLSID_server);
    if (FAILED(hr))
    {
        std::cout << "CLSIDFromString failure: " << std::hex << std::showbase << hr << std::endl;
        return EXIT_FAILURE;
    }

    CComPtr<IDebugApi> server;

    hr = ::CoCreateInstance(CLSID_server, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(IDebugApi), (void**)&server);
    if (FAILED(hr))
    {
        std::cout << "CoCreateInstance failure: " << std::hex << std::showbase << hr << std::endl;
        return EXIT_FAILURE;
    }

    DebugState state = {};
    hr = server->GetState(&state);
    if (FAILED(hr))
    {
        std::cout << "GetState failure: " << std::hex << std::showbase << hr << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "PC Address: " << std::hex << std::showbase << state.Cpu.PC << std::endl;

    ::CoUninitialize();

    return EXIT_SUCCESS;

    return 0;
}


COM.



COM-



:



  1. Inprocess
  2. Out-of-process


  • , COM , . , COM GUI, IDA.

    COM DLL.



  • , COM- . , , , -. .. , COM .





, out-of-process COM. , GitHub " " : https://github.com/dotnet/samples/tree/master/core/extensions/OutOfProcCOM. .





As a result, I managed to make IDA Pro and the .NET Framework application friends with Windows tools, without fussing bikes from my own RPC protocols. In addition, I solved the problem of having only one copy of the emulator kernel and sharing its state between several applications.




All Articles