Click here to Skip to main content
Click here to Skip to main content

Analyzing a .NET executable or DLL without .NET installed

By , 15 Feb 2013
 

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.

321269/net-analyze.jpg

You select an executable.

If it is a .NET executable, you will be able to see a tree view of all the classes within this file.

321269/net-analyze1.jpg

If it is not a .NET executable, the following message will popup:

321269/net-analyze2.jpg

Using the code

GetDotNetClassName is used after opening the executable binary file:

CPEParser objPEParser;
list<string> lString= objPEParser.GetDotNetClassName(ofn.lpstrFile);

Please note that if the list has 0 items, we can determine that the executable is not a .NET one, but Win32.

Here is the GetDotNetClassName function:

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));

    int MetadataTable[64];
    i16Length       = 24;
    
    for(int i = 0; i < 32 ; i++)
    {
        if((valid1 >> i) & 1)
        {
            MetadataTable[i] = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
            i16Length += 4;
        }
        else
        {
            MetadataTable[i] = 0;
        }
    }

    for(int i = 0; i < 32 ; i++)
    {
        if((valid2 >> i) & 1)
        {
            MetadataTable[i + 32] = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
            i16Length += 4;
        }
        else
        {
            MetadataTable[i + 32] = 0;
        }
    }

    //read Module Table
    if(MetadataTable[0] != 0)
    {
        int rowSize = 2 + ((HeapOffSetSize & 0x01) ? 4: 2) + 3 * ((HeapOffSetSize & 0x02)? 4 : 2);
        //byte to skip
        i16Length   += rowSize * MetadataTable[0]; 
    }

    //read Typeref Table
    if(MetadataTable[1] != 0)
    {
        int MaxRow = MetadataTable[0] + MetadataTable[26] + MetadataTable[35] + MetadataTable[01];
        int rowSize = ((MaxRow < 65536)? 2 : 4) + 2 * ((HeapOffSetSize & 0x01) ? 4: 2);
        i16Length  += rowSize * MetadataTable[1];
    }
    
    list<TypeDef> lTypeDef;
    //read typedef table
    if(MetadataTable[2] != 0)
    {
        int flagSize = 4;
        int szTypeName = ((HeapOffSetSize & 0x01) ? 4: 2);
        int MaxRow    = MetadataTable[2] + MetadataTable[1] + MetadataTable[27];
        int szExtend  = (MaxRow < 65536)? 2 : 4;
        int szField   =  (MetadataTable[4] < 65536)? 2 : 4;
        int szMethod  = (MetadataTable[6] < 65536)? 2 : 4;
        
        TypeDef sTypeDef;

        for(int i = 0; i < MetadataTable[2]; i++)
        {
            sTypeDef.iFlag = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
            i16Length     += flagSize;

            if(szTypeName == 2)
                sTypeDef.iTypeName = *(reinterpret_cast<short *>(pMetaDataTable + i16Length));
            else
                sTypeDef.iTypeName = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
    
            i16Length       += szTypeName;
            
            if(szTypeName == 2)
                sTypeDef.iTypeNameSpace = *(reinterpret_cast<short *>(pMetaDataTable + i16Length));
            else
                sTypeDef.iTypeNameSpace = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
    
            i16Length       += szTypeName;
            
            if(szExtend == 2)
                sTypeDef.iExtends = *(reinterpret_cast<short *>(pMetaDataTable + i16Length));
            else
                sTypeDef.iExtends = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
        
            i16Length       += szExtend;
            
            if(szField == 2)
                sTypeDef.iFieldList = *(reinterpret_cast<short *>(pMetaDataTable + i16Length));
            else
                sTypeDef.iFieldList = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
    
            i16Length       += szField;
            
            if(szMethod == 2)
                sTypeDef.iMethodList = *(reinterpret_cast<short *>(pMetaDataTable + i16Length));
            else
                sTypeDef.iMethodList = *(reinterpret_cast<int *>(pMetaDataTable + i16Length));
        
            i16Length+= szMethod;

            lTypeDef.push_back(sTypeDef);
        }
    }

    //now read the strings
    char *pstrStart = pMetaDataAddress + GetMetaData(lStreamHeader, "#Strings")->offset;

    for(list<TypeDef>::iterator iteType = lTypeDef.begin();
        iteType != lTypeDef.end(); iteType++)
    {
        lString.push_back(ReadString(pstrStart + (*iteType).iTypeName));
    }

    UnmapViewOfFile(pFileBase);
    CloseHandle(hMapFile);
    CloseHandle(hFile);

    return lString;
} 

