605 lines
24 KiB
C#
605 lines
24 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
|
|
// haryadi
|
|
// #define SINGULARITY_ASMP
|
|
|
|
namespace Microsoft.Singularity.Loader
|
|
{
|
|
using Microsoft.Singularity;
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.Memory;
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
|
|
using PageType = System.GCs.PageType;
|
|
|
|
[CLSCompliant(false)]
|
|
internal class PEImage
|
|
{
|
|
// PE Signature
|
|
internal readonly uint signature;
|
|
|
|
// IMAGE_FILE_HEADER
|
|
internal readonly ushort machine;
|
|
internal readonly ushort numberOfSections;
|
|
internal readonly uint timeDateStamp;
|
|
internal readonly ushort sizeOfOptionalHeader;
|
|
internal readonly ushort characteristics;
|
|
|
|
// IMAGE_OPTIONAL_HEADER32
|
|
internal readonly ushort magic;
|
|
internal readonly uint addressOfEntryPoint;
|
|
internal readonly uint imageBase;
|
|
internal readonly uint sectionAlignment;
|
|
internal readonly uint fileAlignment;
|
|
private readonly uint sizeOfImage; // use loadedSize (this is rnd'd)
|
|
internal readonly uint sizeOfHeaders;
|
|
internal readonly uint checkSum;
|
|
internal readonly ushort dllCharacteristics;
|
|
internal readonly uint loaderFlags;
|
|
internal readonly uint numberOfRvaAndSizes;
|
|
|
|
// IMAGE_DATA_DIRECTORY and SECTION_HEADERs
|
|
internal readonly DirectoryEntry[] directory;
|
|
internal readonly SectionHeader[] sections;
|
|
internal readonly uint loadedSize;
|
|
|
|
internal const ushort IMAGE_FILE_32BIT_MACHINE = 0x0100; // 32 bit machine.
|
|
internal const ushort IMAGE_FILE_DLL = 0x2000; // File is a DLL.
|
|
|
|
internal const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
|
|
internal const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
|
|
internal const ushort IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x010b;
|
|
|
|
enum Machine : ushort {
|
|
UNKNOWN = 0,
|
|
I386 = 0x014c, // Intel 386.
|
|
R3000 = 0x0162, // MIPS little-endian, = 0x160 big-endian
|
|
R4000 = 0x0166, // MIPS little-endian
|
|
R10000 = 0x0168, // MIPS little-endian
|
|
WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2
|
|
ALPHA = 0x0184, // Alpha_AXP
|
|
SH3 = 0x01a2, // SH3 little-endian
|
|
SH3DSP = 0x01a3,
|
|
SH3E = 0x01a4, // SH3E little-endian
|
|
SH4 = 0x01a6, // SH4 little-endian
|
|
SH5 = 0x01a8, // SH5
|
|
ARM = 0x01c0, // ARM Little-Endian
|
|
THUMB = 0x01c2,
|
|
AM33 = 0x01d3,
|
|
POWERPC = 0x01F0, // IBM PowerPC Little-Endian
|
|
POWERPCFP = 0x01f1,
|
|
IA64 = 0x0200, // Intel 64
|
|
MIPS16 = 0x0266, // MIPS
|
|
ALPHA64 = 0x0284, // ALPHA64
|
|
MIPSFPU = 0x0366, // MIPS
|
|
MIPSFPU16 = 0x0466, // MIPS
|
|
TRICORE = 0x0520, // Infineon
|
|
EBC = 0x0EBC, // EFI Byte Code
|
|
X64 = 0x8664, // AMD64, etc.
|
|
M32R = 0x9041, // M32R little-endian
|
|
CEE = 0xC0EE,
|
|
};
|
|
|
|
// Directory Entries
|
|
|
|
enum DirEntry {
|
|
Export = 0, // Export Directory
|
|
Import = 1, // Import Directory
|
|
Security = 4, // Security Directory
|
|
BaseReloc = 5, // Base Relocation Table
|
|
Debug = 6, // Debug Directory
|
|
Copyright = 7, // Description String
|
|
};
|
|
|
|
// Corresponds to the WinNT IMAGE_NT_HEADERS data structure
|
|
internal static PEImage kernel = null;
|
|
internal static ExportTable kernelExports = null;
|
|
internal static PEImage mpAbi = null;
|
|
internal static ExportTable mpAbiExports = null;
|
|
|
|
internal PEImage(IoMemory mem)
|
|
{
|
|
Kernel.Waypoint(601);
|
|
if (mem.Length < 64) {
|
|
throw new BadImageFormatException("Invalid MZ header");
|
|
}
|
|
|
|
magic = mem.Read16Unchecked(0);
|
|
Kernel.Waypoint(602);
|
|
|
|
int offset = (int)mem.Read32Unchecked(60);
|
|
|
|
if (magic != IMAGE_DOS_SIGNATURE || offset < 64 || offset + 120 > mem.Length) {
|
|
throw new BadImageFormatException("Invalid MZ header");
|
|
}
|
|
|
|
signature = mem.Read32Unchecked(offset + 0);
|
|
machine = mem.Read16Unchecked(offset + 4);
|
|
numberOfSections = mem.Read16Unchecked(offset + 6);
|
|
timeDateStamp = mem.Read16Unchecked(offset + 8);
|
|
sizeOfOptionalHeader = mem.Read16Unchecked(offset + 20);
|
|
characteristics = mem.Read16Unchecked(offset + 22);
|
|
magic = mem.Read16Unchecked(offset + 24);
|
|
addressOfEntryPoint = mem.Read32Unchecked(offset + 40);
|
|
imageBase = mem.Read32Unchecked(offset + 52);
|
|
sectionAlignment = mem.Read32Unchecked(offset + 56);
|
|
fileAlignment = mem.Read32Unchecked(offset + 60);
|
|
sizeOfImage = mem.Read32Unchecked(offset + 80);
|
|
sizeOfHeaders = mem.Read32Unchecked(offset + 84);
|
|
checkSum = mem.Read32Unchecked(offset + 88);
|
|
dllCharacteristics = mem.Read16Unchecked(offset + 94);
|
|
loaderFlags = mem.Read32Unchecked(offset + 112);
|
|
numberOfRvaAndSizes = mem.Read32Unchecked(offset + 116);
|
|
offset += 120;
|
|
|
|
Kernel.Waypoint(603);
|
|
// Verify that we have a valid NT header
|
|
|
|
if (signature != IMAGE_NT_SIGNATURE ||
|
|
sizeOfOptionalHeader != 224 ||
|
|
magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
|
|
numberOfRvaAndSizes != 16) {
|
|
|
|
throw new BadImageFormatException("Invalid PE header");
|
|
}
|
|
|
|
Kernel.Waypoint(693);
|
|
|
|
directory = new DirectoryEntry[numberOfRvaAndSizes];
|
|
for (uint i = 0; i < numberOfRvaAndSizes; i++) {
|
|
directory[i] = new DirectoryEntry(mem, ref offset);
|
|
}
|
|
|
|
sections = new SectionHeader[numberOfSections];
|
|
for (uint i = 0; i < numberOfSections; i++) {
|
|
sections[i] = new SectionHeader(mem, ref offset);
|
|
|
|
}
|
|
|
|
Kernel.Waypoint(694);
|
|
|
|
// Calc the sizes of the loaded regions according to starting virtual address
|
|
loadedSize = sizeOfImage;
|
|
for (uint i = 0; i < numberOfSections; i++) {
|
|
if (!sections[i].IsDiscardable) {
|
|
uint addr = sections[i].virtualAddress;
|
|
uint size = sections[i].virtualSize;
|
|
uint last = addr + size;
|
|
|
|
if (loadedSize < last) {
|
|
loadedSize = last;
|
|
}
|
|
}
|
|
}
|
|
|
|
Kernel.Waypoint(604);
|
|
}
|
|
|
|
internal ExportTable GetExportTable(IoMemory mem)
|
|
{
|
|
if (directory[(int)DirEntry.Export].virtualAddress == 0) {
|
|
return null;
|
|
}
|
|
return new ExportTable(mem, mem.VirtualAddress,
|
|
directory[(int)DirEntry.Export]);
|
|
}
|
|
|
|
internal ImportTable GetImportTable(IoMemory mem)
|
|
{
|
|
if (directory[(int)DirEntry.Import].virtualAddress == 0) {
|
|
return null;
|
|
}
|
|
return new ImportTable(mem, directory[(int)DirEntry.Import]);
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
internal uint GetRelocationsRaw()
|
|
{
|
|
uint relocationAddr = directory[(int)DirEntry.BaseReloc].virtualAddress;
|
|
|
|
for (uint i = 0; i < numberOfSections; i++) {
|
|
if (sections[i].virtualAddress == relocationAddr) {
|
|
return sections[i].pointerToRawData;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////// Static Methods.
|
|
//
|
|
public static void Initialize()
|
|
{
|
|
IoMemory pages = IoMemory.MapPhysicalMemory(BootInfo.KERNEL_BASE, 4096, true, false);
|
|
kernel = new PEImage(pages);
|
|
pages = IoMemory.MapPhysicalMemory(BootInfo.KERNEL_BASE, kernel.loadedSize, true, false);
|
|
kernelExports = kernel.GetExportTable(pages);
|
|
|
|
DebugStub.LoadedBinary(pages.VirtualAddress,
|
|
kernel.sizeOfImage,
|
|
"kernel.x86",
|
|
kernel.checkSum,
|
|
kernel.timeDateStamp,
|
|
false);
|
|
|
|
// This breakpoint is triggered by a "-d" to windbg.
|
|
if (DebugStub.PollForBreak()) {
|
|
DebugStub.Break();
|
|
}
|
|
|
|
#if GENERATE_ABI_SHIM
|
|
DebugStub.WriteLine(" InitializeMpAbi() *****");
|
|
InitializeMpAbi();
|
|
#endif
|
|
}
|
|
|
|
// haryadi
|
|
public static void InitializeMpAbi()
|
|
{
|
|
// Note: When mapping the abi stub (MpSyscalls.x86), we must
|
|
// map it with writable flag! as we want to resolve the stub's
|
|
// imports
|
|
IoMemory mpPages = IoMemory.MapPhysicalMemory(BootInfo.MP_ABI_BASE, 4096, true, true);
|
|
mpAbi = new PEImage(mpPages);
|
|
mpPages = IoMemory.MapPhysicalMemory(BootInfo.MP_ABI_BASE, mpAbi.loadedSize, true, true);
|
|
mpAbiExports = mpAbi.GetExportTable(mpPages);
|
|
|
|
// Resolve imports in abi shim dll with the kernel exports
|
|
// which are the real stub that will do IPI stuffs
|
|
ImportTable mpAbiIt = mpAbi.GetImportTable(mpPages);
|
|
|
|
DebugStub.WriteLine("HSG: ** Resolving Imports");
|
|
mpAbiIt.ResolveImports(kernelExports);
|
|
}
|
|
|
|
public static void Finalize()
|
|
{
|
|
// Uncomment the following line to notify debugger when we shutdown.
|
|
// DebugStub.UnloadedBinary(UIntPtr.MaxValue, false);
|
|
}
|
|
|
|
internal static PEImage KernelImage
|
|
{
|
|
[NoHeapAllocation]
|
|
get { return kernel; }
|
|
}
|
|
|
|
public static PEImage Load(Process process, IoMemory rawMemory,
|
|
out IoMemory loadedMemory, bool isForMp)
|
|
{
|
|
return Load(process, rawMemory, out loadedMemory,
|
|
isForMp, process == Process.kernelProcess);
|
|
}
|
|
|
|
public static PEImage Load(Process process, IoMemory rawMemory,
|
|
out IoMemory loadedMemory, bool isForMp,
|
|
bool inKernelSpace)
|
|
{
|
|
UIntPtr entryPoint = UIntPtr.Zero;
|
|
loadedMemory = null;
|
|
|
|
if (null == rawMemory || 0 == rawMemory.Length) {
|
|
DebugStub.WriteLine("No PXE image to load!");
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Allocate memory and copy the PXE image from memory to memory
|
|
//
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, " PXE at {0:x8}, Length ={1:x8}",
|
|
(uint)rawMemory.VirtualAddress,
|
|
rawMemory.Length);
|
|
#endif
|
|
|
|
Kernel.Waypoint(580);
|
|
Tracing.Log(Tracing.Debug, "Loading:");
|
|
PEImage image = new PEImage(rawMemory);
|
|
image.DumpLimitedToStream();
|
|
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, " Loaded Size={0:x8}", image.loadedSize);
|
|
#endif
|
|
|
|
Kernel.Waypoint(581);
|
|
if (0 == image.loadedSize) {
|
|
throw new BadImageFormatException("Invalid PE, no content");
|
|
}
|
|
|
|
try {
|
|
if (inKernelSpace) {
|
|
loadedMemory = IoMemory.AllocateFixed(
|
|
(UIntPtr)image.loadedSize,
|
|
process, PageType.System);
|
|
} else {
|
|
// Situate the process image in the user range
|
|
loadedMemory = IoMemory.AllocateUserFixed(
|
|
(UIntPtr)image.loadedSize,
|
|
process, PageType.System);
|
|
}
|
|
|
|
Kernel.Waypoint(582);
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, " loaded at {0:x8}, Length ={1:x8}",
|
|
(uint)loadedMemory.VirtualAddress,
|
|
loadedMemory.Length);
|
|
#endif
|
|
// Copy the header so the debugger can find it.
|
|
IoMemory.Copy(rawMemory, 0, loadedMemory, 0, (int)image.sizeOfHeaders);
|
|
|
|
#if verbose
|
|
image.DumpLimitedToStream();
|
|
#endif
|
|
Kernel.Waypoint(583);
|
|
// load sections into memory where they belong.
|
|
for (int i = 0; i < image.numberOfSections; i++)
|
|
{
|
|
if (image.sections[i].IsDiscardable ||
|
|
image.sections[i].sizeOfRawData == 0) {
|
|
continue;
|
|
}
|
|
|
|
int targetOffset = (int)image.sections[i].virtualAddress;
|
|
int sourceOffset = (int)image.sections[i].pointerToRawData;
|
|
uint rawSize = Math.Min(image.sections[i].sizeOfRawData,
|
|
image.sections[i].virtualSize);
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, "section[{0}] source={1:x8}..{2:x8} target={3:x8}..{4:x8}",
|
|
i,
|
|
sourceOffset, sourceOffset + rawSize,
|
|
targetOffset, targetOffset + rawSize);
|
|
#endif
|
|
IoMemory.Copy(rawMemory, sourceOffset, loadedMemory, targetOffset, (int)rawSize);
|
|
}
|
|
Kernel.Waypoint(584);
|
|
|
|
//
|
|
// Handle Relocations
|
|
//
|
|
int relocationTableOffset = (int)image.GetRelocationsRaw();
|
|
uint diff = (uint)loadedMemory.VirtualAddress - (uint) image.imageBase;
|
|
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, " Base loaded={0:x8}, relocated ={1:x8} diff={2:x8}",
|
|
image.imageBase, (uint)loadedMemory.VirtualAddress, diff);
|
|
|
|
Tracing.Log(Tracing.Debug, " relocationTableOffset ={0:x8} ", relocationTableOffset);
|
|
#endif
|
|
|
|
Relocations.FixupBlocks(rawMemory, (int)relocationTableOffset,
|
|
loadedMemory, diff);
|
|
// We should probably zero the relocation table.
|
|
|
|
Kernel.Waypoint(585);
|
|
|
|
//
|
|
// Resolve Imports
|
|
//
|
|
ImportTable it = image.GetImportTable(loadedMemory);
|
|
Kernel.Waypoint(586);
|
|
|
|
#if !PAGING
|
|
|
|
#if GENERATE_ABI_SHIM
|
|
if (it != null) {
|
|
#endif
|
|
//it.DumpIAT("Import directory");
|
|
|
|
// haryadi -- if this is loading for remote processor
|
|
// then solve the imports with abi stub
|
|
if (isForMp) {
|
|
it.ResolveImports(mpAbiExports);
|
|
}
|
|
else {
|
|
it.ResolveImports(kernelExports);
|
|
}
|
|
|
|
//DumpIAT(loadedMemory, "Import Address Table",
|
|
// ref image.directory[12]);
|
|
#if GENERATE_ABI_SHIM
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
if (it != null) {
|
|
// Ring-3 protection domains come with a set of
|
|
// stubs that accomplish the ring3-to-ring0 ABI
|
|
// transitions. Use these when called for.
|
|
ExportTable abiStubs = process.Domain.ABIStubs;
|
|
|
|
if (abiStubs != null) {
|
|
it.ResolveImports(abiStubs);
|
|
} else {
|
|
it.ResolveImports(kernelExports);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Kernel.Waypoint(587);
|
|
|
|
//
|
|
// Dump Exports
|
|
//
|
|
ExportTable et = image.GetExportTable(loadedMemory);
|
|
if (et != null) {
|
|
et.Dump();
|
|
}
|
|
|
|
Kernel.Waypoint(588);
|
|
|
|
entryPoint = (UIntPtr)loadedMemory.VirtualAddress + image.addressOfEntryPoint;
|
|
|
|
Tracing.Log(Tracing.Debug, " Loaded: {0:x8}..{1:x8}, Entry: {2:x8}",
|
|
(ulong)loadedMemory.VirtualAddress,
|
|
(ulong)(loadedMemory.VirtualAddress + loadedMemory.Length),
|
|
(ulong)(entryPoint));
|
|
}
|
|
finally {
|
|
if (entryPoint == UIntPtr.Zero && loadedMemory != null) {
|
|
// Need to dispose of target Range.
|
|
loadedMemory = null;
|
|
}
|
|
}
|
|
return image;
|
|
}
|
|
|
|
// haryadi -- HelloMpLoad skips several procedures to be able to
|
|
// load HelloMp.x86 properly
|
|
public static PEImage HelloMpLoad(Process process, IoMemory rawMemory,
|
|
out IoMemory loadedMemory)
|
|
{
|
|
UIntPtr entryPoint = UIntPtr.Zero;
|
|
loadedMemory = null;
|
|
|
|
if (null == rawMemory || 0 == rawMemory.Length) {
|
|
DebugStub.WriteLine("No PXE image to load!");
|
|
return null;
|
|
}
|
|
|
|
Kernel.Waypoint(580);
|
|
Tracing.Log(Tracing.Debug, "Loading:");
|
|
PEImage image = new PEImage(rawMemory);
|
|
image.DumpLimitedToStream();
|
|
|
|
Kernel.Waypoint(581);
|
|
if (0 == image.loadedSize) {
|
|
throw new BadImageFormatException("Invalid PE, no content");
|
|
}
|
|
|
|
try {
|
|
// The loadedImage is current loaded to physical memory
|
|
// directly
|
|
loadedMemory = IoMemory.AllocatePhysical
|
|
((UIntPtr)image.loadedSize);
|
|
|
|
Kernel.Waypoint(582);
|
|
|
|
// Copy the header so the debugger can find it.
|
|
IoMemory.Copy(rawMemory, 0, loadedMemory, 0,
|
|
(int)image.sizeOfHeaders);
|
|
Kernel.Waypoint(583);
|
|
// load sections into memory where they belong.
|
|
for (int i = 0; i < image.numberOfSections; i++)
|
|
{
|
|
if (image.sections[i].IsDiscardable ||
|
|
image.sections[i].sizeOfRawData == 0) {
|
|
continue;
|
|
}
|
|
int targetOffset = (int)image.sections[i].virtualAddress;
|
|
int sourceOffset = (int)image.sections[i].pointerToRawData;
|
|
uint rawSize = Math.Min(image.sections[i].sizeOfRawData,
|
|
image.sections[i].virtualSize);
|
|
IoMemory.Copy(rawMemory, sourceOffset, loadedMemory,
|
|
targetOffset, (int)rawSize);
|
|
}
|
|
Kernel.Waypoint(584);
|
|
|
|
int relocationTableOffset = (int)image.GetRelocationsRaw();
|
|
uint diff = (uint)loadedMemory.VirtualAddress -
|
|
(uint) image.imageBase;
|
|
entryPoint = (UIntPtr)loadedMemory.VirtualAddress +
|
|
image.addressOfEntryPoint;
|
|
}
|
|
finally {
|
|
if (entryPoint == UIntPtr.Zero && loadedMemory != null) {
|
|
// Need to dispose of target Range.
|
|
loadedMemory = null;
|
|
}
|
|
}
|
|
return image;
|
|
}
|
|
|
|
|
|
[NoHeapAllocation]
|
|
public UIntPtr GetEntryPoint(IoMemory loadedImage)
|
|
{
|
|
return loadedImage.VirtualAddress + addressOfEntryPoint;
|
|
}
|
|
|
|
[AccessedByRuntime("output to header : defined in PEImage.cpp")]
|
|
[OutsideGCDomain]
|
|
[StackBound(64)]
|
|
[NoInline]
|
|
[NoStackLinkCheck]
|
|
[NoStackOverflowCheck]
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
[NoHeapAllocation]
|
|
internal static extern int HalCallEntryPoint(UIntPtr entry, int threadIndex,
|
|
bool runAtRing3);
|
|
|
|
[NoHeapAllocation]
|
|
internal static int CallEntryPoint(UIntPtr entry, int threadIndex,
|
|
bool runAtRing3)
|
|
{
|
|
return HalCallEntryPoint(entry, threadIndex, runAtRing3);
|
|
}
|
|
|
|
//
|
|
// Output Routines
|
|
//
|
|
[Conditional("DEBUG")]
|
|
internal void DumpLimitedToStream()
|
|
{
|
|
Tracing.Log(Tracing.Debug, " Entry point: {0:x8}", addressOfEntryPoint);
|
|
Tracing.Log(Tracing.Debug, " Image base: {0:x8}", imageBase);
|
|
#if verbose
|
|
Tracing.Log(Tracing.Debug, " Section alignment: {0:x8}", sectionAlignment);
|
|
Tracing.Log(Tracing.Debug, " File alignment: {0:x8}", fileAlignment);
|
|
Tracing.Log(Tracing.Debug, " Directories: {0:x8}", numberOfRvaAndSizes);
|
|
#endif
|
|
Tracing.Log(Tracing.Debug, " Loaded Size: {0:x8}", loadedSize);
|
|
if (directory[0].virtualAddress != 0) {
|
|
directory[0].DumpToStream("Export directory ");
|
|
}
|
|
if (directory[1].virtualAddress != 0) {
|
|
directory[1].DumpToStream("Import directory ");
|
|
}
|
|
if (directory[5].virtualAddress != 0) {
|
|
directory[5].DumpToStream("Relocation Table ");
|
|
}
|
|
if (directory[6].virtualAddress != 0) {
|
|
directory[6].DumpToStream("Debug Directory ");
|
|
}
|
|
if (directory[11].virtualAddress != 0) {
|
|
directory[11].DumpToStream("Bound Import Table ");
|
|
}
|
|
if (directory[12].virtualAddress != 0) {
|
|
directory[12].DumpToStream("Import Address Table ");
|
|
}
|
|
|
|
for (uint i = 0; i < numberOfSections; i++) {
|
|
sections[i].DumpToStream();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|