assemblies c# 언어 - .NET 어셈블리가 x86 또는 x64 용으로 빌드되었는지 확인하는 방법





7 Answers

CorFlags CLI 도구 (예 : C : \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe)를 사용하여 어셈블리의 출력을 기준으로 어셈블리의 상태를 확인하고 어셈블리를 바이너리 자산을 사용하려면 32BIT 플래그가 1 ( x86 ) 또는 0 ( PE 에 따라 모든 CPU 또는 x64 )으로 설정되었는지 확인해야 할 위치를 결정할 수 있어야합니다.

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

블로그 게시물 x64 .NET 개발 에는 corflags 에 대한 정보가 있습니다.

더 좋게는 Module.GetPEKind사용 하여 다른 속성과 함께 PortableExecutableKindsPE32Plus (64 비트), Required32Bit (32 비트 및 WOW) 또는 ILOnly (모든 CPU)인지 여부를 확인할 수 있습니다 .

사양 reference manual

.NET 어셈블리의 임의 목록이 있습니다.

각 DLL이 x64 또는 모든 CPU와는 반대로 x86 용으로 빌드되었는지 프로그래밍 방식으로 확인해야합니다. 이것이 가능한가?




그냥 자기 자신을 쓰는 건 어때? PE 아키텍처의 핵심은 Windows 95에서 구현 된 이후로 심각하게 변경되지 않았습니다. 다음은 C # 예제입니다.

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    if (bReader.ReadUInt16() == 23117) //check the MZ signature
                    {
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                        if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                        {
                            fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                            architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                        }
                    }
                }
            }
        }
        catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */}
        //if architecture returns 0, there has been an error.
        return architecture;
    }
}

이제 현재 상수는 다음과 같습니다.

0x10B - PE32  format.
0x20B - PE32+ format.

그러나이 방법을 사용하면 새로운 상수의 가능성을 고려할 수 있습니다.




[TestMethod]
public void EnsureKWLLibrariesAreAll64Bit()
{
    var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(x => x.FullName.StartsWith("YourCommonProjectName")).ToArray();
    foreach (var assembly in assemblies)
    {
        var myAssemblyName = AssemblyName.GetAssemblyName(assembly.FullName.Split(',')[0] + ".dll");
        Assert.AreEqual(ProcessorArchitecture.MSIL, myAssemblyName.ProcessorArchitecture);
    }
}



아래는 현재 작업 디렉토리 및 모든 하위 디렉토리의 모든 dllsexes 에 대해 corflags.exe 를 실행하고 결과를 파싱하고 각각의 대상 아키텍처를 표시하는 배치 파일입니다.

사용되는 corflags.exe 의 버전에 따라 출력의 행 항목에는 32BITREQ 또는 32BITREQ (및 32BITPREF )가 포함됩니다. 이 두 가지 중 출력에 포함되는 것은 Any CPUx86 을 구별하기 위해 검사해야하는 중요한 항목입니다. 이전 버전의 corflags.exe (Windows SDK v8.0A 이전 버전)를 사용하는 경우 다른 사람이 이전 답변에서 지정한대로 32BIT 항목 만 출력에 나타납니다. 그렇지 않으면 32BITREQ32BITPREF 32BITREQ32BITPREF .

이것은 corflags.exe%PATH% 에 있다고 가정합니다. 이를 보장하는 가장 간단한 방법은 Developer Command Prompt 를 사용하는 것입니다. 또는 기본 위치 에서 복사 할 수 있습니다 .

아래의 배치 파일을 관리되지 않는 dll 또는 exe 에 대해 실행하면 Corflags.exe 의 실제 출력은 Corflags.exe 과 비슷한 오류 메시지가되므로 x86 으로 잘못 표시됩니다.

corflags : 오류 CF008 : 지정된 파일에 유효한 관리되는 헤더가 없습니다.

@echo off

echo.
echo Target architecture for all exes and dlls:
echo.

