public void Process() { Console.WriteLine("Loading image '{0}'...", fileName); hModule = Native.LoadLibraryEx( this.fileName, IntPtr.Zero, Native.LoadLibraryFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE ); if (hModule == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to load image!"); } // LOAD_LIBRARY_AS_IMAGE_RESOURCE returns ( HMODULE | 2 ) loadAddr = (long)(hModule.ToInt64() & ~2); Console.WriteLine("Loaded at 0x{0:X2}!", loadAddr); var dosHeader = Native.PtrToStruct <Native.IMAGE_DOS_HEADER>(new IntPtr(loadAddr)); if (dosHeader.e_magic != Native.IMAGE_DOS_SIGNATURE) { throw new InvalidOperationException("Target image has invalid DOS signature!"); } var peHeader = Native.PtrToStruct <Native.IMAGE_NT_HEADERS>(new IntPtr(this.loadAddr + dosHeader.e_lfanew)); if (peHeader.Signature != Native.IMAGE_NT_SIGNATURE) { throw new InvalidOperationException("Target image has invalid PE signature!"); } int sizeOfNtHeaders = 0; switch (peHeader.FileHeader.Machine) { case 0x014c: sizeOfNtHeaders = Marshal.SizeOf(typeof(Native.IMAGE_NT_HEADERS32)); break; case 0x8664: sizeOfNtHeaders = Marshal.SizeOf(typeof(Native.IMAGE_NT_HEADERS64)); break; default: throw new InvalidOperationException("Unexpected architecture in PE header: " + peHeader.FileHeader.Machine); } int numSections = peHeader.FileHeader.NumberOfSections; long baseSectionsAddr = loadAddr + dosHeader.e_lfanew + sizeOfNtHeaders; Console.WriteLine("# of sections: {0}", numSections); var sectionHeaders = new Native.IMAGE_SECTION_HEADER[numSections]; for (int x = 0; x < sectionHeaders.Length; ++x) { long baseAddr = baseSectionsAddr + (x * Marshal.SizeOf(sectionHeaders[x])); var sectionHdr = Native.PtrToStruct <Native.IMAGE_SECTION_HEADER>(new IntPtr(baseAddr)); var searchFlags = Native.IMAGE_SECTION_HEADER.CharacteristicFlags.IMAGE_SCN_MEM_READ | Native.IMAGE_SECTION_HEADER.CharacteristicFlags.IMAGE_SCN_CNT_INITIALIZED_DATA; var excludeFlags = Native.IMAGE_SECTION_HEADER.CharacteristicFlags.IMAGE_SCN_MEM_WRITE | Native.IMAGE_SECTION_HEADER.CharacteristicFlags.IMAGE_SCN_MEM_DISCARDABLE; if ((sectionHdr.Characteristics & searchFlags) != searchFlags) { Console.WriteLine("\nSection '{0}' skipped: not an initialized read section.", sectionHdr.Name); continue; } if ((sectionHdr.Characteristics & excludeFlags) != 0) { Console.WriteLine("\nSection '{0}' skipped: not a non-discardable readonly section.", sectionHdr.Name); continue; } ScanSection(sectionHdr); } if (deferredProtos.Count > 0) { Console.WriteLine("WARNING: Some protobufs were left unresolved: "); foreach (var proto in deferredProtos) { DoParseFile(proto); } } FinalPassWriteFiles(); }
unsafe void ScanSection(Native.IMAGE_SECTION_HEADER sectionHdr) { long sectionDataAddr = loadAddr + sectionHdr.PointerToRawData; Console.WriteLine("\nScanning section '{0}' at 0x{1:X2}...\n", sectionHdr.Name, sectionDataAddr); byte *dataPtr = (byte *)(sectionDataAddr); byte *endPtr = (byte *)(dataPtr + sectionHdr.SizeOfRawData); while (dataPtr < endPtr) { if (*dataPtr == 0x0A) { byte *originalPtr = dataPtr; int nullskiplevel = 0; rescan: int t = nullskiplevel; dataPtr = originalPtr; byte[] data = null; using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) { for (; *(short *)dataPtr != 0 || t-- > 0; dataPtr++) { bw.Write(*dataPtr); } bw.Write((byte)0); data = ms.ToArray(); } dataPtr++; if (data.Length < 2) { dataPtr = originalPtr + 1; continue; } byte strLen = data[1]; if (data.Length - 2 < strLen) { dataPtr = originalPtr + 1; continue; } string protoName = Encoding.ASCII.GetString(data, 2, strLen); if (!protoName.EndsWith(".proto")) { dataPtr = originalPtr + 1; continue; } if (!HandleProto(protoName, data)) { nullskiplevel++; goto rescan; } } else { dataPtr++; } } }