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 sealed 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);
320 if (m_mdWriter.TargetRuntime >= TargetRuntime.NET_2_0) {
321 m_textWriter.Write ((ushort) 2);
322 m_textWriter.Write ((ushort) 5);
324 m_textWriter.Write ((ushort) 2);
325 m_textWriter.Write ((ushort) 0);
328 m_textWriter.Write (header.Metadata.VirtualAddress);
329 m_textWriter.Write (header.Metadata.Size);
330 m_textWriter.Write ((uint) header.Flags);
331 m_textWriter.Write (header.EntryPointToken);
332 m_textWriter.Write (header.Resources.VirtualAddress);
333 m_textWriter.Write (header.Resources.Size);
334 m_textWriter.Write (header.StrongNameSignature.VirtualAddress);
335 m_textWriter.Write (header.StrongNameSignature.Size);
336 m_textWriter.Write (header.CodeManagerTable.VirtualAddress);
337 m_textWriter.Write (header.CodeManagerTable.Size);
338 m_textWriter.Write (header.VTableFixups.VirtualAddress);
339 m_textWriter.Write (header.VTableFixups.Size);
340 m_textWriter.Write (header.ExportAddressTableJumps.VirtualAddress);
341 m_textWriter.Write (header.ExportAddressTableJumps.Size);
342 m_textWriter.Write (header.ManagedNativeHeader.VirtualAddress);
343 m_textWriter.Write (header.ManagedNativeHeader.Size);
346 public override void VisitDebugHeader (DebugHeader header)
348 m_textWriter.BaseStream.Position = m_mdWriter.DebugHeaderPosition;
349 uint sizeUntilData = 0x1c;
350 header.AddressOfRawData = m_img.TextSection.VirtualAddress + m_mdWriter.DebugHeaderPosition + sizeUntilData;
351 header.PointerToRawData = 0x200 + m_mdWriter.DebugHeaderPosition + sizeUntilData;
352 header.SizeOfData = 0x18 + (uint) header.FileName.Length + 1;
354 m_textWriter.Write (header.Characteristics);
355 m_textWriter.Write (header.TimeDateStamp);
356 m_textWriter.Write (header.MajorVersion);
357 m_textWriter.Write (header.MinorVersion);
358 m_textWriter.Write ((uint) header.Type);
359 m_textWriter.Write (header.SizeOfData);
360 m_textWriter.Write (header.AddressOfRawData.Value);
361 m_textWriter.Write (header.PointerToRawData);
363 m_textWriter.Write (header.Magic);
364 m_textWriter.Write (header.Signature.ToByteArray ());
365 m_textWriter.Write (header.Age);
366 m_textWriter.Write (Encoding.ASCII.GetBytes (header.FileName));
367 m_textWriter.Write ((byte) 0);
370 public override void VisitImportTable (ImportTable it)
372 m_textWriter.BaseStream.Position = m_mdWriter.ImportTablePosition;
373 m_textWriter.Write (it.ImportLookupTable.Value);
374 m_textWriter.Write (it.DateTimeStamp);
375 m_textWriter.Write (it.ForwardChain);
376 m_textWriter.Write (it.Name.Value);
377 m_textWriter.Write (it.ImportAddressTable.Value);
378 m_textWriter.Write (new byte [20]);
381 public override void VisitImportLookupTable (ImportLookupTable ilt)
383 m_textWriter.Write (ilt.HintNameRVA.Value);
384 m_textWriter.Write (new byte [16]);
387 public override void VisitHintNameTable (HintNameTable hnt)
389 m_textWriter.Write (hnt.Hint);
390 m_textWriter.Write (Encoding.ASCII.GetBytes (hnt.RuntimeMain));
391 m_textWriter.Write ('\0');
392 m_textWriter.Write (Encoding.ASCII.GetBytes (hnt.RuntimeLibrary));
393 m_textWriter.Write ('\0');
394 m_textWriter.Write (new byte [4]);
396 // patch header with ep rva
397 RVA ep = m_img.TextSection.VirtualAddress +
398 (uint) m_textWriter.BaseStream.Position;
399 long pos = m_binaryWriter.BaseStream.Position;
400 m_binaryWriter.BaseStream.Position = 0xa8;
401 m_binaryWriter.Write (ep.Value);
402 m_binaryWriter.BaseStream.Position = pos;
404 // patch reloc Sect with ep
405 uint reloc = (ep.Value + 2) % 0x1000;
406 uint rva = (ep.Value + 2) - reloc;
408 m_relocWriter.BaseStream.Position = 0;
409 m_relocWriter.Write (rva);
410 m_relocWriter.BaseStream.Position = 8;
411 m_relocWriter.Write ((ushort) ((3 << 12) | reloc));
413 m_textWriter.Write (hnt.EntryPoint);
414 m_textWriter.Write (hnt.RVA);
417 public override void TerminateImage (Image img)
419 m_binaryWriter.BaseStream.Position = 0x200;
421 WriteSection (m_textSect, m_textWriter);
422 WriteSection (m_relocSect, m_relocWriter);
423 if (m_rsrcSect != null)
424 WriteSection (m_rsrcSect, m_rsrcWriter);
427 void WriteSection (Section sect, MemoryBinaryWriter sectWriter)
429 sectWriter.MemoryStream.WriteTo (m_binaryWriter.BaseStream);
430 m_binaryWriter.Write (new byte [
431 sect.SizeOfRawData - sectWriter.BaseStream.Length]);