From c24f44cfb7cc4ead74fc8d5af1765d72ebc4c81a Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 9 Mar 2018 17:45:58 +0000 Subject: [PATCH] Add GUI viewers for PE resources. --- exeinfogui/MainForm.xeto.cs | 28 +++-- exeinfogui/NE/TabNeResources.xeto.cs | 19 ++-- exeinfogui/PE/PanelPeStrings.xeto | 8 ++ exeinfogui/PE/PanelPeStrings.xeto.cs | 52 +++++++++ exeinfogui/PE/PanelPeVersion.xeto | 85 +++++++++++++++ exeinfogui/PE/PanelPeVersion.xeto.cs | 151 +++++++++++++++++++++++++++ exeinfogui/PE/TabPeResources.xeto | 15 +++ exeinfogui/PE/TabPeResources.xeto.cs | 121 +++++++++++++++++++++ exeinfogui/PanelText.xeto | 11 ++ exeinfogui/PanelText.xeto.cs | 47 +++++++++ exeinfogui/exeinfogui.csproj | 1 + 11 files changed, 522 insertions(+), 16 deletions(-) create mode 100644 exeinfogui/PE/PanelPeStrings.xeto create mode 100644 exeinfogui/PE/PanelPeStrings.xeto.cs create mode 100644 exeinfogui/PE/PanelPeVersion.xeto create mode 100644 exeinfogui/PE/PanelPeVersion.xeto.cs create mode 100644 exeinfogui/PE/TabPeResources.xeto create mode 100644 exeinfogui/PE/TabPeResources.xeto.cs create mode 100644 exeinfogui/PanelText.xeto create mode 100644 exeinfogui/PanelText.xeto.cs diff --git a/exeinfogui/MainForm.xeto.cs b/exeinfogui/MainForm.xeto.cs index 9bf4dda..aeb1dd3 100644 --- a/exeinfogui/MainForm.xeto.cs +++ b/exeinfogui/MainForm.xeto.cs @@ -30,6 +30,7 @@ using exeinfogui.GEM; using exeinfogui.LE; using exeinfogui.LX; using exeinfogui.NE; +using exeinfogui.PE; using Eto.Forms; using Eto.Serialization.Xaml; using libexeinfo; @@ -42,8 +43,10 @@ namespace exeinfogui Label lblSubsystem; TabGemResources tabGemResources; TabLeVxdVersion tabLeVxdVersion; + TabLxResources tabLxResources; TabControl tabMain; TabNeResources tabNeResources; + TabPeResources tabPeResources; TabPageSegments tabSegments; TabPageStrings tabStrings; TextBox txtFile; @@ -51,7 +54,6 @@ namespace exeinfogui TextBox txtOs; TextBox txtSubsystem; TextBox txtType; - TabLxResources tabLxResources; public MainForm() { @@ -62,13 +64,15 @@ namespace exeinfogui tabGemResources = new TabGemResources {Visible = false}; tabNeResources = new TabNeResources {Visible = false}; tabLeVxdVersion = new TabLeVxdVersion {Visible = false}; - tabLxResources = new TabLxResources {Visible = false}; + tabLxResources = new TabLxResources {Visible = false}; + tabPeResources = new TabPeResources {Visible = false}; tabMain.Pages.Add(tabSegments); tabMain.Pages.Add(tabStrings); tabMain.Pages.Add(tabGemResources); tabMain.Pages.Add(tabNeResources); tabMain.Pages.Add(tabLeVxdVersion); tabMain.Pages.Add(tabLxResources); + tabMain.Pages.Add(tabPeResources); } protected void OnBtnLoadClick(object sender, EventArgs e) @@ -84,7 +88,8 @@ namespace exeinfogui tabSegments.Visible = false; tabNeResources.Visible = false; tabLeVxdVersion.Visible = false; - tabLxResources.Visible = false; + tabLxResources.Visible = false; + tabPeResources.Visible = false; OpenFileDialog dlgOpen = new OpenFileDialog {Title = "Choose executable file", MultiSelect = false}; @@ -101,7 +106,7 @@ namespace exeinfogui IExecutable stExe = new AtariST(dlgOpen.FileName); IExecutable lxExe = new libexeinfo.LX(dlgOpen.FileName); IExecutable coffExe = new COFF(dlgOpen.FileName); - IExecutable peExe = new PE(dlgOpen.FileName); + IExecutable peExe = new libexeinfo.PE(dlgOpen.FileName); IExecutable geosExe = new Geos(dlgOpen.FileName); IExecutable recognizedExe = null; @@ -133,13 +138,24 @@ namespace exeinfogui tabLeVxdVersion.Visible = true; tabLeVxdVersion.Update(((libexeinfo.LX)lxExe).WinVersion); } - if(((libexeinfo.LX)lxExe).neFormatResourceTable.types != null && ((libexeinfo.LX)lxExe).neFormatResourceTable.types.Any()) + + if(((libexeinfo.LX)lxExe).neFormatResourceTable.types != null && + ((libexeinfo.LX)lxExe).neFormatResourceTable.types.Any()) { tabLxResources.Update(((libexeinfo.LX)lxExe).neFormatResourceTable.types); tabLxResources.Visible = true; } } - else if(peExe.Recognized) recognizedExe = peExe; + else if(peExe.Recognized) + { + recognizedExe = peExe; + if(((libexeinfo.PE)peExe).WindowsResourcesRoot != null && + ((libexeinfo.PE)peExe).WindowsResourcesRoot.children != null) + { + tabPeResources.Update(((libexeinfo.PE)peExe).WindowsResourcesRoot); + tabPeResources.Visible = true; + } + } else if(stExe.Recognized) { recognizedExe = stExe; diff --git a/exeinfogui/NE/TabNeResources.xeto.cs b/exeinfogui/NE/TabNeResources.xeto.cs index 48bef09..28a8d64 100644 --- a/exeinfogui/NE/TabNeResources.xeto.cs +++ b/exeinfogui/NE/TabNeResources.xeto.cs @@ -37,15 +37,14 @@ namespace exeinfogui.NE { public class TabNeResources : TabPage { - PanelHexDump panelHexDump; - PanelNeAccelerators panelNeAccelerators; - PanelNeStrings panelNeStrings; - PanelOs2Bitmap panelOs2Bitmap; - PanelWin16Version panelWin16Version; - PanelWindowsIcon panelWindowsIcon; - Panel pnlResource; - TreeGridItemCollection treeData; - TreeGridView treeResources; + PanelHexDump panelHexDump; + PanelNeAccelerators panelNeAccelerators; + PanelNeStrings panelNeStrings; + PanelOs2Bitmap panelOs2Bitmap; + PanelWin16Version panelWin16Version; + PanelWindowsIcon panelWindowsIcon; + Panel pnlResource; + TreeGridView treeResources; public TabNeResources() { @@ -68,7 +67,7 @@ namespace exeinfogui.NE public void Update(IEnumerable resourceTypes, libexeinfo.NE.TargetOS os) { - treeData = new TreeGridItemCollection(); + TreeGridItemCollection treeData = new TreeGridItemCollection(); foreach(libexeinfo.NE.ResourceType resourceType in resourceTypes.OrderBy(r => r.name)) { diff --git a/exeinfogui/PE/PanelPeStrings.xeto b/exeinfogui/PE/PanelPeStrings.xeto new file mode 100644 index 0000000..f113ff0 --- /dev/null +++ b/exeinfogui/PE/PanelPeStrings.xeto @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/exeinfogui/PE/PanelPeStrings.xeto.cs b/exeinfogui/PE/PanelPeStrings.xeto.cs new file mode 100644 index 0000000..2359927 --- /dev/null +++ b/exeinfogui/PE/PanelPeStrings.xeto.cs @@ -0,0 +1,52 @@ +// +// PanelPeStrings.xeto.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017-2018 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using Eto.Forms; +using Eto.Serialization.Xaml; + +namespace exeinfogui.PE +{ + public class PanelPeStrings : Panel + { + GridView treeStrings; + + public PanelPeStrings() + { + XamlReader.Load(this); + + treeStrings.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(r => r)}, + HeaderText = "String" + }); + } + + public void Update(byte[] data) + { + treeStrings.DataStore = libexeinfo.PE.GetStrings(data); + } + } +} \ No newline at end of file diff --git a/exeinfogui/PE/PanelPeVersion.xeto b/exeinfogui/PE/PanelPeVersion.xeto new file mode 100644 index 0000000..b77aae8 --- /dev/null +++ b/exeinfogui/PE/PanelPeVersion.xeto @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/exeinfogui/PE/PanelPeVersion.xeto.cs b/exeinfogui/PE/PanelPeVersion.xeto.cs new file mode 100644 index 0000000..85cc785 --- /dev/null +++ b/exeinfogui/PE/PanelPeVersion.xeto.cs @@ -0,0 +1,151 @@ +// +// PanelPeVersion.xeto.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017-2018 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Text; +using Eto.Forms; +using Eto.Serialization.Xaml; +using libexeinfo.Windows; +using Version = libexeinfo.Windows.Version; + +namespace exeinfogui.PE +{ + public class PanelPeVersion : Panel + { + ObservableCollection stringsByLanguage; + GridView treeLanguages; + GridView treeStrings; + TextBox txtFileDate; + TextBox txtFileFlags; + TextBox txtFileOs; + TextBox txtFileSubtype; + TextBox txtFileType; + TextBox txtFileVersion; + TextBox txtProductVersion; + + public PanelPeVersion() + { + XamlReader.Load(this); + + treeLanguages.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(r => r.Name)}, + HeaderText = "Language (codepage)" + }); + + treeStrings.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(r => r.Key)}, + HeaderText = "Key" + }); + + treeStrings.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(r => r.Value)}, + HeaderText = "Value" + }); + + stringsByLanguage = new ObservableCollection(); + treeLanguages.SelectionChanged += TreeLanguagesOnSelectionChanged; + treeLanguages.AllowMultipleSelection = false; + } + + void TreeLanguagesOnSelectionChanged(object sender, EventArgs eventArgs) + { + treeStrings.DataStore = null; + if(!(treeLanguages.SelectedItem is StrByLang strs)) return; + + List strings = new List(); + foreach(KeyValuePair kvp in strs.Strings) + strings.Add(new Strings {Key = kvp.Key, Value = kvp.Value}); + + treeStrings.DataStore = strings; + } + + public void Update(byte[] data) + { + Update(new libexeinfo.PE.Version(data)); + } + + public void Update(libexeinfo.PE.Version version) + { + txtFileDate.Text = version.FileDate != new DateTime(1601, 1, 1) ? $"{version.FileDate}" : "Not set"; + txtFileFlags.Text = version.FileFlags == 0 ? "Normal" : $"{version.FileFlags}"; + txtFileOs.Text = Version.OsToString(version.FileOs); + + if(version.FileType == VersionFileType.VFT_DRV) + txtFileSubtype.Text = $"{Version.DriverToString(version.FileSubtype)} driver"; + else if(version.FileType == VersionFileType.VFT_DRV) + txtFileSubtype.Text = $"{Version.FontToString(version.FileSubtype)} font"; + else if(version.FileSubtype > 0) txtFileSubtype.Text = $"{(uint)version.FileSubtype}"; + else txtFileSubtype.Text = "None"; + + txtFileType.Text = Version.TypeToString(version.FileType); + txtFileVersion.Text = $"{version.FileVersion}"; + txtProductVersion.Text = $"{version.ProductVersion}"; + + stringsByLanguage.Clear(); + + foreach(KeyValuePair> strByLang in version.StringsByLanguage) + { + string cultureName; + string encodingName; + + try { cultureName = new CultureInfo(Convert.ToInt32(strByLang.Key.Substring(0, 4), 16)).DisplayName; } + catch { cultureName = $"0x{Convert.ToInt32(strByLang.Key.Substring(0, 4), 16):X4}"; } + + try + { + encodingName = Encoding.GetEncoding(Convert.ToInt32(strByLang.Key.Substring(4), 16)).EncodingName; + } + catch { encodingName = $"0x{Convert.ToInt32(strByLang.Key.Substring(4), 16):X4}"; } + + stringsByLanguage.Add(new StrByLang + { + Name = $"{cultureName} ({encodingName})", + Strings = strByLang.Value + }); + } + + treeLanguages.DataStore = stringsByLanguage; + } + + class StrByLang + { + public Dictionary Strings; + public string Name { get; set; } + } + + class Strings + { + public string Key { get; set; } + public string Value { get; set; } + } + } +} \ No newline at end of file diff --git a/exeinfogui/PE/TabPeResources.xeto b/exeinfogui/PE/TabPeResources.xeto new file mode 100644 index 0000000..e5f7da5 --- /dev/null +++ b/exeinfogui/PE/TabPeResources.xeto @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/exeinfogui/PE/TabPeResources.xeto.cs b/exeinfogui/PE/TabPeResources.xeto.cs new file mode 100644 index 0000000..5d1ccc0 --- /dev/null +++ b/exeinfogui/PE/TabPeResources.xeto.cs @@ -0,0 +1,121 @@ +// +// TabPeResources.xeto.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017-2018 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Text; +using exeinfogui.Windows; +using Eto.Forms; +using Eto.Serialization.Xaml; + +namespace exeinfogui.PE +{ + public class TabPeResources : TabPage + { + PanelHexDump panelHexDump; + PanelPeStrings panelPeStrings; + PanelPeVersion panelPeVersion; + PanelText panelText; + PanelWindowsIcon panelWindowsIcon; + Panel pnlResource; + TreeGridView treeResources; + + public TabPeResources() + { + XamlReader.Load(this); + + treeResources.Columns.Add(new GridColumn {HeaderText = "Identifier", DataCell = new TextBoxCell(0)}); + treeResources.Columns.Add(new GridColumn {HeaderText = "Size", DataCell = new TextBoxCell(1)}); + + treeResources.AllowMultipleSelection = false; + treeResources.SelectionChanged += TreeResourcesOnSelectionChanged; + + panelPeVersion = new PanelPeVersion(); + panelPeStrings = new PanelPeStrings(); + panelHexDump = new PanelHexDump(); + panelWindowsIcon = new PanelWindowsIcon(); + panelText = new PanelText(); + } + + public void Update(libexeinfo.PE.ResourceNode root) + { + TreeGridItemCollection treeData = new TreeGridItemCollection(); + + foreach(libexeinfo.PE.ResourceNode rootChild in root.children) + treeData.Add(GetChildren(rootChild, rootChild.name)); + + treeResources.DataStore = treeData; + } + + static TreeGridItem GetChildren(libexeinfo.PE.ResourceNode node, string type) + { + string sizeStr = node.data == null ? null : $"{node.data.Length}"; + + TreeGridItem item = new TreeGridItem {Values = new object[] {$"{node.name}", sizeStr, type, node.data}}; + + if(node.children == null) return item; + + foreach(libexeinfo.PE.ResourceNode child in node.children) item.Children.Add(GetChildren(child, type)); + + return item; + } + + void TreeResourcesOnSelectionChanged(object sender, EventArgs eventArgs) + { + if(((TreeGridItem)treeResources.SelectedItem)?.Values[3] == null) + { + pnlResource.Content = null; + return; + } + + byte[] data = ((TreeGridItem)treeResources.SelectedItem)?.Values[3] as byte[]; + string type = ((TreeGridItem)treeResources.SelectedItem)?.Values[2] as string; + + switch(type) + { + case "RT_STRING": + pnlResource.Content = panelPeStrings; + panelPeStrings.Update(data); + break; + case "RT_ICON": + pnlResource.Content = panelWindowsIcon; + panelWindowsIcon.Update(data); + break; + case "RT_VERSION": + pnlResource.Content = panelPeVersion; + panelPeVersion.Update(data); + break; + case "RT_MANIFEST": + pnlResource.Content = panelText; + panelText.Update(data, Encoding.UTF8); + break; + default: + pnlResource.Content = panelHexDump; + panelHexDump.Update(data); + break; + } + } + } +} \ No newline at end of file diff --git a/exeinfogui/PanelText.xeto b/exeinfogui/PanelText.xeto new file mode 100644 index 0000000..f1d93b9 --- /dev/null +++ b/exeinfogui/PanelText.xeto @@ -0,0 +1,11 @@ + + + + + + + +