REM For each exe and dll in this directory and all subdirectories...
for %%a in (.exe, .dll) do forfiles /s /m *%%a /c "cmd /c echo @relpath" > testfiles.txt

for /f %%b in (testfiles.txt) do (
    REM Dump corflags results to a text file
    corflags /nologo %%b > corflagsdeets.txt

   REM Parse the corflags results to look for key markers   
   findstr /C:"PE32+">nul .\corflagsdeets.txt && (      
      REM `PE32+` indicates x64
        echo %%~b = x64
    ) || (
      REM pre-v8 Windows SDK listed only "32BIT" line item, 
      REM newer versions list "32BITREQ" and "32BITPREF" line items
        findstr /C:"32BITREQ  : 0">nul /C:"32BIT     : 0" .\corflagsdeets.txt && (
            REM `PE32` and NOT 32bit required indicates Any CPU
            echo %%~b = Any CPU
        ) || (
            REM `PE32` and 32bit required indicates x86
            echo %%~b = x86
        )
    )

    del corflagsdeets.txt
)

del testfiles.txt
echo.



.NET 어셈블리의 대상 플랫폼을 확인하는 또 다른 방법은 .NET Reflector를 사용 하여 어셈블리를 검사하는 것입니다.

@ # ~ # € ~! 나는 새로운 버전이 무료가 아니라는 것을 깨달았습니다! 따라서 .NET Reflector의 무료 버전을 사용하는 경우이를 수정하여 대상 플랫폼을 확인할 수 있습니다.




더 고급 응용 프로그램은 여기에서 찾을 수 있습니다. CodePlex - ApiChange

예 :

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\winhlp32.exe
File Name; Type; Size; Processor; IL Only; Signed
winhlp32.exe; Unmanaged; 296960; X86

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\HelpPane.exe
File Name; Type; Size; Processor; IL Only; Signed
HelpPane.exe; Unmanaged; 733696; Amd64



보다 일반적인 방법 - 파일 구조를 사용하여 비트 및 이미지 유형을 결정합니다.

public static CompilationMode GetCompilationMode(this FileInfo info)
{
    if (!info.Exists) throw new ArgumentException($"{info.FullName} does not exist");

    var intPtr = IntPtr.Zero;
    try
    {
        uint unmanagedBufferSize = 4096;
        intPtr = Marshal.AllocHGlobal((int)unmanagedBufferSize);

        using (var stream = File.Open(info.FullName, FileMode.Open, FileAccess.Read))
        {
            var bytes = new byte[unmanagedBufferSize];
            stream.Read(bytes, 0, bytes.Length);
            Marshal.Copy(bytes, 0, intPtr, bytes.Length);
        }

        //Check DOS header magic number
        if (Marshal.ReadInt16(intPtr) != 0x5a4d) return CompilationMode.Invalid;

        // This will get the address for the WinNT header  
        var ntHeaderAddressOffset = Marshal.ReadInt32(intPtr + 60);

        // Check WinNT header signature
        var signature = Marshal.ReadInt32(intPtr + ntHeaderAddressOffset);
        if (signature != 0x4550) return CompilationMode.Invalid;

        //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER
        var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24);

        var result = CompilationMode.Invalid;
        uint clrHeaderSize;
        if (magic == 0x10b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4);
            result |= CompilationMode.Bit32;
        }
        else if (magic == 0x20b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4);
            result |= CompilationMode.Bit64;
        }
        else return CompilationMode.Invalid;

        result |= clrHeaderSize != 0
            ? CompilationMode.CLR
            : CompilationMode.Native;

        return result;
    }
    finally
    {
        if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr);
    }
}

컴파일 모드 열거

[Flags]
public enum CompilationMode
{
    Invalid = 0,
    Native = 0x1,
    CLR = Native << 1,
    Bit32 = CLR << 1,
    Bit64 = Bit32 << 1
}

GitHub 에서 설명이있는 소스 코드




Related