-
Notifications
You must be signed in to change notification settings - Fork 4k
/
MvidReader.cs
executable file
·212 lines (179 loc) · 6.27 KB
/
MvidReader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace Microsoft.CodeAnalysis.BuildTasks
{
public static class MvidReader
{
private static readonly Guid s_empty = Guid.Empty;
public static Guid ReadAssemblyMvidOrEmpty(Stream stream)
{
return ReadAssemblyMvidOrEmpty(new BinaryReader(stream));
}
private static Guid ReadAssemblyMvidOrEmpty(BinaryReader reader)
{
// DOS Header: Magic number (2)
if (!ReadUInt16(reader, out ushort magicNumber) || magicNumber != 0x5a4d) // "MZ"
{
return s_empty;
}
// DOS Header: Address of PE Signature (at 0x3C)
if (!MoveTo(0x3C, reader))
{
return s_empty;
}
if (!ReadUInt32(reader, out uint pointerToPeSignature))
{
return s_empty;
}
// jump over the MS DOS Stub to the PE Signature
if (!MoveTo(pointerToPeSignature, reader))
{
return s_empty;
}
// PE Signature ('P' 'E' null null)
if (!ReadUInt32(reader, out uint peSig) || peSig != 0x00004550)
{
return s_empty;
}
// COFF Header: Machine (2)
if (!Skip(2, reader))
{
return s_empty;
}
// COFF Header: NumberOfSections (2)
if (!ReadUInt16(reader, out ushort sections))
{
return s_empty;
}
// COFF Header: TimeDateStamp (4), PointerToSymbolTable (4), NumberOfSymbols (4)
if (!Skip(12, reader))
{
return s_empty;
}
// COFF Header: OptionalHeaderSize (2)
if (!ReadUInt16(reader, out ushort optionalHeaderSize))
{
return s_empty;
}
// COFF Header: Characteristics (2)
if (!Skip(2, reader))
{
return s_empty;
}
// Optional header
if (!Skip(optionalHeaderSize, reader))
{
return s_empty;
}
// Section headers
return FindMvidInSections(sections, reader);
}
private static Guid FindMvidInSections(ushort count, BinaryReader reader)
{
for (int i = 0; i < count; i++)
{
// Section: Name (8)
if (!ReadBytes(reader, 8, out byte[]? name))
{
return s_empty;
}
if (name!.Length == 8 && name[0] == '.' &&
name[1] == 'm' && name[2] == 'v' && name[3] == 'i' && name[4] == 'd' && name[5] == '\0')
{
// Section: VirtualSize (4)
if (!ReadUInt32(reader, out uint virtualSize) || virtualSize != 16)
{
// The .mvid section only stores a Guid
return s_empty;
}
// Section: VirtualAddress (4), SizeOfRawData (4)
if (!Skip(8, reader))
{
return s_empty;
}
// Section: PointerToRawData (4)
if (!ReadUInt32(reader, out uint pointerToRawData))
{
return s_empty;
}
return ReadMvidSection(reader, pointerToRawData);
}
else
{
// Section: VirtualSize (4), VirtualAddress (4), SizeOfRawData (4),
// PointerToRawData (4), PointerToRelocations (4), PointerToLineNumbers (4),
// NumberOfRelocations (2), NumberOfLineNumbers (2), Characteristics (4)
if (!Skip(4 + 4 + 4 + 4 + 4 + 4 + 2 + 2 + 4, reader))
{
return s_empty;
}
}
}
return s_empty;
}
private static Guid ReadMvidSection(BinaryReader reader, uint pointerToMvidSection)
{
if (!MoveTo(pointerToMvidSection, reader))
{
return s_empty;
}
if (!ReadBytes(reader, 16, out byte[]? guidBytes))
{
return s_empty;
}
return new Guid(guidBytes!);
}
private static bool ReadUInt16(BinaryReader reader, out ushort output)
{
if (reader.BaseStream.Position + 2 >= reader.BaseStream.Length)
{
output = 0;
return false;
}
output = reader.ReadUInt16();
return true;
}
private static bool ReadUInt32(BinaryReader reader, out uint output)
{
if (reader.BaseStream.Position + 4 >= reader.BaseStream.Length)
{
output = 0;
return false;
}
output = reader.ReadUInt32();
return true;
}
private static bool ReadBytes(BinaryReader reader, int count, out byte[]? output)
{
if (reader.BaseStream.Position + count >= reader.BaseStream.Length)
{
output = null;
return false;
}
output = reader.ReadBytes(count);
return true;
}
private static bool Skip(int bytes, BinaryReader reader)
{
if (reader.BaseStream.Position + bytes >= reader.BaseStream.Length)
{
return false;
}
reader.BaseStream.Seek(bytes, SeekOrigin.Current);
return true;
}
private static bool MoveTo(uint position, BinaryReader reader)
{
if (position >= reader.BaseStream.Length)
{
return false;
}
reader.BaseStream.Seek(position, SeekOrigin.Begin);
return true;
}
}
}