Skip to content

Instantly share code, notes, and snippets.

@Slaynash
Created May 12, 2021 14:02
Show Gist options
  • Save Slaynash/a07da4a7e755f8f17882e9686d25bf82 to your computer and use it in GitHub Desktop.
Save Slaynash/a07da4a7e755f8f17882e9686d25bf82 to your computer and use it in GitHub Desktop.
PE (x64) Imports listing example
[StructLayout(LayoutKind.Explicit)]
internal struct ImageDataDirectory
{
[FieldOffset(0)]
public uint virtualAddress;
[FieldOffset(4)]
public uint size;
}
public struct ImageFileHeader
{
public ushort machine;
public ushort numberOfSections;
public uint timeDateStamp;
public uint pointerToSymbolTable;
public uint numberOfSymbols;
public ushort sizeOfOptionalHeader;
public ushort characteristrics;
}
[StructLayout(LayoutKind.Explicit)]
internal struct ImageImportDescriptor
{
[FieldOffset(0)]
public uint OriginalFirstThunk;
[FieldOffset(4)]
public uint TimeDateStamp;
[FieldOffset(8)]
public uint ForwarderChain;
[FieldOffset(12)]
public uint Name;
[FieldOffset(16)]
public uint FirstThunk;
}
[StructLayout(LayoutKind.Explicit)]
internal struct ImageNtHeaders
{
[FieldOffset(0)]
public uint signature;
[FieldOffset(4)]
public ImageFileHeader fileHeader;
[FieldOffset(24)]
public OptionalFileHeader64 optionalHeader64;
//[FieldOffset(24)]
//public OptionalFileHeader32 optionalHeader32;
}
[StructLayout(LayoutKind.Explicit)]
internal struct ImageSectionHeader
{
//[FieldOffset(0)]
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
//public char[8] name;
[FieldOffset(8)]
public int virtualSize;
[FieldOffset(12)]
public int virtualAddress;
[FieldOffset(16)]
public int sizeOfRawData;
[FieldOffset(20)]
public int pointerToRawData;
[FieldOffset(24)]
public int pointerToRelocations;
[FieldOffset(28)]
public int pointerToLinenumbers;
[FieldOffset(32)]
public ushort numberOfRelocations;
[FieldOffset(34)]
public ushort numberOfLinenumbers;
[FieldOffset(36)]
public /* DataSectionFlags */ uint characteristics;
}
[StructLayout(LayoutKind.Explicit)]
internal struct ImageThunkData32
{
[FieldOffset(0)]
public uint forwarderString;
[FieldOffset(0)]
public uint function;
[FieldOffset(0)]
public uint ordinal;
[FieldOffset(0)]
public uint addressOfData;
}
[StructLayout(LayoutKind.Explicit)]
internal struct ImageThunkData64
{
[FieldOffset(0)]
public ulong forwarderString;
[FieldOffset(0)]
public ulong function;
[FieldOffset(0)]
public ulong ordinal;
[FieldOffset(0)]
public ulong addressOfData;
}
[StructLayout(LayoutKind.Explicit)]
internal struct OptionalFileHeader64
{
[FieldOffset(120)]
public ImageDataDirectory importTable;
}
internal static class PEParser
{
internal static unsafe ImageNtHeaders* AnalyseModuleWin(IntPtr moduleBaseAddress)
{
if (*(byte*)(moduleBaseAddress + 0x0) != 0x4D || *(byte*)(moduleBaseAddress + 0x1) != 0x5A)
throw new ArgumentException("The passed module isn't a valid PE file");
int OFFSET_TO_PE_HEADER_OFFSET = 0x3c;
uint offsetToPESig = *(uint*)(moduleBaseAddress + OFFSET_TO_PE_HEADER_OFFSET);
IntPtr pPESig = IntPtr.Add(moduleBaseAddress, (int)offsetToPESig);
if (*(byte*)(pPESig + 0x0) != 0x50 || *(byte*)(pPESig + 0x1) != 0x45 || *(byte*)(pPESig + 0x2) != 0x0 || *(byte*)(pPESig + 0x3) != 0x0)
throw new ArgumentException("The passed module isn't a valid PE file");
return (ImageNtHeaders*)pPESig;
}
}
private unsafe void TestThingy()
{
byte[] data = File.ReadAllBytes(@"C:\UnityInstalls\2018.4.20f1\Editor\Data\PlaybackEngines\windowsstandalonesupport\Variations\win64_nondevelopment_mono\UnityPlayer.dll");
fixed (byte* dataPtr = data)
{
ImageNtHeaders* imageNtHeaders = PEParser.AnalyseModuleWin((IntPtr)dataPtr);
ImageSectionHeader* pSech = ImageFirstSection(imageNtHeaders);
ImageDataDirectory* imageDirectoryEntryImport = &imageNtHeaders->optionalHeader64.importTable;
ImageImportDescriptor* pImportDescriptor = (ImageImportDescriptor*)(dataPtr + Rva2Offset(imageDirectoryEntryImport->virtualAddress, pSech, imageNtHeaders));
for (uint i = 0; i < imageDirectoryEntryImport->size / sizeof(ImageImportDescriptor); ++i)
{
ImageImportDescriptor* pImportDescriptorI = pImportDescriptor + i;
if (pImportDescriptorI->Name != 0)
{
string imagename = CppUtils.CharArrayPtrToString((IntPtr)((ulong)dataPtr + Rva2Offset(pImportDescriptorI->Name, pSech, imageNtHeaders)));
ulong baseFunctionOffset = (ulong)dataPtr + Rva2Offset(pImportDescriptorI->FirstThunk, pSech, imageNtHeaders);
ImageThunkData64* thunkData = (ImageThunkData64*)((ulong)dataPtr + Rva2Offset(pImportDescriptorI->OriginalFirstThunk, pSech, imageNtHeaders));
uint j = 0;
ulong functionoffset = 0;
while (*(IntPtr*)(functionoffset = baseFunctionOffset + (uint)(j * IntPtr.Size)) != IntPtr.Zero)
{
// TODO handle ordinals
string importname = CppUtils.CharArrayPtrToString((IntPtr)((ulong)dataPtr + Rva2Offset((uint)thunkData->addressOfData, pSech, imageNtHeaders) + 0x2));
UnityEngine.Debug.Log(imagename + "::" + importname + " at [UnityPlayer.dll+" + string.Format("{0:X}", functionoffset - (ulong)dataPtr) + "]");
thunkData++;
j++;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment