2008-11-17 18:29:00 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
2008-03-05 09:52:00 -05:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (entry.size == 0) {
|
2008-03-05 09:52:00 -05:00
|
|
|
DebugStub.WriteLine("// No import table.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if verbose
|
|
|
|
[Conditional("DEBUG")]
|
|
|
|
public void DumpIAT(String title)
|
|
|
|
{
|
|
|
|
Tracing.Log(Tracing.Debug, "// {0}", title);
|
2008-11-17 18:29:00 -05:00
|
|
|
if (entry.size == 0) {
|
2008-03-05 09:52:00 -05:00
|
|
|
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.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
for (;;) {
|
2008-03-05 09:52:00 -05:00
|
|
|
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;
|
2008-11-17 18:29:00 -05:00
|
|
|
for (;;) {
|
2008-03-05 09:52:00 -05:00
|
|
|
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)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
if (entry.size == 0) {
|
2008-03-05 09:52:00 -05:00
|
|
|
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);
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
#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;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
#if PTR_SIZE_64
|
|
|
|
|
|
|
|
//
|
|
|
|
// AIFIX: Add hint logic.
|
|
|
|
//
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
ulong ImportEntry = (ulong) mem.Read64((int) offsetIAT);
|
|
|
|
|
|
|
|
if (ImportEntry == 0) {
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ImportEntry >> 63) != 0) {
|
|
|
|
|
|
|
|
throw new BadImageFormatException("Import Ordinal encountered");
|
|
|
|
}
|
|
|
|
|
|
|
|
name = mem.ReadAsciiZeroString(((int) (ImportEntry & 0x7FFFFFFF)) + 2);
|
|
|
|
|
|
|
|
UIntPtr Address;
|
|
|
|
|
|
|
|
Address = exports.Resolve(hint, name);
|
|
|
|
|
|
|
|
if (Address == 0) {
|
|
|
|
|
|
|
|
throw new BadImageFormatException("Import not found");
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.Write64((int) offsetIAT, (ulong) Address);
|
|
|
|
|
|
|
|
offsetIAT += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
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);
|
2008-11-17 18:29:00 -05:00
|
|
|
if (0 != addr) {
|
2008-03-05 09:52:00 -05:00
|
|
|
//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);
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
else {
|
2008-03-05 09:52:00 -05:00
|
|
|
Tracing.Log(Tracing.Debug, " Import not found: {0}", name);
|
2008-11-17 18:29:00 -05:00
|
|
|
throw new BadImageFormatException("Import not found");
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// increment "array indices"
|
|
|
|
offsetIAT += 4;
|
|
|
|
offsetHintTable +=4;
|
|
|
|
}
|
|
|
|
//Tracing.Log(Tracing.Debug, "");
|
2008-11-17 18:29:00 -05:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
//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
|
|
|
|
}
|