Example #1
0
        public static PeHeaders FromUnmanagedPtr(IntPtr memoryPtr)
        {
            var headers = new PeHeaders();

            headers.Load(memoryPtr, 0);
            return(headers);
        }
Example #2
0
        /// <summary>
        /// Retrieve PDB information from Assembly, by reading it's PE header.
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static AssemblyDebugInfo ReadAssemblyDebugInfo(Assembly assembly)
        {
            // The trick is that GetHINSTANCE returns the real HINSTANCE handler,
            // which in Win32 API world is module's base address in memory
            // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
            //
            // Which means for a loaded Assembly we can get an unmanaged pointer
            // right to the start of the PE (Portable Executable) header. Every
            // binary on Windows - DLL or EXE - following the PE format.
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx

            var modulePtr = Marshal.GetHINSTANCE(assembly.ManifestModule);

            // Parses PE headers structure from the module base address pointer

            var peHdrs = PeHeaders.FromUnmanagedPtr(modulePtr);

            // Depending on whether this is 32-bit or 64-bit module, the offsets are
            // slightly different

            uint debugOffset, debugSize;

            if (peHdrs.Is32BitOptionalHeader && peHdrs.OptionalHeader32.NumberOfRvaAndSizes >= 7)
            {
                debugOffset = peHdrs.OptionalHeader32.Debug.VirtualAddress;
                debugSize   = peHdrs.OptionalHeader32.Debug.Size;
            }
            else if (!peHdrs.Is32BitOptionalHeader && peHdrs.OptionalHeader64.NumberOfRvaAndSizes >= 7)
            {
                debugOffset = peHdrs.OptionalHeader64.Debug.VirtualAddress;
                debugSize   = peHdrs.OptionalHeader64.Debug.Size;
            }
            else
            {
                // In case DEBUG information is not in the module

                return(null);
            }

            // Navigating to the DEBUG_DIRECTORY portion, which holds the debug information

            var debugPtr       = new IntPtr(modulePtr.ToInt64() + debugOffset);
            var debugDirectory = (IMAGE_DEBUG_DIRECTORY)Marshal.PtrToStructure(debugPtr, typeof(IMAGE_DEBUG_DIRECTORY));

            // Check that DEBUG information is there and that it is in CODEVIEW/RSDS format,
            // which is what's used by .NET framework

            if (debugDirectory.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
            {
                return(null);
            }
            var rsdsPtr = new IntPtr(modulePtr.ToInt64() + debugDirectory.AddressOfRawData);

            if (Marshal.ReadInt32(rsdsPtr) != RSDS_SIGNATURE)
            {
                return(null);
            }

            // Read the RSDS info, which includes the PDB GUID and its Age, together with
            // PDB filepath

            var rsdsInfo = (RSDS_DEBUG_FORMAT)Marshal.PtrToStructure(rsdsPtr, typeof(RSDS_DEBUG_FORMAT));
            var pathPtr  = new IntPtr(rsdsPtr.ToInt64() + Marshal.SizeOf(typeof(RSDS_DEBUG_FORMAT)));
            var path     = Marshal.PtrToStringAnsi(pathPtr);

            return(new AssemblyDebugInfo()
            {
                Guid = new Guid(rsdsInfo.Guid),
                Age = rsdsInfo.Age,
                Path = path
            });
        }