The Download Haephrati-Net-Alanyze.zip source code which accompanies this article demonstrates the exact way to implement that, and the executable is included as well.

 

 Michael Haephrati CodeProject MVP 2013    

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Michael Haephrati
Israel Israel
Member
Michael Haephrati, born in 1964, an entrepreneur, inventor and a musician. Haephrati worked on many ventures starting from HarmonySoft, designing Rashumon, the first Graphical Multi-lingual word processor for Amiga computer.
 
Worked with Amdocs and managed several software projects, among them one for the Ministry of Tourism in New Zealand.  During 1995-1996 he worked as a Contractor with Apple at Cupertino. After returning to Israel, worked as a Project Manager with Top Image Systems (mostly with JCC, Nicosia), and then at a research institute made the fist steps developing the credit scoring field in Israel. He founded Target Scoring and developed a credit scoring system named ThiS, based on geographical statistical data, participating VISA CAL, Isracard, Bank Leumi and Bank Discount (Target Scoring, being the VP Business Development of a large Israeli institute).

During 2000, he founded Target Eye, and developed the first remote PC surveillance and monitoring system, named Target Eye.

Other ventures included: Data Cleansing (as part of the DataTune system which was implemented in many organizations.
 


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberMember 416352421 Feb '13 - 5:33 
GeneralMy vote of 5memberRutuanie20 Feb '13 - 21:30 
QuestionIt's good to see you back.protectorPete O'Hanlon19 Feb '13 - 1:50 
QuestionDo you not understand that I'm trying to help you here?protectorPete O'Hanlon18 Feb '13 - 9:30 
QuestionPlease stop.protectorPete O'Hanlon18 Feb '13 - 9:18 
GeneralMy vote of 3memberPaulo Zemek16 Feb '13 - 14:28 
GeneralMy vote of 5memberWebBHTAN16 Feb '13 - 4:53 
SuggestionRefinementsmemberJaime Olivares28 Jan '13 - 5:26 
GeneralMy vote of 5memberliliflower35525 Jan '13 - 1:17 
GeneralMy vote of 5memberresi243125 Jan '13 - 0:14 
GeneralMy vote of 5membermidulm24 Jan '13 - 23:08 
GeneralMy vote of 5groupbalam198824 Jan '13 - 22:23 
GeneralMy vote of 5groupevan89724 Jan '13 - 21:44 
GeneralMy vote of 5memberRutuanie24 Jan '13 - 19:30 
GeneralMy vote of 1memberPJohnMathews23 Jan '13 - 22:19 
GeneralMy vote of 1memberPJohnMathews23 Jan '13 - 19:57 
Questionnot working on exes built with .net4.0memberAnandChavali22 Jan '13 - 23:36 
not working on exes built with .net4.0
Thanks and Regards,
Anand.

GeneralMy vote of 5memberBabs29115 Oct '12 - 9:22 
GeneralMy vote of 5memberRumon200014 Oct '12 - 3:00 
GeneralMy vote of 5memberJason44413 Oct '12 - 21:46 
GeneralMy vote of 5memberMember 951180113 Oct '12 - 19:36 
GeneralMy vote of 5memberFlorida201213 Oct '12 - 12:01 
GeneralMy vote of 5memberBarb Henry 213 Oct '12 - 11:25 
GeneralMy vote of 5memberBarb Henry 213 Oct '12 - 11:24 
GeneralMy vote of 5memberjohannafeldman1213 Oct '12 - 11:09 
GeneralMy vote of 5memberGeorge Rogers II13 Oct '12 - 6:41 
GeneralMy vote of 5memberHillary Higg1 Oct '12 - 23:36 
GeneralMy vote of 5memberEmma20123217 Sep '12 - 6:46 
GeneralMy vote of 4member@k@ ?13 Feb '12 - 9:01 
QuestionVoted 1membergxdata6 Feb '12 - 14:20 
AnswerRe: Voted 1memberMichael Haephrati8 Feb '12 - 6:38 
GeneralMy vote of 1membergxdata6 Feb '12 - 14:18 
SuggestionRe: My vote of 1memberMichael Haephrati3 May '12 - 23:18 
GeneralMy vote of 2membervilainchien31 Jan '12 - 9:33 
GeneralMy vote of 5memberdanlobo31 Jan '12 - 9:02 
GeneralMy vote of 5memberAnold Harris31 Jan '12 - 6:59 
BugincompletememberRoger6531 Jan '12 - 6:40 
GeneralRe: incompletememberMichael Haephrati31 Jan '12 - 7:34 
GeneralMy vote of 3memberSharjith31 Jan '12 - 6:38 
GeneralMy vote fo 3memberSharjith31 Jan '12 - 6:36 
GeneralMy vote of 5memberJeff Kibling31 Jan '12 - 3:24 
GeneralMy vote of 3memberGLLNS30 Jan '12 - 9:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 16 Feb 2013
Article Copyright 2012 by Michael Haephrati
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid