Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem in update dialog #221

Closed
laomms opened this issue Nov 23, 2021 · 7 comments
Closed

Problem in update dialog #221

laomms opened this issue Nov 23, 2021 · 7 comments
Labels
pe Issues related to AsmResolver.PE win32resources Issues related to AsmResolver.PE.Win32Resources

Comments

@laomms
Copy link

laomms commented Nov 23, 2021

I want to try to use AsmResolver library to update dialog controls, I took C:\Windows\en-US\notepad.exe.mui as an experiment

pic1

I want try to delete help button in dialog form.

pic2

After comparing using tools, I found three differences

pic3

Below is the code:

code
        static void Main(string[] args)
        {
            string filePath = @"C:\Windows\en-US\notepad.exe.mui";
            ModifyFileDescription(filePath, "modify.mui");
            Console.ReadKey();
        }
        static void ModifyFileDescription(string input, string output)
        {
            var file = PEFile.FromFile(input);
            var image = PEImage.FromFile(file);
            var stringTables = (IResourceDirectory)image.Resources.Entries.First(e => e.Id == (int)ResourceType.Dialog);
            var stringEntry = (IResourceDirectory)stringTables.Entries.First(e => e.Id == 1541); // ID
            var dataEntry = (IResourceData)stringEntry.Entries.First(e => e.Id == 1033); // Lang ID
            byte[] content = ((AsmResolver.DataSegment)dataEntry.Contents).Data;

            var byteSearch = new byte[] { 0x00, 0x00, 0x01, 0x50, 0xAE, 0x00, 0x4B, 0x00, 0x32, 0x00, 0x0E, 0x00, 0x0E, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x26, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
            var index = SearchBytePattern(content, byteSearch);
            if (index > 0)
            {
                ushort oSize = BitConverter.ToUInt16(content.Skip(12).Take(2).ToArray(), 0);  //C4 00 to C0 00
                oSize -= 4;
                content[12] = BitConverter.GetBytes(oSize).ToArray()[0];
                content[13] = BitConverter.GetBytes(oSize).ToArray()[1];
                ushort controlCount = BitConverter.ToUInt16(content.Skip(16).Take(2).ToArray(), 0);  //0D 00 to 0C 00
                controlCount -= 1;
                content[16] = BitConverter.GetBytes(controlCount).ToArray()[0];
                content[17] = BitConverter.GetBytes(controlCount).ToArray()[1];
                byte[] bytesWrite = content.Take(index - 1).ToArray().Concat(content.Skip(index - 1 + byteSearch.Length).Take(content.Length - index - byteSearch.Length + 1).ToArray()).ToArray();
                using (var stream = new MemoryStream())
                {
                    var writer = new BinaryStreamWriter(stream);
                    writer.WriteUInt16((ushort)bytesWrite.Length);
                    writer.WriteBytes(bytesWrite);
                    writer.Align(4);
                    dataEntry.Contents = new AsmResolver.DataSegment(stream.ToArray());
                    var rsrc = file.Sections.First(s => s.Name == ".rsrc");
                    var newContents = new ResourceDirectoryBuffer();
                    newContents.AddDirectory(image.Resources);
                    rsrc.Contents = newContents;

                    file.AlignSections();
                    file.OptionalHeader.DataDirectories[(int)DataDirectoryIndex.ResourceDirectory] = new DataDirectory(newContents.DirectoryTable.Rva, newContents.DirectoryTable.GetPhysicalSize());
                    file.Write(output);
                }
            }           
        }

        public static int SearchBytePattern(byte[] src, byte[] pattern)
        {
            for (int x = 0; x < src.Length; x++)
            {
                byte currentValue = src[x];
                if (currentValue != pattern[0])
                {
                    continue;
                }
                bool match = false;
                try
                {
                    for (int y = 0; y < pattern.Length; y++)
                    {
                        byte tempValue = src[x + y];
                        if (tempValue != pattern[y])
                        {
                            match = false;
                            break;
                        }
                        match = true;
                    }
                }
                catch { }
                if (match)
                {
                    return x;
                }
            }
            return -1;
        }

After updated, However, garbled characters appear, and the dialog box cannot be opened completely.Don't know where the problem is.

error
@Washi1337
Copy link
Owner

Make sure you retain the right binary format for RT_DIALOG resources. The way you are editing the resource does not conform with this format:

Reference:
https://docs.microsoft.com/en-us/windows/win32/api/Winuser/ns-winuser-dlgtemplate

@Washi1337 Washi1337 added pe Issues related to AsmResolver.PE win32resources Issues related to AsmResolver.PE.Win32Resources and removed enhancement labels Nov 23, 2021
@laomms
Copy link
Author

laomms commented Nov 25, 2021

I wrote the dialog parsing code based on the c++ code here (https://blog.csdn.net/zhyulo/article/details/88239145), the result same as what I tested on https://speedtesting.herokuapp.com/peviewer/. but It seems to be troublesome to write back to new section.

code
using AsmResolver;
using AsmResolver.PE;
using AsmResolver.PE.File;
using AsmResolver.PE.Win32Resources;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace CallTest
{

    class Program
    {
#pragma warning disable 0649
        public struct ControlData
        {
            public uint Style;
            public uint ExStyle;
            public ushort x;
            public ushort y;
            public ushort cx;
            public ushort cy;
            public ushort id;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct DialogBoxHeader
        {
            public uint Style;
            public uint ExStyle;
            public ushort DlgItems; //control amount
            public ushort x;
            public ushort y;
            public ushort cx;
            public ushort cy;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] menuName;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct DialogFont
        {
            public ushort wPointSize;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] FontName;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct DialogBoxHeaderEx
        {
            public uint SignEx; //0xFFFF0001
            public uint Version;
            public uint ExStyle;
            public uint Style;
            public ushort DlgItems; //control amount
            public ushort x;
            public ushort y;
            public ushort cx;
            public ushort cy;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] menuName;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct DialogFontEx
        {
            public ushort wPointSize;
            public ushort Weight;
            public byte Italic;
            public byte CharSet;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] FontName;
        }
#pragma warning restore 0649


        static void Main(string[] args)
        {
            string filePath = @"C:\Windows\en-US\notepad.exe.mui";
            ModifyFileDescription(filePath, "modify.mui");
            Console.ReadKey();
        }
        static void ModifyFileDescription(string input, string output)
        {
            var file = PEFile.FromFile(input);
            var image = PEImage.FromFile(file);
            var stringTables = (IResourceDirectory)image.Resources.Entries.First(e => e.Id == (int)ResourceType.Dialog);
            var stringEntry = (IResourceDirectory)stringTables.Entries.First(e => e.Id == 1541); // ID
            var dataEntry = (IResourceData)stringEntry.Entries.First(e => e.Id == 1033); // Lang ID
            byte[] content = ((AsmResolver.DataSegment)dataEntry.Contents).Data;
            ParseDialog( content);
        }


        private static byte[] ParseDialog( byte[] bytesIn)
        {
            bool isDialogEx = false;
            dynamic DlgBoxHeader;
            #region DlgBoxHeader
            if (Enumerable.SequenceEqual(bytesIn.Take(4).ToArray(), new byte[] { 0x1, 0x0, 0xFF, 0xFF })) //Dialog or DialogEx
            {
                isDialogEx = true;
                DlgBoxHeader = new DialogBoxHeaderEx();
            }
            else
            {
                isDialogEx = false;
                DlgBoxHeader = new DialogBoxHeader();
            }
            int size = Marshal.SizeOf(DlgBoxHeader);
            IntPtr buff = Marshal.AllocHGlobal(size);
            Marshal.Copy(bytesIn.Take(size).ToArray(), 0, buff, size);
            DlgBoxHeader = isDialogEx ? (DialogBoxHeaderEx)Marshal.PtrToStructure(buff, typeof(DialogBoxHeaderEx)) : (DialogBoxHeader)Marshal.PtrToStructure(buff, typeof(DialogBoxHeader));
            if (DlgBoxHeader.ExStyle != 0)
            {
                Console.WriteLine("0x" + DlgBoxHeader.ExStyle.ToString("x8"));
            }
            bytesIn = bytesIn.Skip(size).ToArray();
            #endregion
            #region MenuName
            byte[] bClassName = null;
            byte[] bMenuName = DlgBoxHeader.menuName;
            if (BitConverter.ToInt16(bMenuName.Take(2).ToArray(), 0) == -1)
            {
                bClassName = bytesIn;
            }
            else if (BitConverter.ToInt16(bMenuName.Take(2).ToArray(), 0) != 0)
            {
                var len = GetUnicodeStringLength(bytesIn);
                var szMenuName = Encoding.Unicode.GetString(bytesIn, 0, len);
                Console.WriteLine("MenuName:" + szMenuName);
                bClassName = bytesIn.Skip(len).ToArray();
            }
            else
            {
                bClassName = bytesIn;
            }
            #endregion
            #region ClassName
            byte[] bCaption = null;
            if (BitConverter.ToInt16(bClassName.Take(2).ToArray(), 0) == -1)
            {
                bCaption = bClassName.Skip(2).ToArray();
            }
            else if (BitConverter.ToInt16(bClassName.Take(2).ToArray(), 0) != 0)
            {
                var len = GetUnicodeStringLength(bClassName);
                var szClassName = Encoding.Unicode.GetString(bClassName, 0, len);
                Console.WriteLine("ClassName:" + szClassName);
                bCaption = bClassName.Skip(len + 2).ToArray();
            }
            else
            {
                bCaption = bClassName.Skip(2).ToArray();
            }
            #endregion
            #region Caption
            byte[] bItemData = null;
            if (BitConverter.ToInt16(bCaption.Take(2).ToArray(), 0) != 0)
            {
                var len = GetUnicodeStringLength(bCaption);
                var szCaption = Encoding.Unicode.GetString(bCaption, 0, len);
                Console.WriteLine("Caption:" + szCaption);
                bItemData = bCaption.Skip(len + 2).ToArray();
            }
            else
            {
                bItemData = bCaption.Skip(2).ToArray();
            }
            #endregion
            #region DialogFont
            if ((DlgBoxHeader.Style & (uint)DialogBoxStyles.DS_SETFONT) != 0) //if have font
            {
                DialogFontEx DlgFont = new DialogFontEx();
                size = Marshal.SizeOf(DlgFont);
                buff = Marshal.AllocHGlobal(size);
                Marshal.Copy(bItemData.Take(size).ToArray(), 0, buff, size);
                DlgFont = (DialogFontEx)Marshal.PtrToStructure(buff, typeof(DialogFontEx));
                if (BitConverter.ToInt16(DlgFont.FontName.Take(2).ToArray(), 0) != 0)
                {
                    bItemData = bItemData.Skip(size - 2).ToArray();
                    var len = GetUnicodeStringLength(bItemData);
                    var szFontName = Encoding.Unicode.GetString(bItemData, 0, len);
                    Console.WriteLine("FontName:" + szFontName);
                    bItemData = bItemData.Skip(len).ToArray();
                }
            }
            #endregion
            #region ControlList
            int isControl = 0;
            bItemData = bItemData.Skip(4).ToArray();
            for (int i = 0; i < DlgBoxHeader.DlgItems; i++)
            {
                ControlData ctlData = new ControlData();
                size = Marshal.SizeOf(ctlData);
                buff = Marshal.AllocHGlobal(size);
                uint helpID = 0;
                if (isDialogEx)
                {
                    helpID = (uint)BitConverter.ToInt16(bItemData.Take(2).ToArray(), 0);
                    Marshal.Copy(bItemData.Skip(2).Take(size).ToArray(), 0, buff, size);
                }
                else
                {
                    Marshal.Copy(bItemData.Take(size).ToArray(), 0, buff, size);
                }
                ctlData = (ControlData)Marshal.PtrToStructure(buff, typeof(ControlData));
                Console.WriteLine("IDC_" + ctlData.id.ToString());
                Console.WriteLine(ctlData.x.ToString() + "," + ctlData.y.ToString() + "," + ctlData.cx.ToString() + "," + ctlData.cy.ToString());
                var Style = isDialogEx ? ctlData.ExStyle : ctlData.Style;
                var ExStyle = isDialogEx ? ctlData.Style : ctlData.ExStyle;
                byte[] bClassID = bItemData.Skip(size).ToArray(); //move to id in struct
                if (isDialogEx)
                {
                    bClassID = bClassID.Skip(2).ToArray();
                }
                uint NotStyle = 0;
                #region ControlStyle
                byte[] bCtlName = null;
                if (BitConverter.ToInt16(bClassID.Take(2).ToArray(), 0) == -1)
                {
                    switch (bClassID[2])
                    {
                        case 0x80:
                            switch (Style & 0xF)
                            {
                                case (uint)WindowStyles.BS_PUSHBUTTON:
                                    Console.WriteLine("PUSHBUTTON");
                                    NotStyle = (uint)(WindowStyles.BS_PUSHBUTTON | WindowStyles.WS_TABSTOP);
                                    break;
                                case (uint)WindowStyles.BS_DEFPUSHBUTTON:
                                    Console.WriteLine("DEFPUSHBUTTON");
                                    NotStyle = (uint)(WindowStyles.BS_DEFPUSHBUTTON | WindowStyles.WS_TABSTOP);
                                    break;
                                case (uint)WindowStyles.BS_CHECKBOX:
                                    Console.WriteLine("CHECKBOX");
                                    NotStyle = (uint)(WindowStyles.BS_CHECKBOX | WindowStyles.WS_TABSTOP);
                                    break;
                                case (uint)WindowStyles.BS_AUTOCHECKBOX:
                                    Console.WriteLine("AUTOCHECKBOX");
                                    NotStyle = (uint)WindowStyles.BS_AUTOCHECKBOX;
                                    break;
                                case (uint)WindowStyles.BS_RADIOBUTTON:
                                    Console.WriteLine("RADIOBUTTON");
                                    NotStyle = (uint)WindowStyles.BS_RADIOBUTTON;
                                    break;
                                case (uint)WindowStyles.BS_3STATE:
                                    Console.WriteLine("STATE3" + "\t");
                                    NotStyle = (uint)WindowStyles.BS_3STATE;
                                    break;
                                case (uint)WindowStyles.BS_AUTO3STATE:
                                    Console.WriteLine("AUTO3STATE");
                                    NotStyle = (uint)WindowStyles.BS_AUTO3STATE;
                                    break;
                                case (uint)WindowStyles.BS_GROUPBOX:
                                    Console.WriteLine("GROUPBOX");
                                    NotStyle = (uint)WindowStyles.BS_GROUPBOX;
                                    break;
                                case (uint)WindowStyles.BS_AUTORADIOBUTTON:
                                    Console.WriteLine("AUTORADIOBUTTON");
                                    NotStyle = (uint)WindowStyles.BS_AUTORADIOBUTTON;
                                    break;
                                default:
                                    Console.WriteLine("CONTROL" + "\t");
                                    NotStyle = 0;
                                    isControl = 1;
                                    break;
                            }
                            break;
                        case 0x81:
                            Console.WriteLine("EDITTEXT");
                            NotStyle = (uint)(WindowStyles.ES_LEFT | WindowStyles.WS_BORDER | WindowStyles.WS_TABSTOP);
                            break;
                        case 0x82:
                            switch (Style & 0xF)
                            {
                                case (uint)WindowStyles.SS_LEFT:
                                    Console.WriteLine("LTEXT" + "\t");
                                    NotStyle = (uint)(WindowStyles.SS_LEFT | WindowStyles.WS_GROUP);
                                    break;
                                case (uint)WindowStyles.SS_RIGHT:
                                    Console.WriteLine("RTEXT" + "\t");
                                    NotStyle = (uint)(WindowStyles.SS_RIGHT | WindowStyles.WS_GROUP);
                                    break;
                                case (uint)WindowStyles.SS_CENTER:
                                    Console.WriteLine("CTEXT" + "\t");
                                    NotStyle = (uint)(WindowStyles.SS_CENTER | WindowStyles.WS_GROUP);
                                    break;
                                case (uint)WindowStyles.SS_ICON:
                                    Console.WriteLine("ICON" + "\t");
                                    NotStyle = (uint)WindowStyles.SS_ICON;
                                    break;
                                default:
                                    Console.WriteLine("CONTROL" + "\t");
                                    NotStyle = 0;
                                    isControl = 2;
                                    break;
                            }
                            break;
                        case 0x83:
                            Console.WriteLine("LISTBOX" + "\t");
                            NotStyle = (uint)(WindowStyles.WS_BORDER | WindowStyles.LBS_NOTIFY);
                            break;
                        case 0x84:
                            Console.WriteLine("SCROLLBAR");
                            NotStyle = 0;
                            break;
                        case 0x85:
                            Console.WriteLine("COMBOBOX");
                            NotStyle = 0;
                            break;
                        default:
                            Console.WriteLine("CONTROL" + "\t");
                            NotStyle = 0;
                            isControl = -2;
                            break;
                    }
                    bCtlName = bClassID.Skip(4).ToArray();
                }
                else
                {
                    var len = GetUnicodeStringLength(bClassID);
                    var szCtlName = Encoding.Unicode.GetString(bClassID, 0, len);
                    Console.WriteLine("CtlName:" + szCtlName);
                    bCtlName = bClassID.Skip(len + 2).ToArray();
                }
                #endregion
                NotStyle |= (uint)WindowStyles.WS_CHILD | (uint)WindowStyles.WS_VISIBLE;
                Style &= ~NotStyle;
                NotStyle &= ~(isDialogEx ? ctlData.ExStyle : ctlData.Style);
                #region ControlName
                byte[] bCtlId = null;
                if (BitConverter.ToInt16(bCtlName.Take(2).ToArray(), 0) == -1)
                {
                    bCtlId = bCtlName.Skip(6).ToArray();
                }
                else
                {
                    if (isControl == 0 && (bClassID[1] == 0x81 || bClassID[1] == 0x83 || bClassID[1] == 0x84 || bClassID[1] == 0x85))
                    {
                        bCtlId = bCtlName.Skip(2).ToArray();
                    }
                    else
                    {
                        var len = GetUnicodeStringLength(bCtlName);
                        var szCtlId = Encoding.Unicode.GetString(bCtlName, 0, len);
                        Console.WriteLine("CtlId:" + szCtlId);
                        if (len > 2)
                        {
                            bCtlId = bCtlName.Skip(len + 4).ToArray();
                        }
                        else
                        {
                            bCtlId = bCtlName.Skip(2).ToArray();
                        }
                    }
                }
                #endregion

                string[] pStyle = { "", "button", "static" };
                if (isControl != 0)
                {
                    if (isControl == -1)
                    {
                        Console.WriteLine(BitConverter.ToInt16(bCtlName.Take(2).ToArray(), 0).ToString());
                    }
                    else if (isControl > 0)
                    {
                        Console.WriteLine(pStyle[isControl]);
                    }
                    else
                    {
                        Console.WriteLine(bClassID[0].ToString());
                    }
                    if (Convert.ToInt32(Style) != 0 || NotStyle == 0)
                    {
                        Console.WriteLine("0x" + Style.ToString("x8"));
                    }
                    if (NotStyle != 0)
                    {
                        Console.WriteLine("0x" + NotStyle.ToString("x8"));
                    }
                    NotStyle = 0;
                    Style = NotStyle;
                }

                if (Style!=0 || NotStyle!=0 || ExStyle !=0 || (isDialogEx && helpID !=0))
                {
                    if (Style != 0 || ((~NotStyle) != 0 && (~isControl) != 0))
                    {
                        Console.WriteLine("0x" + Style.ToString("x8"));
                    }
                    if (NotStyle != 0)
                    {
                        if (Style!=0)
                        {
                            Console.WriteLine(" |0x" + NotStyle.ToString("x8"));
                        }
                        else
                        {
                            Console.WriteLine(",0x" + NotStyle.ToString("x8"));
                        }
                    }
                    if (ExStyle != 0 || (isDialogEx && helpID != 0))
                    {
                        if (ExStyle == (uint)WindowExStyles.WS_EX_STATICEDGE)
                        {
                            Console.WriteLine(", WS_EX_STATICEDGE");
                        }
                        else
                        {
                            Console.WriteLine("0x" + ExStyle.ToString("x8"));
                        }
                        if (isDialogEx && helpID != 0)
                        {
                            Console.WriteLine(ctlData.id.ToString());
                        }
                    }
                }
                bItemData = bCtlId.Skip(2).ToArray();
                if (isDialogEx)
                {
                    bItemData = bItemData.Skip(2).ToArray();
                }
            }
            #endregion
            return bytesIn;
        }

        private static int GetUnicodeStringLength(byte[] byteIn)
        {
            int nullterm = 0;
            while (nullterm < byteIn.Length && byteIn[nullterm] != 0)
            {
                nullterm += 2;
            }
            return nullterm;
        }
        public enum DialogBoxStyles
        {
            DS_SETFOREGROUND = 0x200,
            DS_NOFAILCREATE = 0x10,
            DS_CONTEXTHELP = 0x2000,
            DS_CENTERMOUSE = 0x1000,
            DS_MODALFRAME = 0x80,
            DS_S_SUCCESS = 0,
            DS_SHELLFONT = DS_SETFONT | DS_FIXEDSYS,
            DS_NOIDLEMSG = 0x100,
            DS_LOCALEDIT = 0x20,
            DS_SYSMODAL = 0x2,
            DS_FIXEDSYS = 0x8,
            DS_ABSALIGN = 0x1,
            DS_SETFONT = 0x40,
            DS_CONTROL = 0x400,
            DS_CENTER = 0x800,
            DS_3DLOOK = 0x4
        }

        public enum WindowExStyles
        {
            WS_EX_DLGMODALFRAME = 0x1,
            WS_EX_NOPARENTNOTIFY = 0x4,
            WS_EX_TOPMOST = 0x8,
            WS_EX_ACCEPTFILES = 0x10,
            WS_EX_TRANSPARENT = 0x20,
            WS_EX_MDICHILD = 0x40,
            WS_EX_TOOLWINDOW = 0x80,
            WS_EX_WINDOWEDGE = 0x100,
            WS_EX_CLIENTEDGE = 0x200,
            WS_EX_CONTEXTHELP = 0x400,
            WS_EX_RIGHT = 0x1000,
            WS_EX_LEFT = 0x0,
            WS_EX_RTLREADING = 0x2000,
            WS_EX_LTRREADING = 0x0,
            WS_EX_LEFTSCROLLBAR = 0x4000,
            WS_EX_RIGHTSCROLLBAR = 0x0,
            WS_EX_CONTROLPARENT = 0x10000,
            WS_EX_STATICEDGE = 0x20000,
            WS_EX_APPWINDOW = 0x40000,
            WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE),
            WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST),
            WS_EX_LAYERED = 0x80000,
            WS_EX_NOREDIRECTIONBITMAP = 0x200000,
            WS_EX_NOINHERITLAYOUT = 0x100000,
            WS_EX_NOACTIVATE = 0x8000000,
            WS_EX_LAYOUTRTL = 0x400000,
            WS_EX_COMPOSITED = 0x2000000

        }

        public enum WindowStyles : uint
        {
            WS_OVERLAPPED = 0x0,
            WS_POPUP = 0x80000000U,
            WS_CHILD = 0x40000000,
            WS_MINIMIZE = 0x20000000,
            WS_VISIBLE = 0x10000000,
            WS_DISABLED = 0x8000000,
            WS_CLIPSIBLINGS = 0x4000000,
            WS_CLIPCHILDREN = 0x2000000,
            WS_MAXIMIZE = 0x1000000,
            WS_CAPTION = 0xC00000,
            WS_BORDER = 0x800000,
            WS_DLGFRAME = 0x400000,
            WS_VSCROLL = 0x200000,
            WS_HSCROLL = 0x100000,
            WS_SYSMENU = 0x80000,
            WS_THICKFRAME = 0x40000,
            WS_GROUP = 0x20000,
            WS_TABSTOP = 0x10000,
            WS_MINIMIZEBOX = 0x20000,
            WS_MAXIMIZEBOX = 0x10000,
            WS_TILED = 0x0,
            WS_ICONIC = 0x20000000,
            WS_SIZEBOX = 0x40000,
            WS_TILEDWINDOW = 0xCF0000,
            WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),
            WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU),
            WS_CHILDWINDOW = (WS_CHILD),

            //		
            //		 * Edit Control Styles
            //		 
            ES_LEFT = 0x0,
            ES_CENTER = 0x1,
            ES_RIGHT = 0x2,
            ES_MULTILINE = 0x4,
            ES_UPPERCASE = 0x8,
            ES_LOWERCASE = 0x10,
            ES_PASSWORD = 0x20,
            ES_AUTOVSCROLL = 0x40,
            ES_AUTOHSCROLL = 0x80,
            ES_NOHIDESEL = 0x100,
            ES_OEMCONVERT = 0x400,
            ES_READONLY = 0x800,
            ES_WANTRETURN = 0x1000,
            ES_NUMBER = 0x2000,


            //		
            //		 * Button Control Styles
            //		 
            BS_PUSHBUTTON = 0x0,
            BS_DEFPUSHBUTTON = 0x1,
            BS_CHECKBOX = 0x2,
            BS_AUTOCHECKBOX = 0x3,
            BS_RADIOBUTTON = 0x4,
            BS_3STATE = 0x5,
            BS_AUTO3STATE = 0x6,
            BS_GROUPBOX = 0x7,
            BS_USERBUTTON = 0x8,
            BS_AUTORADIOBUTTON = 0x9,
            BS_PUSHBOX = 0xA,
            BS_OWNERDRAW = 0xB,
            BS_TYPEMASK = 0xF,
            BS_LEFTTEXT = 0x20,
            BS_TEXT = 0x0,
            BS_ICON = 0x40,
            BS_BITMAP = 0x80,
            BS_LEFT = 0x100,
            BS_RIGHT = 0x200,
            BS_CENTER = 0x300,
            BS_TOP = 0x400,
            BS_BOTTOM = 0x800,
            BS_VCENTER = 0xC00,
            BS_PUSHLIKE = 0x1000,
            BS_MULTILINE = 0x2000,
            BS_NOTIFY = 0x4000,
            BS_FLAT = 0x8000,
            BS_RIGHTBUTTON = BS_LEFTTEXT,


            //		
            //		 * Static Control Constants
            //		 
            SS_LEFT = 0x0,
            SS_CENTER = 0x1,
            SS_RIGHT = 0x2,
            SS_ICON = 0x3,
            SS_BLACKRECT = 0x4,
            SS_GRAYRECT = 0x5,
            SS_WHITERECT = 0x6,
            SS_BLACKFRAME = 0x7,
            SS_GRAYFRAME = 0x8,
            SS_WHITEFRAME = 0x9,
            SS_USERITEM = 0xA,
            SS_SIMPLE = 0xB,
            SS_LEFTNOWORDWRAP = 0xC,
            SS_OWNERDRAW = 0xD,
            SS_BITMAP = 0xE,
            SS_ENHMETAFILE = 0xF,
            SS_ETCHEDHORZ = 0x10,
            SS_ETCHEDVERT = 0x11,
            SS_ETCHEDFRAME = 0x12,
            SS_TYPEMASK = 0x1F,
            SS_REALSIZECONTROL = 0x40,
            SS_NOPREFIX = 0x80,
            SS_NOTIFY = 0x100,
            SS_CENTERIMAGE = 0x200,
            SS_RIGHTJUST = 0x400,
            SS_REALSIZEIMAGE = 0x800,
            SS_SUNKEN = 0x1000,
            SS_EDITCONTROL = 0x2000,
            SS_ENDELLIPSIS = 0x4000,
            SS_PATHELLIPSIS = 0x8000,
            SS_WORDELLIPSIS = 0xC000,
            SS_ELLIPSISMASK = 0xC000,


            // Dialog Styles
            DS_ABSALIGN = 0x1,
            DS_SYSMODAL = 0x2,
            DS_LOCALEDIT = 0x20,
            DS_SETFONT = 0x40,
            DS_MODALFRAME = 0x80,
            DS_NOIDLEMSG = 0x100,
            DS_SETFOREGROUND = 0x200,
            DS_3DLOOK = 0x4,
            DS_FIXEDSYS = 0x8,
            DS_NOFAILCREATE = 0x10,
            DS_CONTROL = 0x400,
            DS_CENTER = 0x800,
            DS_CENTERMOUSE = 0x1000,
            DS_CONTEXTHELP = 0x2000,
            DS_SHELLFONT = (DS_SETFONT | DS_FIXEDSYS),

            // Listbox Styles
            LBS_NOTIFY = 0x1,
            LBS_SORT = 0x2,
            LBS_NOREDRAW = 0x4,
            LBS_MULTIPLESEL = 0x8,
            LBS_OWNERDRAWFIXED = 0x10,
            LBS_OWNERDRAWVARIABLE = 0x20,
            LBS_HASSTRINGS = 0x40,
            LBS_USETABSTOPS = 0x80,
            LBS_NOINTEGRALHEIGHT = 0x100,
            LBS_MULTICOLUMN = 0x200,
            LBS_WANTKEYBOARDINPUT = 0x400,
            LBS_EXTENDEDSEL = 0x800,
            LBS_DISABLENOSCROLL = 0x1000,
            LBS_NODATA = 0x2000,
            LBS_NOSEL = 0x4000,
            LBS_COMBOBOX = 0x8000,
            LBS_STANDARD = (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER),

            // combobox styles
            CBS_SIMPLE = 0x1,
            CBS_DROPDOWN = 0x2,
            CBS_DROPDOWNLIST = 0x3,
            CBS_OWNERDRAWFIXED = 0x10,
            CBS_OWNERDRAWVARIABLE = 0x20,
            CBS_AUTOHSCROLL = 0x40,
            CBS_OEMCONVERT = 0x80,
            CBS_SORT = 0x100,
            CBS_HASSTRINGS = 0x200,
            CBS_NOINTEGRALHEIGHT = 0x400,
            CBS_DISABLENOSCROLL = 0x800,
            CBS_UPPERCASE = 0x2000,
            CBS_LOWERCASE = 0x4000,


            // Scroll Bar Styles
            SBS_HORZ = 0x0,
            SBS_VERT = 0x1,
            SBS_TOPALIGN = 0x2,
            SBS_LEFTALIGN = 0x2,
            SBS_BOTTOMALIGN = 0x4,
            SBS_RIGHTALIGN = 0x4,
            SBS_SIZEBOXTOPLEFTALIGN = 0x2,
            SBS_SIZEBOXBOTTOMRIGHTALIGN = 0x4,
            SBS_SIZEBOX = 0x8,
            SBS_SIZEGRIP = 0x10,

            //treeview styles

            TVS_HASBUTTONS = 0x1,
            TVS_HASLINES = 0x2,
            TVS_LINESATROOT = 0x4,
            TVS_EDITLABELS = 0x8,
            TVS_DISABLEDRAGDROP = 0x10,
            TVS_SHOWSELALWAYS = 0x20,
            TVS_RTLREADING = 0x40,
            TVS_NOTOOLTIPS = 0x80,
            TVS_CHECKBOXES = 0x100,
            TVS_TRACKSELECT = 0x200,
            TVS_SINGLEEXPAND = 0x400,
            TVS_INFOTIP = 0x800,
            TVS_FULLROWSELECT = 0x1000,
            TVS_NOSCROLL = 0x2000,
            TVS_NONEVENHEIGHT = 0x4000,
            TVS_NOHSCROLL = 0x8000,


            //tab control styles
            TCS_SCROLLOPPOSITE = 0x1,
            TCS_BOTTOM = 0x2,
            TCS_RIGHT = 0x2,
            TCS_MULTISELECT = 0x4,
            TCS_FLATBUTTONS = 0x8,
            TCS_FORCEICONLEFT = 0x10,
            TCS_FORCELABELLEFT = 0x20,
            TCS_HOTTRACK = 0x40,
            TCS_VERTICAL = 0x80,
            TCS_TABS = 0x0,
            TCS_BUTTONS = 0x100,
            TCS_SINGLELINE = 0x0,
            TCS_MULTILINE = 0x200,
            TCS_RIGHTJUSTIFY = 0x0,
            TCS_FIXEDWIDTH = 0x400,
            TCS_RAGGEDRIGHT = 0x800,
            TCS_FOCUSONBUTTONDOWN = 0x1000,
            TCS_OWNERDRAWFIXED = 0x2000,
            TCS_TOOLTIPS = 0x4000,
            TCS_FOCUSNEVER = 0x8000,

            //spin styles
            UDS_WRAP = 0x1,
            UDS_SETBUDDYINT = 0x2,
            UDS_ALIGNRIGHT = 0x4,
            UDS_ALIGNLEFT = 0x8,
            UDS_AUTOBUDDY = 0x10,
            UDS_ARROWKEYS = 0x20,
            UDS_HORZ = 0x40,
            UDS_NOTHOUSANDS = 0x80,
            UDS_HOTTRACK = 0x100,

            //progress styles
            PBS_SMOOTH = 0x1,
            PBS_VERTICAL = 0x4,


            //list view styles
            LVS_ICON = 0x0,
            LVS_REPORT = 0x1,
            LVS_SMALLICON = 0x2,
            LVS_LIST = 0x3,
            LVS_TYPEMASK = 0x3,
            LVS_SINGLESEL = 0x4,
            LVS_SHOWSELALWAYS = 0x8,
            LVS_SORTASCENDING = 0x10,
            LVS_SORTDESCENDING = 0x20,
            LVS_SHAREIMAGELISTS = 0x40,
            LVS_NOLABELWRAP = 0x80,
            LVS_AUTOARRANGE = 0x100,
            LVS_EDITLABELS = 0x200,
            LVS_OWNERDATA = 0x1000,
            LVS_NOSCROLL = 0x2000,
            LVS_TYPESTYLEMASK = 0xFC00,
            LVS_ALIGNTOP = 0x0,
            LVS_ALIGNLEFT = 0x800,
            LVS_ALIGNMASK = 0xC00,
            LVS_OWNERDRAWFIXED = 0x400,
            LVS_NOCOLUMNHEADER = 0x4000,
            LVS_NOSORTHEADER = 0x8000,

            ACS_CENTER = 0x1,
            ACS_TRANSPARENT = 0x2,
            ACS_AUTOPLAY = 0x4,
            ACS_TIMER = 0x8
        }

    }
}

@Washi1337
Copy link
Owner

Washi1337 commented Nov 25, 2021

Maybe I am missing something, but that code doesn't do any writing / updating of the resource directory, only parsing?

Reconstructing the resources directory of this particular PE file (notepad.exe.mui) works fine for me as well using the code below. It must mean the code you use to edit the contents of that particular resource is not conforming to the format of an RT_DIALOG resource.

Bare minimum example code for reconstructing the resources directory
// Read raw PE file. 
var file = PEFile.FromFile("/tmp/notepad.exe.mui");
var image = PEImage.FromFile(file);

/* ... Do something here with image.Resources ... */

// Reconstruct rsrc section.
var rsrc = file.Sections.First(s => s.Name == ".rsrc");
var contents = new ResourceDirectoryBuffer();
contents.AddDirectory(image.Resources!);
rsrc.Contents = contents;

// Update optional header.
file.AlignSections();
file.OptionalHeader.DataDirectories[(int) DataDirectoryIndex.ResourceDirectory]
    = new DataDirectory(contents.DataEntryTable.Rva, contents.DataEntryTable.GetPhysicalSize());

// Save
file.Write("/tmp/notepad2.exe.mui");

Remember that AsmResolver does not have rich support for these types of resources in the Win32Resources package (#66), and as such it does not do any verification on the data you construct. If you are editing a resource file, then you are currently responsible for (re)constructing it correctly.

@laomms
Copy link
Author

laomms commented Nov 25, 2021

The notepad.exe.mui sample, I change

                byte[] bytesWrite = content.Take(index - 1).ToArray().Concat(content.Skip(index - 1 + byteSearch.Length).Take(content.Length - index - byteSearch.Length + 1).ToArray()).ToArray();
                using (var stream = new MemoryStream())
                {
                    var writer = new BinaryStreamWriter(stream);
                    writer.WriteUInt16((ushort)bytesWrite.Length);
                    writer.WriteBytes(bytesWrite);
                    writer.Align(4);
                    dataEntry.Contents = new AsmResolver.DataSegment(stream.ToArray());
                    var rsrc = file.Sections.First(s => s.Name == ".rsrc");
                    var newContents = new ResourceDirectoryBuffer();
                    newContents.AddDirectory(image.Resources);
                    rsrc.Contents = newContents;

                    file.AlignSections();
                    file.OptionalHeader.DataDirectories[(int)DataDirectoryIndex.ResourceDirectory] = new DataDirectory(newContents.DirectoryTable.Rva, newContents.DirectoryTable.GetPhysicalSize());
                    file.Write(output);
                }

to

                byte[] bytesWrite = content.Take(index - 1).ToArray().Concat(content.Skip(index - 1 + byteSearch.Length).Take(content.Length - index - byteSearch.Length + 1).ToArray()).ToArray();
                dataEntry.Contents = new AsmResolver.DataSegment(bytesWrite);
                var rsrc = file.Sections.First(s => s.Name == ".rsrc");
                var newContents = new ResourceDirectoryBuffer();
                newContents.AddDirectory(image.Resources!);
                rsrc.Contents = newContents;
                file.AlignSections();
                file.OptionalHeader.DataDirectories[(int)DataDirectoryIndex.ResourceDirectory] = new DataDirectory(newContents.DirectoryTable.Rva, newContents.DirectoryTable.GetPhysicalSize());
                file.Write(output);

It update successful。
byte[] to MemoryStream and back to byte[], It's four bytes more than the original array,

@Washi1337
Copy link
Owner

It update successful。
byte[] to MemoryStream and back to byte[], It's four bytes more than the original array,

I am not sure what this statement means. Does it mean that it has solved your problem? If so, can I close the issue? If not, can you clarify what you mean by this?

Remember that reconstructing a PE file without applying any changes does not always mean the exact same file will be produced. AsmResolver will (re)do some calculations of offsets as it lays out the sections. It is not guaranteed to follow the exact same linkage as the original compiler has done for the original program.

@laomms
Copy link
Author

laomms commented Nov 25, 2021

yes, you can close the issue.

@Washi1337
Copy link
Owner

Perfect! Glad you got it working!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pe Issues related to AsmResolver.PE win32resources Issues related to AsmResolver.PE.Win32Resources
Projects
None yet
Development

No branches or pull requests

2 participants