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!
Achieving TLB-to-TIL conversion can be done through an intermediary C++ conversion:
To achieve TLB-to-TIL conversion, this article requires the following tools:
* 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”.
Windows type libraries are a Windows-specific feature which integrates seamlessly with the MSVC compiler through the #import
statement.
Source: learn.microsoft.com
#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.
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
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
.
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.
With the TIL loaded, we can now instruct IDA to import the new structures such as ICLRMetaHost
and its ICLRMetaHost_vtbl
virtual function table.
Once our structures imported, we can leverage IDA’s structure offsets to make raw offsets human-readable as observed in the following slider (left before, right after).
In our .NET injection analysis, this enables us to identify where the raw .NET assembly is loaded as observed in the beneath slider (left before, right after). Such information in turn allows us to identify from where it originates and where we could best intercept it for further analysis.
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.
Maxime Thiebaut
Maxime Thiebaut is a GCFA-certified Incident Response & Digital Forensics Analyst within NVISO CSIRT. He spends most of his time performing defensive research and responding to incidents. Previously, Maxime worked on the SANS SEC699 course. Besides his coding capabilities, Maxime enjoys reverse engineering samples observed in the wild.
Maxime Thiebaut is a GCFA-certified intrusion analyst in NVISO's Managed Detection & Response team. He spends most of his time investigating incidents and improving detection capabilities. Previously, Maxime worked on the SANS SEC699 course. Besides his coding capabilities, Maxime enjoys reverse engineering samples observed in the wild. View all posts by Maxime Thiebaut
Published