Хороший подход для определения PEFileKind сборки? - PullRequest
0 голосов
/ 08 сентября 2018

В C # или VB.NET я хотел бы знать, какой из подходов был бы наилучшим для определения PEFileKinds сборки, загруженной через Reflection . Другими словами, определите, является ли сборка WinExe, консольным приложением или библиотекой динамических ссылок.

Я нашел это решение (другие предложенные решения в этом вопросе не эффективны), но если я не ошибаюсь, я думаю, что подразумевается, что загруженный файл является сборкой .NET, и , кажется, немного аккуратно, чтобы вручную проанализировать PE-заголовок.

Я также нашел это другое решение, но, читая комментарии, оно кажется неэффективным в некоторых обстоятельствах.

По этим причинам мне интересно, существует ли действительно безопасный, управляемый способ, предпочтительно через Reflection , для определения типа PE-файла загруженной сборки.

Я уверен, что перечисление System.Reflection.Emit.PEFileKinds не существует только для декоративных целей. Если это перечисление существует, то логично предположить, что в пространствах имен Reflection может быть элемент / функция, которую я пропустил которые внутренне используют это перечисление для возврата типа PE-файла объекта Assembly, однако мне удалось просмотреть закрытые члены класса Assembly через Reflection и другие связанные классы, и я ничего не нашел отношение.

1 Ответ

0 голосов
/ 08 сентября 2018

В соответствии с поиском справочного источника , перечисление PEFileKinds используется только в AssemblyBuilder и ModuleBuilder (и непубличных типах помощников для них). Это перечисление и классы находятся в пространстве имен System.Reflection.Emit - например, они предназначены для записи сборок, а не чтения.

Однако официальный System.Reflection.Metadata пакет NuGet предоставляет соответствующие значения PE-заголовка сборки в своем System.Reflection.PortableExecutable пространстве имен . Эти заголовки можно использовать для обратного инжиниринга эквивалентного значения PEFileKinds. Вот пример на C #:

using (var stream = File.OpenRead(filenameAndExtension))
{
    using (var peFile = new PEReader(stream))
    {
        var headers = peFile.PEHeaders;
        Console.WriteLine($"Reading {filenameAndExtension} with System.Reflection.Metadata");
        Console.WriteLine($"  IsDll: {headers.IsDll}");
        Console.WriteLine($"  IsExe: {headers.IsExe}");
        Console.WriteLine($"  IsConsoleApplication: {headers.IsConsoleApplication}");

        PEFileKinds reverseEngineeredKind;

        // NOTE: the header values cause IsConsoleApplication to return
        //       true for DLLs, so we need to check IsDll first
        if (headers.IsDll)
        {
            reverseEngineeredKind = PEFileKinds.Dll;
        }
        else if (headers.IsConsoleApplication)
        {
            reverseEngineeredKind = PEFileKinds.ConsoleApplication;
        }
        else
        {
            reverseEngineeredKind = PEFileKinds.WindowApplication;
        }
        Console.WriteLine($"  Reverse-engineered kind: {reverseEngineeredKind}");
    }
}

Я запускал этот код на сборках, созданных с помощью System.Reflection.Emit, чтобы обеспечить его точность. Полная программа в этом гисте .

Вероятно, вы также можете получить эту информацию с помощью сторонних библиотек, таких как Mono.Cecil или, как упоминал Лекс Ли, PeNet .

...