5
// Jb Evain (jbevain@gmail.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
namespace Mono.Cecil.Binary {
34
using Mono.Cecil.Metadata;
36
class ImageWriter : BaseImageVisitor {
40
MetadataWriter m_mdWriter;
41
BinaryWriter m_binaryWriter;
44
MemoryBinaryWriter m_textWriter;
46
MemoryBinaryWriter m_relocWriter;
48
MemoryBinaryWriter m_rsrcWriter;
50
public ImageWriter (MetadataWriter writer, AssemblyKind kind, BinaryWriter bw)
53
m_img = writer.GetMetadataRoot ().GetImage ();
57
m_textWriter = new MemoryBinaryWriter ();
58
m_textWriter.BaseStream.Position = 80;
59
m_relocWriter = new MemoryBinaryWriter ();
62
public Image GetImage ()
67
public MemoryBinaryWriter GetTextWriter ()
72
public uint GetAligned (uint integer, uint alignWith)
74
return (integer + alignWith - 1) & ~(alignWith - 1);
77
public void Initialize ()
80
ResourceWriter resWriter = null;
82
uint sectAlign = img.PEOptionalHeader.NTSpecificFields.SectionAlignment;
83
uint fileAlign = img.PEOptionalHeader.NTSpecificFields.FileAlignment;
85
m_textSect = img.TextSection;
86
foreach (Section s in img.Sections) {
87
if (s.Name == Section.Relocs)
89
else if (s.Name == Section.Resources) {
91
m_rsrcWriter = new MemoryBinaryWriter ();
93
resWriter = new ResourceWriter (img, m_rsrcSect, m_rsrcWriter);
98
// size computations, fields setting, etc.
99
uint nbSects = (uint) img.Sections.Count;
100
img.PEFileHeader.NumberOfSections = (ushort) nbSects;
102
// build the reloc section data
104
m_relocWriter.Write ((uint) 0);
105
m_relocWriter.Write (relocSize);
106
m_relocWriter.Write ((ushort) 0);
107
m_relocWriter.Write ((ushort) 0);
109
m_textSect.VirtualSize = (uint) m_textWriter.BaseStream.Length;
110
m_relocSect.VirtualSize = (uint) m_relocWriter.BaseStream.Length;
111
if (m_rsrcSect != null)
112
m_rsrcSect.VirtualSize = (uint) m_rsrcWriter.BaseStream.Length;
114
// start counting before sections headers
115
// section start + section header sixe * number of sections
116
uint headersEnd = 0x178 + 0x28 * nbSects;
117
uint fileOffset = headersEnd;
118
uint sectOffset = sectAlign;
121
foreach (Section sect in img.Sections) {
122
fileOffset = GetAligned (fileOffset, fileAlign);
123
sectOffset = GetAligned (sectOffset, sectAlign);
125
sect.PointerToRawData = new RVA (fileOffset);
126
sect.VirtualAddress = new RVA (sectOffset);
127
sect.SizeOfRawData = GetAligned (sect.VirtualSize, fileAlign);
129
fileOffset += sect.SizeOfRawData;
130
sectOffset += sect.SizeOfRawData;
131
imageSize += GetAligned (sect.SizeOfRawData, sectAlign);
134
if (m_textSect.VirtualAddress.Value != 0x2000)
135
throw new ImageFormatException ("Wrong RVA for .text section");
137
if (resWriter != null)
140
img.PEOptionalHeader.StandardFields.CodeSize = GetAligned (
141
m_textSect.SizeOfRawData, fileAlign);
142
img.PEOptionalHeader.StandardFields.InitializedDataSize = m_textSect.SizeOfRawData;
143
if (m_rsrcSect != null)
144
img.PEOptionalHeader.StandardFields.InitializedDataSize += m_rsrcSect.SizeOfRawData;
145
img.PEOptionalHeader.StandardFields.BaseOfCode = m_textSect.VirtualAddress;
146
img.PEOptionalHeader.StandardFields.BaseOfData = m_relocSect.VirtualAddress;
148
imageSize += headersEnd;
149
img.PEOptionalHeader.NTSpecificFields.ImageSize = GetAligned (imageSize, sectAlign);
151
img.PEOptionalHeader.DataDirectories.BaseRelocationTable = new DataDirectory (
152
m_relocSect.VirtualAddress, m_relocSect.VirtualSize);
153
if (m_rsrcSect != null)
154
img.PEOptionalHeader.DataDirectories.ResourceTable = new DataDirectory (
155
m_rsrcSect.VirtualAddress, (uint) m_rsrcWriter.BaseStream.Length);
157
if (m_kind == AssemblyKind.Dll) {
158
img.PEFileHeader.Characteristics = ImageCharacteristics.CILOnlyDll;
159
img.HintNameTable.RuntimeMain = HintNameTable.RuntimeMainDll;
160
img.PEOptionalHeader.NTSpecificFields.DLLFlags = 0x400;
162
img.PEFileHeader.Characteristics = ImageCharacteristics.CILOnlyExe;
163
img.HintNameTable.RuntimeMain = HintNameTable.RuntimeMainExe;
167
case AssemblyKind.Dll :
168
case AssemblyKind.Console :
169
img.PEOptionalHeader.NTSpecificFields.SubSystem = SubSystem.WindowsCui;
171
case AssemblyKind.Windows :
172
img.PEOptionalHeader.NTSpecificFields.SubSystem = SubSystem.WindowsGui;
176
RVA importTable = new RVA (img.TextSection.VirtualAddress + m_mdWriter.ImportTablePosition);
178
img.PEOptionalHeader.DataDirectories.ImportTable = new DataDirectory (importTable, 0x57);
180
img.ImportTable.ImportLookupTable = new RVA ((uint) importTable + 0x28);
182
img.ImportLookupTable.HintNameRVA = img.ImportAddressTable.HintNameTableRVA =
183
new RVA ((uint) img.ImportTable.ImportLookupTable + 0x14);
184
img.ImportTable.Name = new RVA ((uint) img.ImportLookupTable.HintNameRVA + 0xe);
187
public override void VisitDOSHeader (DOSHeader header)
189
m_binaryWriter.Write (header.Start);
190
m_binaryWriter.Write (header.Lfanew);
191
m_binaryWriter.Write (header.End);
193
m_binaryWriter.Write ((ushort) 0x4550);
194
m_binaryWriter.Write ((ushort) 0);
197
public override void VisitPEFileHeader (PEFileHeader header)
199
m_binaryWriter.Write (header.Machine);
200
m_binaryWriter.Write (header.NumberOfSections);
201
m_binaryWriter.Write (header.TimeDateStamp);
202
m_binaryWriter.Write (header.PointerToSymbolTable);
203
m_binaryWriter.Write (header.NumberOfSymbols);
204
m_binaryWriter.Write (header.OptionalHeaderSize);
205
m_binaryWriter.Write ((ushort) header.Characteristics);
208
public override void VisitNTSpecificFieldsHeader (PEOptionalHeader.NTSpecificFieldsHeader header)
210
WriteIntOrLong (header.ImageBase);
211
m_binaryWriter.Write (header.SectionAlignment);
212
m_binaryWriter.Write (header.FileAlignment);
213
m_binaryWriter.Write (header.OSMajor);
214
m_binaryWriter.Write (header.OSMinor);
215
m_binaryWriter.Write (header.UserMajor);
216
m_binaryWriter.Write (header.UserMinor);
217
m_binaryWriter.Write (header.SubSysMajor);
218
m_binaryWriter.Write (header.SubSysMinor);
219
m_binaryWriter.Write (header.Reserved);
220
m_binaryWriter.Write (header.ImageSize);
221
m_binaryWriter.Write (header.HeaderSize);
222
m_binaryWriter.Write (header.FileChecksum);
223
m_binaryWriter.Write ((ushort) header.SubSystem);
224
m_binaryWriter.Write (header.DLLFlags);
225
WriteIntOrLong (header.StackReserveSize);
226
WriteIntOrLong (header.StackCommitSize);
227
WriteIntOrLong (header.HeapReserveSize);
228
WriteIntOrLong (header.HeapCommitSize);
229
m_binaryWriter.Write (header.LoaderFlags);
230
m_binaryWriter.Write (header.NumberOfDataDir);
233
public override void VisitStandardFieldsHeader (PEOptionalHeader.StandardFieldsHeader header)
235
m_binaryWriter.Write (header.Magic);
236
m_binaryWriter.Write (header.LMajor);
237
m_binaryWriter.Write (header.LMinor);
238
m_binaryWriter.Write (header.CodeSize);
239
m_binaryWriter.Write (header.InitializedDataSize);
240
m_binaryWriter.Write (header.UninitializedDataSize);
241
m_binaryWriter.Write (header.EntryPointRVA.Value);
242
m_binaryWriter.Write (header.BaseOfCode.Value);
244
m_binaryWriter.Write (header.BaseOfData.Value);
247
void WriteIntOrLong (ulong value)
249
if (m_img.PEOptionalHeader.StandardFields.IsPE64)
250
m_binaryWriter.Write (value);
252
m_binaryWriter.Write ((uint) value);
255
public override void VisitDataDirectoriesHeader (PEOptionalHeader.DataDirectoriesHeader header)
257
m_binaryWriter.Write (header.ExportTable.VirtualAddress);
258
m_binaryWriter.Write (header.ExportTable.Size);
259
m_binaryWriter.Write (header.ImportTable.VirtualAddress);
260
m_binaryWriter.Write (header.ImportTable.Size);
261
m_binaryWriter.Write (header.ResourceTable.VirtualAddress);
262
m_binaryWriter.Write (header.ResourceTable.Size);
263
m_binaryWriter.Write (header.ExceptionTable.VirtualAddress);
264
m_binaryWriter.Write (header.ExceptionTable.Size);
265
m_binaryWriter.Write (header.CertificateTable.VirtualAddress);
266
m_binaryWriter.Write (header.CertificateTable.Size);
267
m_binaryWriter.Write (header.BaseRelocationTable.VirtualAddress);
268
m_binaryWriter.Write (header.BaseRelocationTable.Size);
269
m_binaryWriter.Write (header.Debug.VirtualAddress);
270
m_binaryWriter.Write (header.Debug.Size);
271
m_binaryWriter.Write (header.Copyright.VirtualAddress);
272
m_binaryWriter.Write (header.Copyright.Size);
273
m_binaryWriter.Write (header.GlobalPtr.VirtualAddress);
274
m_binaryWriter.Write (header.GlobalPtr.Size);
275
m_binaryWriter.Write (header.TLSTable.VirtualAddress);
276
m_binaryWriter.Write (header.TLSTable.Size);
277
m_binaryWriter.Write (header.LoadConfigTable.VirtualAddress);
278
m_binaryWriter.Write (header.LoadConfigTable.Size);
279
m_binaryWriter.Write (header.BoundImport.VirtualAddress);
280
m_binaryWriter.Write (header.BoundImport.Size);
281
m_binaryWriter.Write (header.IAT.VirtualAddress);
282
m_binaryWriter.Write (header.IAT.Size);
283
m_binaryWriter.Write (header.DelayImportDescriptor.VirtualAddress);
284
m_binaryWriter.Write (header.DelayImportDescriptor.Size);
285
m_binaryWriter.Write (header.CLIHeader.VirtualAddress);
286
m_binaryWriter.Write (header.CLIHeader.Size);
287
m_binaryWriter.Write (header.Reserved.VirtualAddress);
288
m_binaryWriter.Write (header.Reserved.Size);
291
public override void VisitSection (Section sect)
293
m_binaryWriter.Write (Encoding.ASCII.GetBytes (sect.Name));
294
int more = 8 - sect.Name.Length;
295
for (int i = 0; i < more; i++)
296
m_binaryWriter.Write ((byte) 0);
298
m_binaryWriter.Write (sect.VirtualSize);
299
m_binaryWriter.Write (sect.VirtualAddress.Value);
300
m_binaryWriter.Write (sect.SizeOfRawData);
301
m_binaryWriter.Write (sect.PointerToRawData.Value);
302
m_binaryWriter.Write (sect.PointerToRelocations.Value);
303
m_binaryWriter.Write (sect.PointerToLineNumbers.Value);
304
m_binaryWriter.Write (sect.NumberOfRelocations);
305
m_binaryWriter.Write (sect.NumberOfLineNumbers);
306
m_binaryWriter.Write ((uint) sect.Characteristics);
309
public override void VisitImportAddressTable (ImportAddressTable iat)
311
m_textWriter.BaseStream.Position = 0;
312
m_textWriter.Write (iat.HintNameTableRVA.Value);
313
m_textWriter.Write (new byte [4]);
316
public override void VisitCLIHeader (CLIHeader header)
318
m_textWriter.Write (header.Cb);
319
m_textWriter.Write (header.MajorRuntimeVersion);
320
m_textWriter.Write (header.MinorRuntimeVersion);
321
m_textWriter.Write (header.Metadata.VirtualAddress);
322
m_textWriter.Write (header.Metadata.Size);
323
m_textWriter.Write ((uint) header.Flags);
324
m_textWriter.Write (header.EntryPointToken);
325
m_textWriter.Write (header.Resources.VirtualAddress);
326
m_textWriter.Write (header.Resources.Size);
327
m_textWriter.Write (header.StrongNameSignature.VirtualAddress);
328
m_textWriter.Write (header.StrongNameSignature.Size);
329
m_textWriter.Write (header.CodeManagerTable.VirtualAddress);
330
m_textWriter.Write (header.CodeManagerTable.Size);
331
m_textWriter.Write (header.VTableFixups.VirtualAddress);
332
m_textWriter.Write (header.VTableFixups.Size);
333
m_textWriter.Write (header.ExportAddressTableJumps.VirtualAddress);
334
m_textWriter.Write (header.ExportAddressTableJumps.Size);
335
m_textWriter.Write (header.ManagedNativeHeader.VirtualAddress);
336
m_textWriter.Write (header.ManagedNativeHeader.Size);
339
public override void VisitDebugHeader (DebugHeader header)
341
m_textWriter.BaseStream.Position = m_mdWriter.DebugHeaderPosition;
342
uint sizeUntilData = 0x1c;
343
header.AddressOfRawData = m_img.TextSection.VirtualAddress + m_mdWriter.DebugHeaderPosition + sizeUntilData;
344
header.PointerToRawData = 0x200 + m_mdWriter.DebugHeaderPosition + sizeUntilData;
345
header.SizeOfData = 0x18 + (uint) header.FileName.Length + 1;
347
m_textWriter.Write (header.Characteristics);
348
m_textWriter.Write (header.TimeDateStamp);
349
m_textWriter.Write (header.MajorVersion);
350
m_textWriter.Write (header.MinorVersion);
351
m_textWriter.Write ((uint) header.Type);
352
m_textWriter.Write (header.SizeOfData);
353
m_textWriter.Write (header.AddressOfRawData.Value);
354
m_textWriter.Write (header.PointerToRawData);
356
m_textWriter.Write (header.Magic);
357
m_textWriter.Write (header.Signature.ToByteArray ());
358
m_textWriter.Write (header.Age);
359
m_textWriter.Write (Encoding.ASCII.GetBytes (header.FileName));
360
m_textWriter.Write ((byte) 0);
363
public override void VisitImportTable (ImportTable it)
365
m_textWriter.BaseStream.Position = m_mdWriter.ImportTablePosition;
366
m_textWriter.Write (it.ImportLookupTable.Value);
367
m_textWriter.Write (it.DateTimeStamp);
368
m_textWriter.Write (it.ForwardChain);
369
m_textWriter.Write (it.Name.Value);
370
m_textWriter.Write (it.ImportAddressTable.Value);
371
m_textWriter.Write (new byte [20]);
374
public override void VisitImportLookupTable (ImportLookupTable ilt)
376
m_textWriter.Write (ilt.HintNameRVA.Value);
377
m_textWriter.Write (new byte [16]);
380
public override void VisitHintNameTable (HintNameTable hnt)
382
m_textWriter.Write (hnt.Hint);
383
m_textWriter.Write (Encoding.ASCII.GetBytes (hnt.RuntimeMain));
384
m_textWriter.Write ('\0');
385
m_textWriter.Write (Encoding.ASCII.GetBytes (hnt.RuntimeLibrary));
386
m_textWriter.Write ('\0');
387
m_textWriter.Write (new byte [4]);
389
// patch header with ep rva
390
RVA ep = m_img.TextSection.VirtualAddress +
391
(uint) m_textWriter.BaseStream.Position;
392
long pos = m_binaryWriter.BaseStream.Position;
393
m_binaryWriter.BaseStream.Position = 0xa8;
394
m_binaryWriter.Write (ep.Value);
395
m_binaryWriter.BaseStream.Position = pos;
397
// patch reloc Sect with ep
398
uint reloc = (ep.Value + 2) % 0x1000;
399
uint rva = (ep.Value + 2) - reloc;
401
m_relocWriter.BaseStream.Position = 0;
402
m_relocWriter.Write (rva);
403
m_relocWriter.BaseStream.Position = 8;
404
m_relocWriter.Write ((ushort) ((3 << 12) | reloc));
406
m_textWriter.Write (hnt.EntryPoint);
407
m_textWriter.Write (hnt.RVA);
410
public override void TerminateImage (Image img)
412
m_binaryWriter.BaseStream.Position = 0x200;
414
WriteSection (m_textSect, m_textWriter);
415
WriteSection (m_relocSect, m_relocWriter);
416
if (m_rsrcSect != null)
417
WriteSection (m_rsrcSect, m_rsrcWriter);
420
void WriteSection (Section sect, MemoryBinaryWriter sectWriter)
422
sectWriter.MemoryStream.WriteTo (m_binaryWriter.BaseStream);
423
m_binaryWriter.Write (new byte [
424
sect.SizeOfRawData - sectWriter.BaseStream.Length]);