Originally published with NVISO · · 5 min.

Generating IDA Type Information Libraries from Windows Type Libraries

When working with IDA, a commonly leveraged feature are type information libraries (TIL). These libraries contain high-level type information such as function prototypes, type definitions, standard structures or enums; enabling IDA to convert statements such as movsxd rbx, dword ptr [r12+3Ch] into, for example, the more human-readable counterpart movsxd rbx, [r12+IMAGE_DOS_HEADER.e_lfanew].

On Windows, a similar concept called type libraries (TLB) exists to describe COM (Component Object Model) objects. In a nutshell, COM provides a language-independent interface to objects, abstracting how they have been implemented themselves.

In this quick-post, we’ll explore how to convert Windows type libraries (TLB) into IDA type information libraries (TIL). In particular, we’ll generate the necessary type information library to analyze .NET injection into unmanaged processes using mscoree.dll and mscorlib.dll (e.g., through _AppDomain). In a hurry? Grab the .NET type information library directly!

Abstract

Achieving TLB-to-TIL conversion can be done through an intermediary C++ conversion:

  1. First, the MSVC (Microsoft Visual C++) compiler can be leveraged to convert TLBs into their respective C++ header files.
  2. Once the C++ header files generated, IDAClang can be used to convert these into TILs.

A schema of MSVC converting TLBs into C++ as well as IDAClang converting C++ into TILs.
Figure 1: A schema of MSVC converting TLBs into C++ as well as IDAClang converting C++ into TILs.

Requirements

To achieve TLB-to-TIL conversion, this article requires the following tools:

  1. The MSVC (Microsoft Visual C++) compiler installed through Visual Studio*.
  2. The IDAClang command-line utility.

* For our example, we’ll be generating a type information library targeting the .NET Framework, hence also requiring header files part of the .NET Framework Developer Pack (a.k.a. SDK). The .NET Framework Developer Pack can be installed through Visual Studio.

Given both MSVC and IDAClang rely on a properly configured developer environment (e.g., a configured INCLUDE environment variable), this article assumes all commands are issued within a Visual Studio Developer Command Prompt such as the “x64 Native Tools Command Prompt”.

A capture of the “x64 Native Tools Command Prompt” within the Windows Start menu.
Figure 2: A capture of the “x64 Native Tools Command Prompt” within the Windows Start menu.

Converting Microsoft Type Libraries to C++ Headers

Windows type libraries are a Windows-specific feature which integrates seamlessly with the MSVC compiler through the #import statement.

#import creates two header files that reconstruct the type library contents in C++ source code. The primary header file is similar to the one produced by the Microsoft Interface Definition Language (MIDL) compiler, but with additional compiler-generated code and data. The primary header file has the same base name as the type library, plus a .TLH extension.

Source: learn.microsoft.com

As such, creating a C++ file to import a type library will generate its C++ header. Given we wish to convert mscorlib.tlb into C++ headers, we can create the following C++ file named, for example, til.cpp.

#import "mscorlib.tlb" raw_interfaces_only auto_rename

Once the C++ file has been created, we can rely on the MSVC compiler to generate the necessary headers. The beneath command will generate the mscorlib.tlh file.

CL.exe /c /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /permissive- /TP til.cpp

Converting C++ Headers to IDA Type Information Libraries

With the C++ headers generated, we can now proceed to create the IDA type information library. To do so, we can create a new C++ header file that will reference any standard headers (e.g., those from the .NET Framework Developer Pack) and generated headers (i.e., the previously generated mscorlib.tlh) we wish to use in IDA. The following is our example til.h.

// Include standard headers
// Example: Microsoft .NET Framework Developer Pack
#include <alink.h>
#include <clrdata.h>
#include <cordebug.h>
#include <corhlpr.h>
#include <corprof.h>
#include <corpub.h>
#include <corsym.h>
#include <fusion.h>
#include <gchost.h>
#include <ICeeFileGen.h>
#include <isolation.h>
#include <ivalidator.h>
#include <ivehandler.h>
#include <metahost.h>
#include <mscoree.h>
#include <openum.h>
#include <StrongName.h>
#include <tlbref.h>
#include <VerError.h>

// Include generated headers
// Example: Microsoft Common Language Runtime Class Library
//          The mscorlib.h generated from mscorlib.tlb
#include "mscorlib.tlh"

Once the C++ header file created, we can rely on IDAClang to generate the TIL.

idaclang.exe -x c++ -target x86_64-pc-windows -ferror-limit=0 --idaclang-tildesc "Example" --idaclang-tilname "example.til" til.h

MSVC and Clang (used in IDAClang) are two different C++ compilers. While they can mostly agree, compiling MSVC-generated C++ code using Clang is bound to generate non-fatal errors. While IDAClang may generate quite some errors as shown below, the TIL conversion should succeed after a moment.

IDACLANG: nonfatal: ./mscorlib.tlh:10774:1: error: enumeration previously declared with fixed underlying type
IDACLANG: nonfatal: ./mscorlib.tlh:11509:64: error: expected ';' after struct
IDACLANG: nonfatal: ./mscorlib.tlh:11509:1: error: declaration of anonymous struct must be a definition
IDACLANG: nonfatal: ./mscorlib.tlh:11510:11: error: expected unqualified-id

As an example, we published our .NET type information library mscoru.til.

Using the IDA Type Information Library

Once the TIL generated, we can proceed to make it available to IDA. To do so, copy the TIL to the appropriate folder which, in our example, could be the C:\Program Files\IDA Pro 8.3\til\pc directory. Once the TIL staged, IDA should display the new type information library and allow it to be loaded.

A capture of IDA&rsquo;s Available Type Libraries.
Figure 3: A capture of IDA’s Available Type Libraries.

With the TIL loaded, we can now instruct IDA to import the new structures such as ICLRMetaHost and its ICLRMetaHost_vtbl virtual function table.

A capture of IDA&rsquo;s ICLRMetaHost structure.
Figure 4: A capture of IDA’s ICLRMetaHost structure.

A capture of IDA&rsquo;s ICLRMetaHost_vtbl structure.
Figure 5: A capture of IDA’s ICLRMetaHost_vtbl structure.

Once our structures imported, we can leverage IDA’s structure offsets to make raw offsets human-readable.

A capture of IDA&rsquo;s ICLRMetaHost.GetRuntime call.
Figure 6: A capture of IDA’s ICLRMetaHost.GetRuntime call.

In our .NET injection analysis, this enables us to identify where the raw .NET assembly is loaded. Such information in turn allows us to identify from where it originates and where we could best intercept it for further analysis.

A capture of IDA&rsquo;s _AppDomain.Load_3 call.
Figure 7: A capture of IDA’s _AppDomain.Load_3 call.

Conclusions & Lessons Learned

While tools such as OLEViewer alongside MIDL could in theory generate C++ code as well, we found these to be unreliable. Instead, working with MSVC and IDAClang provides a quick (and clean) approach to convert TLBs into TILs.

The above described process can be extended to other abused COM objects such as the Windows Script Host Object Model (with TLB %SystemRoot%\System32\wshom.ocx) or the Microsoft Management Console (with TLB %SystemRoot%\System32\mmc.exe).

By creating IDA type information libraries matching libraries used by adversaries we gain the capability to properly understand their tooling, how to analyze further stages and how to best defend against them.

References

  1. https://learn.microsoft.com/en-us/cpp/preprocessor/hash-import-directive-cpp
  2. https://hex-rays.com/tutorials/idaclang/
  3. https://thewover.github.io/Introducing-Donut/#disposable-appdomains
Archived Reverse Engineering IDA