This is a mirror of official site: http://jasper-net.blogspot.com/

Analyzing a .NET executable or DLL without .NET installed

| Wednesday, February 1, 2012
image002.jpg

Introduction

This article describes how to add to a Win32 API, C++ application, the ability to browse for executables (.exe) files, and to determine whether they are .NET ones, and if so, to analyze their classes and display a list of them, without having .NET installed on the machine running it.


Background

.NET executables can be easily analyzed, and each class can be enumerated. However, some users prefer not to install the .NET Framework because they don't need it or because it is quite heavy. There seems to be a need to allow applications that are not .NET based, to analyze .NET executables.


The Application

The application works very simple. You run it.

list<string> CPEParser::GetDotNetClassName(string filePathName)
{
    list<string> lString;
    HANDLE hFile = CreateFile(filePathName.c_str(),
                              GENERIC_READ, FILE_SHARE_READ, NULL,
                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, "NetExe");
    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);
   
    char *pFileBase = (char *)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
    IMAGE_DOS_HEADER *pImageDosHeader = reinterpret_cast<IMAGE_DOS_HEADER *>(pFileBase);
    IMAGE_NT_HEADERS *pImageNTHeader  =
      reinterpret_cast<IMAGE_NT_HEADERS *>(pFileBase + pImageDosHeader->e_lfanew);
    IMAGE_FILE_HEADER *pImageFileHeader =
      reinterpret_cast<IMAGE_FILE_HEADER *>(&pImageNTHeader->FileHeader);
    IMAGE_OPTIONAL_HEADER *pImageOpHeader =
      reinterpret_cast<IMAGE_OPTIONAL_HEADER *>(&pImageNTHeader->OptionalHeader);

    IMAGE_DATA_DIRECTORY *entry =
      &pImageOpHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
    if(entry->Size == 0 || entry->Size < sizeof(IMAGE_COR20_HEADER) ||
       entry->VirtualAddress == 0)
    {
        return lString;
    }

    IMAGE_COR20_HEADER *pClrHeader = reinterpret_cast<IMAGE_COR20_HEADER *>(
                ImageRvaToVa(pImageNTHeader, pFileBase, entry->VirtualAddress, 0));
    char *pMetaDataAddress = reinterpret_cast<char *>(ImageRvaToVa(
          pImageNTHeader, pFileBase, pClrHeader->MetaData.VirtualAddress, 0));
    int mdSignature       = *(reinterpret_cast<int *>(pMetaDataAddress));
    short majorVersion    = *(reinterpret_cast<short *>(pMetaDataAddress + 4));
    short minorVersion    = *(reinterpret_cast<short *>(pMetaDataAddress + 6));
    int reserved          = *(reinterpret_cast<int *>(pMetaDataAddress + 8));
    int length            = *(reinterpret_cast<int *>(pMetaDataAddress + 12));
   
    string version;

    for(int i = 16; i < (length + 16); i++)
    {
        version.append(1, *(reinterpret_cast<char *>(pMetaDataAddress + i)));
    }
   
    int reserved2     = *(reinterpret_cast<short *>(pMetaDataAddress + 16 + length));
    int streams       = *(reinterpret_cast<short *>(pMetaDataAddress + 18 + length));
    int i16Length     = 20 + length;
    list<StreamHeader>   lStreamHeader;

    GetStreamHeaders(pMetaDataAddress, i16Length, lStreamHeader, streams);

    //read meta data table
    char *pMetaDataTable = pMetaDataAddress + GetMetaData(lStreamHeader, "#~")->offset;
    int reserved3         = *(reinterpret_cast<int *>(pMetaDataTable));
    char majorVersion1   = *(pMetaDataTable + 4);
    char minorVersion1   = *(pMetaDataTable + 5);
    char HeapOffSetSize  = *(pMetaDataTable + 6);
    char reserved4  = *(pMetaDataTable + 7);
    int valid1      = *(reinterpret_cast<int *>(pMetaDataTable + 8));
    int valid2      = *(reinterpret_cast<int *>(pMetaDataTable + 12));
    int sort1       = *(reinterpret_cast<int *>(pMetaDataTable + 16));
    int sort2       = *(reinterpret_cast<int *>(pMetaDataTable + 20));

Read more: Codeproject
QR: Analyzing-a-Net-executable-or-DLL-without-NET-inst

Posted via email from Jasper-net

0 comments: