ฉันมีรายชื่อชุดประกอบ. NET
ฉันต้องตรวจสอบโดยทางโปรแกรมว่า DLL แต่ละตัวถูกสร้างขึ้นสำหรับ x86 (ตรงข้ามกับ x64 หรือ CPU ใด ๆ ) เป็นไปได้ไหม
ฉันมีรายชื่อชุดประกอบ. NET
ฉันต้องตรวจสอบโดยทางโปรแกรมว่า DLL แต่ละตัวถูกสร้างขึ้นสำหรับ x86 (ตรงข้ามกับ x64 หรือ CPU ใด ๆ ) เป็นไปได้ไหม
คำตอบ:
ดูที่ System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
คุณสามารถตรวจสอบข้อมูลเมตาของแอสเซมบลีจากอินสแตนซ์ AssemblyName ที่ส่งคืน:
ใช้PowerShell :
[36] C: \> [reflection.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | ฟลอริด้า ชื่อ: Microsoft.GLEE เวอร์ชัน: 1.0.0.0 CultureInfo: CodeBase: ไฟล์: /// C: / โครงการ / powershell / BuildAnalyzer / ... EscapedCodeBase: ไฟล์: /// C: / projects / powershell / BuildAnalyzer / ... สถาปัตยกรรมโปรเซสเซอร์: MSIL ธง: PublicKey HashAlgorithm: SHA1 VersionCompatibility: SameMachine KeyPair: FullName: Microsoft.GLEE, เวอร์ชัน = 1.0.0.0, Culture = neut ...
ที่นี่ProcessorArchitectureระบุแพลตฟอร์มเป้าหมาย
ฉันใช้ PowerShell ในตัวอย่างนี้เพื่อเรียกวิธีการ
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
เป็นบางครั้งไดเรกทอรีปัจจุบันของกระบวนการไม่เหมือนกับผู้ให้บริการปัจจุบัน (ซึ่งเป็นที่ที่ฉันถือว่า DLL สำหรับคุณ)
// DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.
น่าเศร้าที่ไม่มีวิธีการอ่าน ProcessorAr Architecture โดยไม่ต้องใช้GetName instance method
; โดยใช้ข้อมูลที่มีการตั้งเสมอAssemblyName constructor
None
คุณสามารถใช้เครื่องมือCorFlags CLI (ตัวอย่าง SDKs \ Windows \ v7.0 \ BinFlags.exe Files \ Microsoft C: \ Program) เพื่อตรวจสอบสถานะของแอสเซมบลีตามเอาท์พุทและเปิดแอสเซมบลีเป็น สินทรัพย์ไบนารีคุณควรจะสามารถระบุตำแหน่งที่คุณต้องการค้นหาเพื่อตรวจสอบว่าการตั้งค่าสถานะ 32BIT เป็น 1 ( x86 ) หรือ 0 ( CPUหรือx64 ใด ๆขึ้นอยู่กับPE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
บล็อกโพสต์การพัฒนา x64 กับ .NETcorflags
มีข้อมูลบางอย่างเกี่ยวกับ
ยิ่งไปกว่านั้นคุณสามารถใช้Module.GetPEKind
เพื่อกำหนดว่าแอสเซมบลีเป็นPortableExecutableKinds
ค่าPE32Plus
(64 บิต), Required32Bit
(32- บิตและ WOW) หรือILOnly
(CPU ใด ๆ ) พร้อมกับคุณลักษณะอื่น ๆ
เพียงเพื่อชี้แจง CorFlags.exe เป็นส่วนหนึ่งของ.NET Framework SDK ฉันมีเครื่องมือในการพัฒนาบนเครื่องของฉันและวิธีที่ง่ายที่สุดสำหรับฉันกำหนดว่า DLL เป็น 32 บิตเท่านั้น:
เปิดพรอมต์คำสั่ง Visual Studio (ใน Windows: เมนู Start / Programs / Microsoft Visual Studio / Visual Studio Tools / พรอมต์คำสั่ง Visual Studio 2008)
CD ไปยังไดเรกทอรีที่มี DLL ที่เป็นปัญหา
เรียกใช้ corflags ดังนี้:
corflags MyAssembly.dll
คุณจะได้ผลลัพธ์ดังนี้:
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 3.5.21022.8
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v2.0.50727
CLR Header: 2.5
PE : PE32
CorFlags : 3
ILONLY : 1
32BIT : 1
Signed : 0
ตามความคิดเห็นธงด้านบนจะต้องอ่านดังต่อไปนี้:
32BITREQ
และ32BITPREF
มากกว่า32BIT
ค่าเดียว
แล้วคุณล่ะเขียนตัวเองเหรอ? แกนหลักของสถาปัตยกรรม 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.
แต่ด้วยวิธีการนี้จะช่วยให้ค่าคงที่ใหม่ให้ตรวจสอบผลตอบแทนตามที่เห็นสมควร
พยายามที่จะใช้ CorFlagsReader จากโครงการนี้ที่ CodePlex มันไม่มีการอ้างอิงถึงแอสเซมบลีอื่นและสามารถใช้ตามที่เป็นอยู่
[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);
}
}
ด้านล่างนี้เป็นไฟล์แบตช์ที่จะทำงานcorflags.exe
กับทั้งหมดdlls
และexes
ในไดเรกทอรีการทำงานปัจจุบันและไดเรกทอรีย่อยทั้งหมดแยกวิเคราะห์ผลลัพธ์และแสดงสถาปัตยกรรมเป้าหมายของแต่ละรายการ
ทั้งนี้ขึ้นอยู่กับรุ่นของcorflags.exe
ที่ใช้ในรายการโฆษณาในการส่งออกทั้งสองจะรวมถึง32BIT
, หรือ 32BITREQ
(และ32BITPREF
) แล้วแต่จำนวนใดของทั้งสองจะรวมอยู่ในการส่งออกเป็นบรรทัดรายการที่สำคัญที่จะต้องตรวจสอบความแตกต่างระหว่างและAny CPU
x86
หากคุณใช้เวอร์ชันเก่ากว่าcorflags.exe
(pre pre SDK ของ Windows SDK v8.0A) เฉพาะ32BIT
รายการโฆษณาเท่านั้นที่จะปรากฏในผลลัพธ์ตามที่คนอื่น ๆ ระบุไว้ในคำตอบที่ผ่านมา มิฉะนั้น32BITREQ
และ32BITPREF
แทนที่
นี้จะถือว่าอยู่ในcorflags.exe
วิธีที่ง่ายที่สุดเพื่อให้แน่ใจว่านี้คือการใช้%PATH%
Developer Command Prompt
หรือคุณสามารถคัดลอกจากที่ตั้งเริ่มต้นได้
หากไฟล์แบตช์ด้านล่างทำงานกับไฟล์ที่ไม่มีการจัดการdll
หรือไฟล์ดังexe
กล่าวจะแสดงอย่างไม่ถูกต้องx86
เนื่องจากเอาต์พุตจริงจากCorflags.exe
จะเป็นข้อความแสดงข้อผิดพลาดคล้ายกับ:
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.
อีกวิธีหนึ่งคือการใช้ dumpbin จากเครื่องมือ Visual Studio บน DLL และค้นหาผลลัพธ์ที่เหมาะสม
dumpbin.exe /HEADERS <your dll path>
FILE HEADER VALUE
14C machine (x86)
4 number of sections
5885AC36 time date stamp Mon Jan 23 12:39:42 2017
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
2102 characteristics
Executable
32 bit word machine
DLL
หมายเหตุ: Above o / p ใช้สำหรับ 32 บิต dll
อีกหนึ่งตัวเลือกที่มีประโยชน์กับ dumpbin.exe คือ / EXPORTS มันจะแสดงฟังก์ชั่นที่เปิดเผยโดย dll
dumpbin.exe /EXPORTS <PATH OF THE DLL>
วิธีทั่วไปมากขึ้น - ใช้โครงสร้างไฟล์เพื่อกำหนดพยานและประเภทภาพ:
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
ฉันโคลนเครื่องมือที่มีประโยชน์อย่างยิ่งที่เพิ่มรายการเมนูบริบทสำหรับชุดประกอบใน windows explorer เพื่อแสดงข้อมูลที่มีอยู่ทั้งหมด:
ดาวน์โหลดได้ที่นี่: https://github.com/tebjan/AssemblyInformation/releases
อีกวิธีในการตรวจสอบแพลตฟอร์มเป้าหมายของชุดประกอบ. NET คือการตรวจสอบชุดประกอบด้วย. NET Reflector ...
@ # ~ # € ~! ฉันเพิ่งรู้ว่าเวอร์ชันใหม่ไม่ฟรี! ดังนั้นการแก้ไขถ้าคุณมี. NET รุ่นสะท้อนแสงฟรีคุณสามารถใช้มันเพื่อตรวจสอบแพลตฟอร์มเป้าหมาย
cfeduke บันทึกความเป็นไปได้ของการโทร GetPEKind เป็นเรื่องที่น่าสนใจที่จะทำสิ่งนี้จาก PowerShell
ตัวอย่างเช่นที่นี่คือรหัสสำหรับ cmdlet ที่สามารถใช้ได้: https://stackoverflow.com/a/16181743/64257
อีกวิธีหนึ่งที่https://stackoverflow.com/a/4719567/64257มีการบันทึกไว้ว่า "นอกจากนี้ยังมี Get-PEHeader cmdlet ในPowerShell Community Extensionsที่สามารถใช้ในการทดสอบภาพที่ปฏิบัติการได้"
แอปพลิเคชันขั้นสูงสำหรับคุณที่นี่: 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
อีกทางเลือกหนึ่งสำหรับเครื่องมือที่กล่าวถึงแล้วคือTelerik JustDecompile (เครื่องมือฟรี) ซึ่งจะแสดงข้อมูลถัดจากชื่อชุดประกอบ: