/*
* Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
*/
using System;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
using Mono.PEToolkit.Metadata;
namespace Mono.PEToolkit{
public class Image : IDisposable {
internal DOSHeader dosHdr;
internal COFFHeader coffHdr;
internal PEHeader peHdr;
internal CorHeader corHdr;
internal Hashtable sections;
// File position right after PEHeader (NT Optional Header).
protected long sectionsPos;
private MetaDataRoot mdRoot;
private string name;
private bool open;
internal BinaryReader reader;
public Image(string name)
{
this.name = name;
open = false;
reader = null;
mdRoot = null;
dosHdr = new DOSHeader();
coffHdr = new COFFHeader();
peHdr = new PEHeader();
corHdr = new CorHeader();
sections = new Hashtable();
sectionsPos = -1;
}
~Image()
{
Close();
}
/*****
* Code added by Bruno Cabral
* */
public CorHeader CorHdr
{
get
{
return this.corHdr;
}
}
public BinaryReader GetResourcesReader()
{
BinaryReader bReader = new BinaryReader(this.reader.BaseStream);
bReader.BaseStream.Position = RVAToVA(this.corHdr.Resources.VirtualAddress);
return this.reader;
}
/**
* End of Code added
* */
public Hashtable Sections {
get {
return sections;
}
}
public void Open()
{
lock (this) if (!open) {
FileInfo pe = new FileInfo(name);
if (!pe.Exists) {
throw new Exception("Invalid file path.");
}
reader = new BinaryReader(new BufferedStream(pe.OpenRead()));
if (!reader.BaseStream.CanSeek) {
throw new Exception("Can't seek.");
}
open = true;
}
}
public void Close()
{
lock (this) if (open) {
reader.Close();
open = false;
}
}
// IDisposable
public void Dispose()
{
Close();
}
public bool IsCLI {
get {
return peHdr.IsCLIImage;
}
}
public MetaDataRoot MetadataRoot {
get {
return mdRoot;
}
}
/// <summary>
/// </summary>
public void ReadHeaders()
{
if (!open) {
throw new Exception("You must open image before trying to read it.");
}
dosHdr.Read(reader);
reader.BaseStream.Position = dosHdr.Lfanew;
ExeSignature peSig = (ExeSignature) reader.ReadUInt16();
if (peSig != ExeSignature.NT) {
throw new Exception ("Invalid image format: cannot find PE signature.");
}
peSig = (ExeSignature) reader.ReadUInt16();
if (peSig != ExeSignature.NT2) {
throw new Exception ("Invalid image format: cannot find PE signature.");
}
coffHdr.Read(reader);
peHdr.Read(reader);
sectionsPos = reader.BaseStream.Position;
ReadSections();
if (this.IsCLI) {
reader.BaseStream.Position = RVAToVA(peHdr.CLIHdrDir.virtAddr);
corHdr.Read (reader);
mdRoot = new MetaDataRoot(this);
reader.BaseStream.Position = RVAToVA(corHdr.MetaData.virtAddr);
mdRoot.Read(reader);
}
}
public void WriteHeaders (BinaryWriter writer)
{
dosHdr.Write (writer);
writer.BaseStream.Position = dosHdr.Lfanew;
writer.Write ((ushort)ExeSignature.NT);
writer.Write ((ushort)ExeSignature.NT2);
coffHdr.Write (writer);
peHdr.Write (writer);
WriteSections (writer);
if (this.IsCLI) {
writer.BaseStream.Position = RVAToVA (peHdr.CLIHdrDir.virtAddr);
corHdr.Write (writer);
long pos = RVAToVA (corHdr.MetaData.virtAddr);
writer.BaseStream.Position = pos;
mdRoot.Write (writer);
}
}
/// <summary>
/// </summary>
protected void ReadSections()
{
if (sectionsPos < 0) {
throw new Exception("Read headers first.");
}
reader.BaseStream.Position = sectionsPos;
int n = coffHdr.NumberOfSections;
for (int i = n; --i >=0;) {
Section sect = new Section();
sect.Read(reader);
sections [sect.Name] = sect;
}
}
protected void WriteSections (BinaryWriter writer)
{
foreach (Section section in sections.Values) {
section.Write (writer);
}
}
/// <summary>
/// </summary>
/// <param name="writer"></param>
public void Dump(TextWriter writer)
{
writer.WriteLine (
"COFF Header:" + Environment.NewLine +
coffHdr.ToString() + Environment.NewLine +
"PE Header:" + Environment.NewLine +
peHdr.ToString() + Environment.NewLine +
"Core Header:" + Environment.NewLine +
corHdr.ToString()
);
}
/// <summary>
/// </summary>
/// <returns></returns>
public override string ToString()
{
StringWriter sw = new StringWriter();
Dump(sw);
return sw.ToString();
}
/// <summary>
/// Returns name of the section for the given RVA.
/// </summary>
/// <param name="rva"></param>
/// <returns></returns>
public string RVAToSectionName(RVA rva)
{
string res = null;
foreach (Section s in Sections.Values) {
RVA sva = s.VirtualAddress;
if (rva >= sva && rva < sva + s.SizeOfRawData) {
res = s.Name;
break;
}
}
return res;
}
public long RVAToVA(RVA rva)
{
string sectName = RVAToSectionName(rva);
long res = 0;
if (sectName != null) {
Section s = (Section) Sections [sectName];
res = rva + (s.PointerToRawData - s.VirtualAddress);
}
return res;
}
public MetaDataRoot MetaDataRoot {
get {
return mdRoot;
}
}
public void DumpStreamHeader(TextWriter writer, string name)
{
if (mdRoot == null || name == null || name == String.Empty || writer == null) return;
writer.Write(name + " header: ");
MDStream s = MetaDataRoot.Streams[name] as MDStream;
if (s != null) {
writer.WriteLine();
writer.WriteLine(s);
} else {
writer.WriteLine("not present.");
writer.WriteLine();
}
}
public void DumpStreamHeader(string name)
{
DumpStreamHeader(Console.Out, name);
}
/// <summary>
/// ADDED BY Bruno Cabral
/// </summary>
/// <returns>The token to the entrypoint of the assembly</returns>
public MDToken GetEntryPointToken()
{
return this.corHdr.EntryPointToken;
}
}
}
|