236 lines
9.7 KiB
C#
236 lines
9.7 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Simple PE Loader for Singularity
|
||
|
//
|
||
|
// Currently does not support:
|
||
|
// x64
|
||
|
// sections loaded at separate addresses
|
||
|
// loading at preferred address
|
||
|
|
||
|
// #define verbose
|
||
|
|
||
|
namespace Microsoft.Singularity.Loader
|
||
|
{
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Io;
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Threading;
|
||
|
|
||
|
[CLSCompliant(false)]
|
||
|
internal class ImportTable
|
||
|
{
|
||
|
private IoMemory mem;
|
||
|
private DirectoryEntry entry;
|
||
|
|
||
|
internal ImportTable(IoMemory mem, DirectoryEntry entry)
|
||
|
{
|
||
|
this.mem = mem;
|
||
|
this.entry = entry;
|
||
|
|
||
|
if (entry.size == 0)
|
||
|
{
|
||
|
DebugStub.WriteLine("// No import table.");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if verbose
|
||
|
[Conditional("DEBUG")]
|
||
|
public void DumpIAT(String title)
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "// {0}", title);
|
||
|
if (entry.size == 0)
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "// No data.");
|
||
|
return;
|
||
|
}
|
||
|
int importOffset = (int)entry.virtualAddress;
|
||
|
Tracing.Log(Tracing.Debug, " import offset={0:x8}", importOffset);
|
||
|
//
|
||
|
// start at the importOffset specified above creating and filling out ImportDescriptors
|
||
|
// There is no indication in the header as to how many descriptors are present.
|
||
|
// In the last descriptor all fields will be 0; this code checks just the firstChunk field.
|
||
|
//
|
||
|
for (;;)
|
||
|
{
|
||
|
ImportDescriptor importDescriptor =
|
||
|
new ImportDescriptor(mem, ref importOffset);
|
||
|
|
||
|
//Use hit/Name array pointed to by "characteristics"
|
||
|
// FirstChunk points to the IAT table which is modified at load time to
|
||
|
// to reflect the fixed-up thunk to access the function
|
||
|
if (importDescriptor.characteristics == 0) {
|
||
|
return;
|
||
|
}
|
||
|
String name = null;
|
||
|
if (importDescriptor.name != 0) {
|
||
|
name = mem.ReadAsciiZeroString((int)importDescriptor.name);
|
||
|
}
|
||
|
Tracing.Log(Tracing.Debug, "// {0}", name);
|
||
|
importDescriptor.DumpToStream();
|
||
|
Tracing.Log(Tracing.Debug, "//");
|
||
|
|
||
|
int importTableOffset = (int)importDescriptor.characteristics;
|
||
|
for (;;)
|
||
|
{
|
||
|
int importTableID = (int) mem.Read32(importTableOffset);
|
||
|
if (importTableID == 0) {
|
||
|
break;
|
||
|
}
|
||
|
Tracing.Log(Tracing.Debug, "importTableID is {0:x8}", importTableID);
|
||
|
int nameStringOffset =
|
||
|
importTableID & 0x7fffffff;
|
||
|
importTableOffset += 4;
|
||
|
if ((importTableID & 0x8000000) != 0) {
|
||
|
Tracing.Log(Tracing.Debug, "// {0:x8} by ordinal {1:x8}",
|
||
|
mem.Read16(importTableOffset),
|
||
|
(importTableID & 0x7ffffff));
|
||
|
}
|
||
|
else {
|
||
|
Tracing.Log(Tracing.Debug, "// {1:x8} {0:x8}",
|
||
|
mem.ReadAsciiZeroString(nameStringOffset+2),
|
||
|
mem.Read16(importTableOffset));
|
||
|
}
|
||
|
}
|
||
|
Tracing.Log(Tracing.Debug, "");
|
||
|
}
|
||
|
//throw new BadImageFormatException("");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
public void ResolveImports(ExportTable exports)
|
||
|
{
|
||
|
if (entry.size == 0)
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "// No imports to resolve.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int importOffset = (int)entry.virtualAddress;
|
||
|
//Tracing.Log(Tracing.Debug, " import offset={0:x8}", importOffset);
|
||
|
//
|
||
|
// start at the importOffset specified above creating and filling out ImportDescriptors
|
||
|
// There is no indication in the header as to how many descriptors are present.
|
||
|
// In the last descriptor all fields will be 0; this code checks just the firstChunk field.
|
||
|
//
|
||
|
for (;;) {
|
||
|
ImportDescriptor importDescriptor =
|
||
|
new ImportDescriptor(mem, ref importOffset);
|
||
|
if (importDescriptor.firstChunk == 0) {
|
||
|
return;
|
||
|
}
|
||
|
ushort hint = 0;
|
||
|
String name = null;
|
||
|
if (importDescriptor.name != 0) {
|
||
|
name = mem.ReadAsciiZeroString((int)importDescriptor.name);
|
||
|
}
|
||
|
#if verbose
|
||
|
Tracing.Log(Tracing.Debug, "// {0}", name);
|
||
|
importDescriptor.DumpToStream("// ");
|
||
|
Tracing.Log(Tracing.Debug, "//");
|
||
|
#endif
|
||
|
UIntPtr offsetHintTable = UIntPtr.Zero;
|
||
|
|
||
|
if (0 == importDescriptor.characteristics) {
|
||
|
offsetHintTable = (UIntPtr)importDescriptor.characteristics;
|
||
|
}
|
||
|
else {
|
||
|
offsetHintTable = (UIntPtr)importDescriptor.firstChunk;
|
||
|
}
|
||
|
UIntPtr offsetIAT = (UIntPtr)importDescriptor.firstChunk;
|
||
|
|
||
|
for (;;) {
|
||
|
// read elements in the hint array for processing
|
||
|
// the hint array terminates when the its content is 0
|
||
|
int importByNameEntry = (int) mem.Read32((int)offsetHintTable);
|
||
|
if (importByNameEntry == 0) break;
|
||
|
#if verbose
|
||
|
Tracing.Log(Tracing.Debug, "importByName entry is {0:x8}",
|
||
|
importByNameEntry);
|
||
|
#endif
|
||
|
int nameStringOffset = importByNameEntry & 0x7fffffff;
|
||
|
if ((importByNameEntry & 0x8000000) != 0) {
|
||
|
// should never happen in Singularity (no Ordinals)
|
||
|
throw new BadImageFormatException("Import Ordinal encountered");
|
||
|
}
|
||
|
else {
|
||
|
name = mem.ReadAsciiZeroString((int)nameStringOffset+2);
|
||
|
hint = mem.Read16Unchecked(nameStringOffset);
|
||
|
//Tracing.Log(Tracing.Debug, " function to lookup is {0}", name);
|
||
|
|
||
|
UIntPtr addr = exports.Resolve(hint, name);
|
||
|
if (0 != addr)
|
||
|
{
|
||
|
//Overwrite ptr in IAT with address of function in the
|
||
|
// IAT thunk table
|
||
|
#if verbose
|
||
|
int meth = name.IndexOf('@');
|
||
|
int rest = name.IndexOf('@', meth + 1) + 1;
|
||
|
int clas = name.LastIndexOf('_', rest, rest - meth) + 1;
|
||
|
Tracing.Log(Tracing.Debug, " import: {1:x8} is {2:x8} {0}",
|
||
|
name.Substring(0, meth) + "@" + name.Substring(clas, rest - clas) + "@" name.Substring(rest)
|
||
|
(uint)offsetIAT, (uint)addr);
|
||
|
#endif
|
||
|
mem.Write32((int) offsetIAT,(uint)addr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, " Import not found: {0}", name);
|
||
|
throw new BadImageFormatException("Import Ordinal encountered");
|
||
|
}
|
||
|
}
|
||
|
// increment "array indices"
|
||
|
offsetIAT += 4;
|
||
|
offsetHintTable +=4;
|
||
|
}
|
||
|
//Tracing.Log(Tracing.Debug, "");
|
||
|
}
|
||
|
//throw new BadImageFormatException("");
|
||
|
}
|
||
|
|
||
|
internal struct ImportDescriptor
|
||
|
{
|
||
|
internal ImportDescriptor(IoMemory mem, ref int offset)
|
||
|
{
|
||
|
if (offset + 20 > mem.Length) {
|
||
|
Error.AccessOutOfRange();
|
||
|
}
|
||
|
this.characteristics = mem.Read32Unchecked(offset + 0);
|
||
|
this.timeDateStamp = mem.Read32Unchecked(offset + 4);
|
||
|
this.forwarderChain = mem.Read32Unchecked(offset + 8);
|
||
|
this.name = mem.Read32Unchecked(offset + 12);
|
||
|
this.firstChunk = mem.Read32Unchecked(offset + 16);
|
||
|
offset += 20;
|
||
|
}
|
||
|
|
||
|
[Conditional("DEBUG")]
|
||
|
internal void DumpToStream()
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "{0:x8} Import Address Table", firstChunk);
|
||
|
Tracing.Log(Tracing.Debug, "{0:x8} Import Name Table", name);
|
||
|
Tracing.Log(Tracing.Debug, "{0:x8} Time date stamp", timeDateStamp);
|
||
|
Tracing.Log(Tracing.Debug, "{0:x8} Index of first forwarder reference",
|
||
|
forwarderChain);
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
internal readonly uint characteristics;
|
||
|
internal readonly uint timeDateStamp;
|
||
|
internal readonly uint forwarderChain;
|
||
|
internal readonly uint name;
|
||
|
internal readonly uint firstChunk;
|
||
|
}
|
||
|
} // ImportTable class
|
||
|
}
|