~do-win/do/test-paths

« back to all changes in this revision

Viewing changes to Mono.Addins.CecilReflector/Mono.Cecil/Mono.Cecil.Binary/ImageWriter.cs

  • Committer: Chris S.
  • Date: 2009-06-21 03:37:34 UTC
  • Revision ID: chris@szikszoy.com-20090621033734-ud2jdcd5pq9r3ue9
initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// ImageWriter.cs
 
3
//
 
4
// Author:
 
5
//   Jb Evain (jbevain@gmail.com)
 
6
//
 
7
// (C) 2005 Jb Evain
 
8
//
 
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:
 
16
//
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
//
 
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.
 
27
//
 
28
 
 
29
namespace Mono.Cecil.Binary {
 
30
 
 
31
        using System.IO;
 
32
        using System.Text;
 
33
 
 
34
        using Mono.Cecil.Metadata;
 
35
 
 
36
        class ImageWriter : BaseImageVisitor {
 
37
 
 
38
                Image m_img;
 
39
                AssemblyKind m_kind;
 
40
                MetadataWriter m_mdWriter;
 
41
                BinaryWriter m_binaryWriter;
 
42
 
 
43
                Section m_textSect;
 
44
                MemoryBinaryWriter m_textWriter;
 
45
                Section m_relocSect;
 
46
                MemoryBinaryWriter m_relocWriter;
 
47
                Section m_rsrcSect;
 
48
                MemoryBinaryWriter m_rsrcWriter;
 
49
 
 
50
                public ImageWriter (MetadataWriter writer, AssemblyKind kind, BinaryWriter bw)
 
51
                {
 
52
                        m_mdWriter= writer;
 
53
                        m_img = writer.GetMetadataRoot ().GetImage ();
 
54
                        m_kind = kind;
 
55
                        m_binaryWriter = bw;
 
56
 
 
57
                        m_textWriter = new MemoryBinaryWriter ();
 
58
                        m_textWriter.BaseStream.Position = 80;
 
59
                        m_relocWriter = new MemoryBinaryWriter ();
 
60
                }
 
61
 
 
62
                public Image GetImage ()
 
63
                {
 
64
                        return m_img;
 
65
                }
 
66
 
 
67
                public MemoryBinaryWriter GetTextWriter ()
 
68
                {
 
69
                        return m_textWriter;
 
70
                }
 
71
 
 
72
                public uint GetAligned (uint integer, uint alignWith)
 
73
                {
 
74
                        return (integer + alignWith - 1) & ~(alignWith - 1);
 
75
                }
 
76
 
 
77
                public void Initialize ()
 
78
                {
 
79
                        Image img = m_img;
 
80
                        ResourceWriter resWriter = null;
 
81
 
 
82
                        uint sectAlign = img.PEOptionalHeader.NTSpecificFields.SectionAlignment;
 
83
                        uint fileAlign = img.PEOptionalHeader.NTSpecificFields.FileAlignment;
 
84
 
 
85
                        m_textSect = img.TextSection;
 
86
                        foreach (Section s in img.Sections) {
 
87
                                if (s.Name == Section.Relocs)
 
88
                                        m_relocSect = s;
 
89
                                else if (s.Name == Section.Resources) {
 
90
                                        m_rsrcSect = s;
 
91
                                        m_rsrcWriter = new MemoryBinaryWriter ();
 
92
 
 
93
                                        resWriter = new ResourceWriter (img, m_rsrcSect, m_rsrcWriter);
 
94
                                        resWriter.Write ();
 
95
                                }
 
96
                        }
 
97
 
 
98
                        // size computations, fields setting, etc.
 
99
                        uint nbSects = (uint) img.Sections.Count;
 
100
                        img.PEFileHeader.NumberOfSections = (ushort) nbSects;
 
101
 
 
102
                        // build the reloc section data
 
103
                        uint relocSize = 12;
 
104
                        m_relocWriter.Write ((uint) 0);
 
105
                        m_relocWriter.Write (relocSize);
 
106
                        m_relocWriter.Write ((ushort) 0);
 
107
                        m_relocWriter.Write ((ushort) 0);
 
108
 
 
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;
 
113
 
 
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;
 
119
                        uint imageSize = 0;
 
120
 
 
121
                        foreach (Section sect in img.Sections) {
 
122
                                fileOffset = GetAligned (fileOffset, fileAlign);
 
123
                                sectOffset = GetAligned (sectOffset, sectAlign);
 
124
 
 
125
                                sect.PointerToRawData = new RVA (fileOffset);
 
126
                                sect.VirtualAddress = new RVA (sectOffset);
 
127
                                sect.SizeOfRawData = GetAligned (sect.VirtualSize, fileAlign);
 
128
 
 
129
                                fileOffset += sect.SizeOfRawData;
 
130
                                sectOffset += sect.SizeOfRawData;
 
131
                                imageSize += GetAligned (sect.SizeOfRawData, sectAlign);
 
132
                        }
 
133
 
 
134
                        if (m_textSect.VirtualAddress.Value != 0x2000)
 
135
                                throw new ImageFormatException ("Wrong RVA for .text section");
 
136
 
 
137
                        if (resWriter != null)
 
138
                                resWriter.Patch ();
 
139
 
 
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;
 
147
 
 
148
                        imageSize += headersEnd;
 
149
                        img.PEOptionalHeader.NTSpecificFields.ImageSize = GetAligned (imageSize, sectAlign);
 
150
 
 
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);
 
156
 
 
157
                        if (m_kind == AssemblyKind.Dll) {
 
158
                                img.PEFileHeader.Characteristics = ImageCharacteristics.CILOnlyDll;
 
159
                                img.HintNameTable.RuntimeMain = HintNameTable.RuntimeMainDll;
 
160
                                img.PEOptionalHeader.NTSpecificFields.DLLFlags = 0x400;
 
161
                        } else {
 
162
                                img.PEFileHeader.Characteristics = ImageCharacteristics.CILOnlyExe;
 
163
                                img.HintNameTable.RuntimeMain = HintNameTable.RuntimeMainExe;
 
164
                        }
 
165
 
 
166
                        switch (m_kind) {
 
167
                        case AssemblyKind.Dll :
 
168
                        case AssemblyKind.Console :
 
169
                                img.PEOptionalHeader.NTSpecificFields.SubSystem = SubSystem.WindowsCui;
 
170
                                break;
 
171
                        case AssemblyKind.Windows :
 
172
                                img.PEOptionalHeader.NTSpecificFields.SubSystem = SubSystem.WindowsGui;
 
173
                                break;
 
174
                        }
 
175
 
 
176
                        RVA importTable = new RVA (img.TextSection.VirtualAddress + m_mdWriter.ImportTablePosition);
 
177
 
 
178
                        img.PEOptionalHeader.DataDirectories.ImportTable = new DataDirectory (importTable, 0x57);
 
179
 
 
180
                        img.ImportTable.ImportLookupTable = new RVA ((uint) importTable + 0x28);
 
181
 
 
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);
 
185
                }
 
