From 382a49c17eb7bc58fc26f0a895f077802787be61 Mon Sep 17 00:00:00 2001 From: 1987kostya Date: Fri, 29 Jan 2021 15:55:56 +0600 Subject: [PATCH] Add icon dumping --- CTFAK/CTFAK.csproj | 1 + CTFAK/MMFParser/Translation/PAME2MFA.cs | 10 +- CTFAK/Program.cs | 9 +- CTFAK/Settings.cs | 1 + CTFAK/Utils/IconLoader.cs | 260 ++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 CTFAK/Utils/IconLoader.cs diff --git a/CTFAK/CTFAK.csproj b/CTFAK/CTFAK.csproj index 6e765a8..8c120ac 100644 --- a/CTFAK/CTFAK.csproj +++ b/CTFAK/CTFAK.csproj @@ -275,6 +275,7 @@ + diff --git a/CTFAK/MMFParser/Translation/PAME2MFA.cs b/CTFAK/MMFParser/Translation/PAME2MFA.cs index f4fcf0e..798791e 100644 --- a/CTFAK/MMFParser/Translation/PAME2MFA.cs +++ b/CTFAK/MMFParser/Translation/PAME2MFA.cs @@ -79,8 +79,8 @@ namespace CTFAK.MMFParser.Translation displaySettings["ResizeDisplay"] = flags["MDI"]; displaySettings["FullscreenAtStart"] = flags["FullscreenAtStart"]; displaySettings["AllowFullscreen"] = flags["FullscreenSwitch"]; - displaySettings["Heading"] = !flags["NoHeading"]; - displaySettings["HeadingWhenMaximized"] = true; + // displaySettings["Heading"] = !flags["NoHeading"]; + // displaySettings["HeadingWhenMaximized"] = true; displaySettings["MenuBar"] = flags["MenuBar"]; displaySettings["MenuOnBoot"] = !flags["MenuHidden"]; displaySettings["NoMinimize"] = newFlags["NoMinimizeBox"]; @@ -361,13 +361,13 @@ namespace CTFAK.MMFParser.Translation newItem.Flags = item.Flags; if (item.InkEffectValue == 0&&Settings.Build<=284) { - newItem.Chunks.GetOrCreateChunk().Blend = 255; + // newItem.Chunks.GetOrCreateChunk().Blend = 255; } else { - newItem.Chunks.GetOrCreateChunk().Blend = item.InkEffectValue; + // newItem.Chunks.GetOrCreateChunk().Blend = item.InkEffectValue; } - newItem.Chunks.GetOrCreateChunk().RGBCoeff = Color.White; + // newItem.Chunks.GetOrCreateChunk().RGBCoeff = Color.White; newItem.IconHandle = 12; diff --git a/CTFAK/Program.cs b/CTFAK/Program.cs index a66b7a3..de51495 100644 --- a/CTFAK/Program.cs +++ b/CTFAK/Program.cs @@ -110,7 +110,13 @@ namespace CTFAK Settings.Verbose = verbose; if (path.ToLower().EndsWith(".exe")) { - + var icon = new IconLoader(path); + foreach (var ico in icon.GetAllIcons()) + { + ico.Save(new FileStream($"{Settings.IconPath}\\{ico.Width}x{ico.Height}.png",FileMode.CreateNew)); + } + + var exeReader = new ByteReader(path, FileMode.Open); var currentExe = new Exe(); Exe.Instance = currentExe; @@ -139,6 +145,7 @@ namespace CTFAK Directory.CreateDirectory($"{Settings.ExtensionPath}"); Directory.CreateDirectory($"{Settings.DLLPath}"); Directory.CreateDirectory($"{Settings.EXEPath}"); + Directory.CreateDirectory($"{Settings.IconPath}"); Directory.CreateDirectory($"{PluginAPI.PluginAPI.PluginPath}"); } public static void InitNativeLibrary() diff --git a/CTFAK/Settings.cs b/CTFAK/Settings.cs index 8704f22..a2cc769 100644 --- a/CTFAK/Settings.cs +++ b/CTFAK/Settings.cs @@ -27,6 +27,7 @@ namespace CTFAK public static string ExtensionPath=>$"{DumpPath}\\PackData\\Extensions"; public static string DLLPath=>$"{DumpPath}\\PackData\\DLLs"; public static string EXEPath=>$"{DumpPath}\\PackData\\Exes"; + public static string IconPath=>$"{DumpPath}\\Icons"; public static string AppName; public static string Copyright; diff --git a/CTFAK/Utils/IconLoader.cs b/CTFAK/Utils/IconLoader.cs new file mode 100644 index 0000000..ec421e9 --- /dev/null +++ b/CTFAK/Utils/IconLoader.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; + +namespace CTFAK.Utils +{ + public class IconLoader + { + private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + + + private readonly static IntPtr RT_ICON = (IntPtr)3; + private readonly static IntPtr RT_GROUP_ICON = (IntPtr)14; + + private const int MAX_PATH = 260; + + private byte[][] iconData = null; // Binary data of each icon. + + public string FileName + { + get; + private set; + } + + + public int Count + { + get { return iconData.Length; } + } + + public IconLoader(string fileName) + { + Initialize(fileName); + } + + public Icon GetIcon(int index) + { + if (index < 0 || Count <= index) + throw new ArgumentOutOfRangeException("index"); + + // Create an Icon from the .ico file in memory. + + using (var ms = new MemoryStream(iconData[index])) + { + return new Icon(ms); + } + } + + + public Icon[] GetAllIcons() + { + var icons = new List(); + for (int i = 0; i < Count; ++i) + icons.Add(GetIcon(i)); + + return icons.ToArray(); + } + + public void Save(int index, Stream outputStream) + { + if (index < 0 || Count <= index) + throw new ArgumentOutOfRangeException("index"); + + if (outputStream == null) + throw new ArgumentNullException("outputStream"); + + var data = iconData[index]; + outputStream.Write(data, 0, data.Length); + } + + private void Initialize(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + + IntPtr hModule = IntPtr.Zero; + try + { + hModule = NativeMethods.LoadLibraryEx(fileName, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + if (hModule == IntPtr.Zero) + throw new Win32Exception(); + + FileName = GetFileName(hModule); + + + + var tmpData = new List(); + + ENUMRESNAMEPROC callback = (h, t, name, l) => + { + + + var dir = GetDataFromResource(hModule, RT_GROUP_ICON, name); + + + int count = BitConverter.ToUInt16(dir, 4); // GRPICONDIR.idCount + int len = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count + for (int i = 0; i < count; ++i) + len += BitConverter.ToInt32(dir, 6 + 14 * i + 8); // GRPICONDIRENTRY.dwBytesInRes + + using (var dst = new BinaryWriter(new MemoryStream(len))) + { + // Copy GRPICONDIR to ICONDIR. + + dst.Write(dir, 0, 6); + + int picOffset = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count + + for (int i = 0; i < count; ++i) + { + // Load the picture. + + ushort id = BitConverter.ToUInt16(dir, 6 + 14 * i + 12); // GRPICONDIRENTRY.nID + var pic = GetDataFromResource(hModule, RT_ICON, (IntPtr)id); + + // Copy GRPICONDIRENTRY to ICONDIRENTRY. + + dst.Seek(6 + 16 * i, SeekOrigin.Begin); + + dst.Write(dir, 6 + 14 * i, 8); // First 8bytes are identical. + dst.Write(pic.Length); // ICONDIRENTRY.dwBytesInRes + dst.Write(picOffset); // ICONDIRENTRY.dwImageOffset + + // Copy a picture. + + dst.Seek(picOffset, SeekOrigin.Begin); + dst.Write(pic, 0, pic.Length); + + picOffset += pic.Length; + } + + tmpData.Add(((MemoryStream)dst.BaseStream).ToArray()); + } + + return true; + }; + NativeMethods.EnumResourceNames(hModule, RT_GROUP_ICON, callback, IntPtr.Zero); + + iconData = tmpData.ToArray(); + } + finally + { + if (hModule != IntPtr.Zero) + NativeMethods.FreeLibrary(hModule); + } + } + + private byte[] GetDataFromResource(IntPtr hModule, IntPtr type, IntPtr name) + { + // Load the binary data from the specified resource. + + IntPtr hResInfo = NativeMethods.FindResource(hModule, name, type); + if (hResInfo == IntPtr.Zero) + throw new Win32Exception(); + + IntPtr hResData = NativeMethods.LoadResource(hModule, hResInfo); + if (hResData == IntPtr.Zero) + throw new Win32Exception(); + + IntPtr pResData = NativeMethods.LockResource(hResData); + if (pResData == IntPtr.Zero) + throw new Win32Exception(); + + uint size = NativeMethods.SizeofResource(hModule, hResInfo); + if (size == 0) + throw new Win32Exception(); + + byte[] buf = new byte[size]; + Marshal.Copy(pResData, buf, 0, buf.Length); + + return buf; + } + + private string GetFileName(IntPtr hModule) + { + + + string fileName; + { + var buf = new StringBuilder(MAX_PATH); + int len = NativeMethods.GetMappedFileName( + NativeMethods.GetCurrentProcess(), hModule, buf, buf.Capacity); + if (len == 0) + throw new Win32Exception(); + + fileName = buf.ToString(); + } + + + + for (char c = 'A'; c <= 'Z'; ++c) + { + var drive = c + ":"; + var buf = new StringBuilder(MAX_PATH); + int len = NativeMethods.QueryDosDevice(drive, buf, buf.Capacity); + if (len == 0) + continue; + + var devPath = buf.ToString(); + if (fileName.StartsWith(devPath)) + return (drive + fileName.Substring(devPath.Length)); + } + + return fileName; + } + + + } + internal static class NativeMethods + { + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport("kernel32.dll", SetLastError = true)] + [SuppressUnmanagedCodeSecurity] + public static extern bool FreeLibrary(IntPtr hModule); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + public static extern bool EnumResourceNames(IntPtr hModule, IntPtr lpszType, ENUMRESNAMEPROC lpEnumFunc, IntPtr lParam); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + public static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType); + + [DllImport("kernel32.dll", SetLastError = true)] + [SuppressUnmanagedCodeSecurity] + public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport("kernel32.dll", SetLastError = true)] + [SuppressUnmanagedCodeSecurity] + public static extern IntPtr LockResource(IntPtr hResData); + + [DllImport("kernel32.dll", SetLastError = true)] + [SuppressUnmanagedCodeSecurity] + public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport("kernel32.dll", SetLastError = true)] + [SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetCurrentProcess(); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + public static extern int QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax); + + [DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + public static extern int GetMappedFileName(IntPtr hProcess, IntPtr lpv, StringBuilder lpFilename, int nSize); + } + + [UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + internal delegate bool ENUMRESNAMEPROC(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam); +}