11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System ;
5+ using System . Buffers . Binary ;
46using System . IO ;
57using System . IO . MemoryMappedFiles ;
8+ using System . Reflection . PortableExecutable ;
69
710namespace Microsoft . NET . HostModel . AppHost
811{
@@ -15,29 +18,13 @@ public static class PEUtils
1518 /// <returns>true if the accessor represents a PE image, false otherwise.</returns>
1619 internal static unsafe bool IsPEImage ( MemoryMappedViewAccessor accessor )
1720 {
18- byte * pointer = null ;
21+ if ( accessor . Capacity < PEOffsets . DosStub . PESignatureOffset + sizeof ( uint ) )
22+ return false ;
1923
20- try
21- {
22- accessor . SafeMemoryMappedViewHandle . AcquirePointer ( ref pointer ) ;
23- byte * bytes = pointer + accessor . PointerOffset ;
24-
25- // https://en.wikipedia.org/wiki/Portable_Executable
26- // Validate that we're looking at Windows PE file
27- if ( ( ( ushort * ) bytes ) [ 0 ] != PEOffsets . DosImageSignature
28- || accessor . Capacity < PEOffsets . DosStub . PESignatureOffset + sizeof ( uint ) )
29- {
30- return false ;
31- }
32- return true ;
33- }
34- finally
35- {
36- if ( pointer != null )
37- {
38- accessor . SafeMemoryMappedViewHandle . ReleasePointer ( ) ;
39- }
40- }
24+ // https://en.wikipedia.org/wiki/Portable_Executable
25+ // Validate that we're looking at Windows PE file
26+ ushort signature = AsLittleEndian ( accessor . ReadUInt16 ( 0 ) ) ;
27+ return signature == PEOffsets . DosImageSignature ;
4128 }
4229
4330 public static bool IsPEImage ( string filePath )
@@ -60,40 +47,15 @@ public static bool IsPEImage(string filePath)
6047 /// <param name="accessor">The memory accessor which has the apphost file opened.</param>
6148 internal static unsafe void SetWindowsGraphicalUserInterfaceBit ( MemoryMappedViewAccessor accessor )
6249 {
63- byte * pointer = null ;
64-
65- try
66- {
67- accessor . SafeMemoryMappedViewHandle . AcquirePointer ( ref pointer ) ;
68- byte * bytes = pointer + accessor . PointerOffset ;
69-
70- // https://en.wikipedia.org/wiki/Portable_Executable
71- uint peHeaderOffset = ( ( uint * ) ( bytes + PEOffsets . DosStub . PESignatureOffset ) ) [ 0 ] ;
72-
73- if ( accessor . Capacity < peHeaderOffset + PEOffsets . PEHeader . Subsystem + sizeof ( ushort ) )
74- {
75- throw new AppHostNotPEFileException ( "Subsystem offset out of file range." ) ;
76- }
77-
78- ushort * subsystem = ( ( ushort * ) ( bytes + peHeaderOffset + PEOffsets . PEHeader . Subsystem ) ) ;
79-
80- // https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format#windows-subsystem
81- // The subsystem of the prebuilt apphost should be set to CUI
82- if ( subsystem [ 0 ] != ( ushort ) PEOffsets . Subsystem . WindowsCui )
83- {
84- throw new AppHostNotCUIException ( subsystem [ 0 ] ) ;
85- }
86-
87- // Set the subsystem to GUI
88- subsystem [ 0 ] = ( ushort ) PEOffsets . Subsystem . WindowsGui ;
89- }
90- finally
91- {
92- if ( pointer != null )
93- {
94- accessor . SafeMemoryMappedViewHandle . ReleasePointer ( ) ;
95- }
96- }
50+ // https://learn.microsoft.com/windows/win32/debug/pe-format#windows-subsystem
51+ // The subsystem of the prebuilt apphost should be set to CUI
52+ uint peHeaderOffset ;
53+ ushort subsystem = GetWindowsSubsystem ( accessor , out peHeaderOffset ) ;
54+ if ( subsystem != ( ushort ) Subsystem . WindowsCui )
55+ throw new AppHostNotCUIException ( subsystem ) ;
56+
57+ // Set the subsystem to GUI
58+ accessor . Write ( peHeaderOffset + PEOffsets . PEHeader . Subsystem , AsLittleEndian ( ( ushort ) Subsystem . WindowsGui ) ) ;
9759 }
9860
9961 public static unsafe void SetWindowsGraphicalUserInterfaceBit ( string filePath )
@@ -113,32 +75,7 @@ public static unsafe void SetWindowsGraphicalUserInterfaceBit(string filePath)
11375 /// <param name="accessor">The memory accessor which has the apphost file opened.</param>
11476 internal static unsafe ushort GetWindowsGraphicalUserInterfaceBit ( MemoryMappedViewAccessor accessor )
11577 {
116- byte * pointer = null ;
117-
118- try
119- {
120- accessor . SafeMemoryMappedViewHandle . AcquirePointer ( ref pointer ) ;
121- byte * bytes = pointer + accessor . PointerOffset ;
122-
123- // https://en.wikipedia.org/wiki/Portable_Executable
124- uint peHeaderOffset = ( ( uint * ) ( bytes + PEOffsets . DosStub . PESignatureOffset ) ) [ 0 ] ;
125-
126- if ( accessor . Capacity < peHeaderOffset + PEOffsets . PEHeader . Subsystem + sizeof ( ushort ) )
127- {
128- throw new AppHostNotPEFileException ( "Subsystem offset out of file range." ) ;
129- }
130-
131- ushort * subsystem = ( ( ushort * ) ( bytes + peHeaderOffset + PEOffsets . PEHeader . Subsystem ) ) ;
132-
133- return subsystem [ 0 ] ;
134- }
135- finally
136- {
137- if ( pointer != null )
138- {
139- accessor . SafeMemoryMappedViewHandle . ReleasePointer ( ) ;
140- }
141- }
78+ return GetWindowsSubsystem ( accessor , out _ ) ;
14279 }
14380
14481 public static unsafe ushort GetWindowsGraphicalUserInterfaceBit ( string filePath )
@@ -151,5 +88,25 @@ public static unsafe ushort GetWindowsGraphicalUserInterfaceBit(string filePath)
15188 }
15289 }
15390 }
91+
92+ private static ushort GetWindowsSubsystem ( MemoryMappedViewAccessor accessor , out uint peHeaderOffset )
93+ {
94+ // https://en.wikipedia.org/wiki/Portable_Executable
95+ if ( accessor . Capacity < PEOffsets . DosStub . PESignatureOffset + sizeof ( uint ) )
96+ throw new AppHostNotPEFileException ( "PESignature offset out of file range." ) ;
97+
98+ peHeaderOffset = AsLittleEndian ( accessor . ReadUInt32 ( PEOffsets . DosStub . PESignatureOffset ) ) ;
99+ if ( accessor . Capacity < peHeaderOffset + PEOffsets . PEHeader . Subsystem + sizeof ( ushort ) )
100+ throw new AppHostNotPEFileException ( "Subsystem offset out of file range." ) ;
101+
102+ // https://learn.microsoft.com/windows/win32/debug/pe-format#windows-subsystem
103+ return AsLittleEndian ( accessor . ReadUInt16 ( peHeaderOffset + PEOffsets . PEHeader . Subsystem ) ) ;
104+ }
105+
106+ private static ushort AsLittleEndian ( ushort value )
107+ => BitConverter . IsLittleEndian ? value : BinaryPrimitives . ReverseEndianness ( value ) ;
108+
109+ private static uint AsLittleEndian ( uint value )
110+ => BitConverter . IsLittleEndian ? value : BinaryPrimitives . ReverseEndianness ( value ) ;
154111 }
155112}
0 commit comments