186
 
 
187
                public override void VisitDOSHeader (DOSHeader header)
 
188
                {
 
189
                        m_binaryWriter.Write (header.Start);
 
190
                        m_binaryWriter.Write (header.Lfanew);
 
191
                        m_binaryWriter.Write (header.End);
 
192
 
 
193
                        m_binaryWriter.Write ((ushort) 0x4550);
 
194
                        m_binaryWriter.Write ((ushort) 0);
 
195
                }
 
196
 
 
197
                public override void VisitPEFileHeader (PEFileHeader header)
 
198
                {
 
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);
 
206
                }
 
207
 
 
208
                public override void VisitNTSpecificFieldsHeader (PEOptionalHeader.NTSpecificFieldsHeader header)
 
209
                {
 
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);
 
231
                }
 
232
 
 
233
                public override void VisitStandardFieldsHeader (PEOptionalHeader.StandardFieldsHeader header)
 
234
                {
 
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);
 
243
                        if (!header.IsPE64)
 
244
                                m_binaryWriter.Write (header.BaseOfData.Value);
 
245
                }
 
246
 
 
247
                void WriteIntOrLong (ulong value)
 
248
                {
 
249
                        if (m_img.PEOptionalHeader.StandardFields.IsPE64)
 
250
                                m_binaryWriter.Write (value);
 
251
                        else
 
252
                                m_binaryWriter.Write ((uint) value);
 
253
                }
 
254
 
 
255
                public override void VisitDataDirectoriesHeader (PEOptionalHeader.DataDirectoriesHeader header)
 
256
                {
 
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);
 
289
                }
 
290
 
 
291
                public override void VisitSection (Section sect)
 
292
                {
 
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);
 
297
 
 
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);
 
307
                }
 
308
 
 
309
                public override void VisitImportAddressTable (ImportAddressTable iat)
 
310
                {
 
311
                        m_textWriter.BaseStream.Position = 0;
 
312
                        m_textWriter.Write (iat.HintNameTableRVA.Value);
 
313
                        m_textWriter.Write (new byte [4]);
 
314
                }
 
315
 
 
316
                public override void VisitCLIHeader (CLIHeader header)
 
317
                {
 
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);
 
337
                }
 
338
 
 
339
                public override void VisitDebugHeader (DebugHeader header)
 
340
                {
 
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;
 
346
 
 
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);
 
355
 
 
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);
 
361
                }
 
362
 
 
363
                public override void VisitImportTable (ImportTable it)
 
364
                {
 
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]);
 
372
                }
 
373
 
 
374
                public override void VisitImportLookupTable (ImportLookupTable ilt)
 
375
                {
 
376
                        m_textWriter.Write (ilt.HintNameRVA.Value);
 
377
                        m_textWriter.Write (new byte [16]);
 
378
                }
 
379
 
 
380
                public override void VisitHintNameTable (HintNameTable hnt)
 
381
                {
 
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]);
 
388
 
 
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;
 
396
 
 
397
                        // patch reloc Sect with ep
 
398
                        uint reloc = (ep.Value + 2) % 0x1000;
 
399
                        uint rva = (ep.Value + 2) - reloc;
 
400
 
 
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));
 
405
 
 
406
                        m_textWriter.Write (hnt.EntryPoint);
 
407
                        m_textWriter.Write (hnt.RVA);
 
408
                }
 
409
 
 
410
                public override void TerminateImage (Image img)
 
411
                {
 
412
                        m_binaryWriter.BaseStream.Position = 0x200;
 
413
 
 
414
                        WriteSection (m_textSect, m_textWriter);
 
415
                        WriteSection (m_relocSect, m_relocWriter);
 
416
                        if (m_rsrcSect != null)
 
417
                                WriteSection (m_rsrcSect, m_rsrcWriter);
 
418
                }
 
419
 
 
420
                void WriteSection (Section sect, MemoryBinaryWriter sectWriter)
 
421
                {
 
422
                        sectWriter.MemoryStream.WriteTo (m_binaryWriter.BaseStream);
 
423
                        m_binaryWriter.Write (new byte [
 
424
                                                sect.SizeOfRawData - sectWriter.BaseStream.Length]);
 
425
                }
 
426
        }
 
427
}