Bavi_H's Blog

Fix Notepad's CR CR LF bug with a hex editor


by Bavi_H, 11/14/2010

(Update 10/18/2015: Added information for the Windows 10 (64-bit) version of Notepad.)

By changing one bit in notepad.exe, you can prevent Notepad from inserting CR CR LF characters at wrap points.

If you are familiar with a hex editor, you can use the steps below to modify the Windows XP, Windows 7 (64-bit), Windows 8 (64-bit), or Windows 10 (64-bit) version of Notepad. Proceed carefully and be sure to work with a copy of Notepad, not the original.

Windows XP

  1. Make a copy of notepad.exe.
  2. Open your copy of notepad.exe in a hex editor and go to offset 40D1. Make sure you see the following values.
    The relevant function call starts at offset 40C9 with: 8B 35 40 12 00 01 50 6A. The value to be changed is at offset 40D1: 01. The relevant function call continues from offset 40D2 with: 68 C8 00 00 00 FF 35 38 98 00 01 FF D6.
    The relevant function call is in black. The value to be changed is in red.
  3. Change the byte at offset 40D1 from 01 to 00.

Windows 7 (64-bit)

  1. You need to make a copy of these two files:
    c:\windows\system32\notepad.exe
    c:\windows\system32\en-US\notepad.exe.mui

    Choose a location to keep your modified copy of Notepad, and copy notepad.exe to that location. In the same location, make a subfolder called en-US and copy notepad.exe.mui into it. (If your Windows uses a language other than US English, you might need to change the "en-US" in these steps to the language code your computer uses.)

  2. Open your copy of notepad.exe in a hex editor and go to offset 8134. Make sure you see the following values.

    Starting at offset 812C: BA C8 00 00 00 45 8D 41.
    Then, at offset 8134, the value to be changed is: 01.
    Then, continuing with offset 8135: FF 15.

  3. Change the byte at offset 8134 from 01 to 00.

Windows 8 (64-bit)

  1. You need to make a copy of these two files:
    c:\windows\system32\notepad.exe
    c:\windows\system32\en-US\notepad.exe.mui

    Choose a location to keep your modified copy of Notepad, and copy notepad.exe to that location. In the same location, make a subfolder called en-US and copy notepad.exe.mui into it. (If your Windows uses a language other than US English, you might need to change the "en-US" in these steps to the language code your computer uses.)

  2. Open your copy of notepad.exe in a hex editor and go to offset 14DEE. Make sure you see the following values.
    The relevant function call starts at offset 14DDC with: 48 8B 0D 8D 46 00 00 45 33 C9 BA C8 00 00 00 45 8D 41. The value to be changed is at offset 14DEE: 01. The relevant function call continues from offset 14DEF with: FF 15 1B 8B 00 00.
    The relevant function call is in black. The value to be changed is in red.
  3. Change the byte at offset 14DEE from 01 to 00.

Windows 10 (64-bit)

  1. You need to make a copy of these two files:
    c:\windows\system32\notepad.exe
    c:\windows\system32\en-US\notepad.exe.mui

    Choose a location to keep your modified copy of Notepad, and copy notepad.exe to that location. In the same location, make a subfolder called en-US and copy notepad.exe.mui into it. (If your Windows uses a language other than US English, you might need to change the "en-US" in these steps to the language code your computer uses.)

  2. Open your copy of notepad.exe in a hex editor and go to offset 3DC6. Make sure you see the following values.
    The relevant function call starts at offset 3DB4 with: 48 8B 0D 05 7A 01 00 45 33 C9 BA C8 00 00 00 45 8D 41. The value to be changed is at offset 3DC6: 01. The relevant function call continues from offset 3DB5 with: FF 15 93 0B 01 00.
    The relevant function call is in black. The value to be changed is in red.
  3. Change the byte at offset 3DC6 from 01 to 00.

More information

Notepad uses a multiline edit control for its text editor area. The multiline edit control includes a message EM_FMTLINES that can be used to add CR CR LF characters at wrap points or to remove all CR CR LF sequences from the text.

Windows XP

I used a debugger (OllyDbg) to look for places where Notepad sends the EM_FMTLINES message. I found several places, but only one is relevant to the hex editor modification above.

If word wrap is on when you Save or Save As, Notepad will remove any CR CR LF sequences in the display window,

01004C5D  8B35 40120001  MOV ESI,DWORD PTR DS:[<&USER32.SendMessageW>]
...
01004C94  57             PUSH EDI                     ; lParam
01004C95  57             PUSH EDI                     ; wParam = 0
01004C96  68 C8000000    PUSH 0C8                     ; Message = EM_FMTLINES
01004C9B  FF35 38980001  PUSH DWORD PTR DS:[1009838]  ; hWnd
01004CA1  FFD6           CALL ESI                     ; SendMessageW

save the file,

...
01004C2A  FF15 3C110001  CALL DWORD PTR DS:[<&KERNEL32.WriteFile>]  ; WriteFile

then re-insert CR CR LF characters at the wrap points.

...
01004CC9  8B35 40120001  MOV ESI,DWORD PTR DS:[<&USER32.SendMessageW>]
01004CCF  50             PUSH EAX                     ; lParam
01004CD0  6A 01          PUSH 1                       ; wParam = 1
01004CD2  68 C8000000    PUSH 0C8                     ; Message = EM_FMTLINES
01004CD7  FF35 38980001  PUSH DWORD PTR DS:[1009838]  ; hWnd
01004CDD  FFD6           CALL ESI                     ; SendMessageW

The modification made with the hex editor above changes the wParam argument in the last call from a 1 to a 0. This prevents the CR CR LF characters from being added at the wrap points. (It tells the edit control to remove all CR CR LF sequences again, but since that was already done, it has no effect.)

Windows 8 (64-bit)

I first examined the Windows 8 version of Notepad using just a hex editor, looking for the same function call bytes that Windows XP uses. I couldn't find the entire function call, so I looked for smaller segments, like just the C8 00 constant that signifies EM_FMTLINES. I found some interesting looking places, but when I made some test edits and tried to run my copy of notepad.exe, no window opened at all. In fact, I discovered trying to use an exact copy of notepad.exe outside of its original folder didn't work either, no window opened.

I found a post by someone else trying to use a copy of notepad.exe outside of its original folder: The Case of the Notepad that Wouldn't Run. In this post, the author discovered the original notepad.exe loads a file called notepad.exe.mui from the subfolder en-US. An .mui file stores the text and shortcut keys the program uses for a specific language. To get notepad.exe to run in another folder, you have to make a en-US subfolder and put a copy of notepad.exe.mui in it.

OllyDbg isn't yet available for 64-bit programs. I found another debugger x64dbg and started looking at the Windows 8 version of Notepad. Note: x64dbg is in alpha and it sometimes crashed or behaved inconsistently when I used it.

I noticed the way parameters are stored before calling a function is different in 64-bit programs. In the Windows XP notepad.exe, the parameters are pushed to the stack, but in the Windows 8 notepad.exe, parameters are stored in registers. I found some Microsoft documents that confirm how function calls work in 64-bit programs: Overview of x64 Calling Conventions and Parameter Passing.

Once I knew the exact registers that were used, I started looking for the EM_FMTLINES parameter by searching for mov rdx,c8 and then, following the pattern of other calls I saw, by searching for mov edx,c8.

Here's the call that inserts CR CR LF characters after a save:

48 8B 0D 8D 46 00 00   mov rcx,qword ptr ds:[7FF6DA9EA070]   ; hWnd
45 33 C9               xor r9d,r9d                           ; lParam = 0
BA C8 00 00 00         mov edx,C8                            ; Message = EM_FMTLINES
45 8D 41 01            lea r8d,dword ptr ds:[r9+1]           ; wParam = 1
FF 15 1B 8B 00 00      call qword ptr ds:[<&SendMessageW>]

To learn about why the LEA instruction might be used here, read What's the purpose of the LEA instruction?

As in the Windows XP Notepad modification, I changed the wParam value from 1 to 0.

Windows 7 (64-bit) and Windows 10 (64-bit)

I didn't use a debugger on the Windows 7 and Windows 10 versions of Notepad. I just used a hex editor to find places where mov edx,c8 was potentially used (BA C8 00 00 00) and looked nearby to see if there was a 01 value.

Links

Notepad bug: Saving with word wrap on inserts CR CR LF characters in the display window
bavih.blogspot.com/2008/07/notepad-bug.html
My original investigation into Notepad's CR CR LF bug.

EM_FMTLINES Message
https://msdn.microsoft.com/en-us/library/bb761570(VS.85).aspx
MSDN documentation of the EM_FMTLINES message for a multiline edit control.

OllyDbg
www.ollydbg.de
A Windows debugger that automatically shows relevant values and names next to disassembled code.

The Case of the Notepad that Wouldn't Run
blogs.technet.com/b/markrussinovich/archive/2006/10/01/the-case-of-the-notepad-that-wouldn_2700_t-run.aspx
In this blog post, Mark Russinovich attempted to make a copy of Notepad look like a setup program to demonstrate a security warning message. He couldn't get that to work, but one thing he found out was that notepad.exe needs a en-US\notepad.exe.mui file in order to start.

Overview of x64 Calling Conventions and Parameter Passing
https://msdn.microsoft.com/en-us/library/ms235286.aspx
https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
These documents explain how 64-bit programs pass parameters in function calls.

x64dbg
x64dbg.com
A 64-bit debugger. Note: x64dbg is in alpha and it sometimes crashed or behaved inconsistently when I used it.

What's the purpose of the LEA instruction?
stackoverflow.com/questions/1658294/whats-the-purpose-of-the-lea-instruction
Various answers explain the LEA instruction can be appealing for its arithmetic abilities that don't affect flags.

Revision History

11/14/2010: Original version.
9/20/2015: Added information for the Windows 8 (64-bit) version of Notepad. Removed the extra information about the non-matching EM_FMTLINES calls in the Windows XP version.
9/21/2015: Added information for the Windows 7 (64-bit) version of Notepad.
10/18/2015: Added information for the Windows 10 (64-bit) version of Notepad. Added clarifications that the Windows 7 and 8 versions I looked at were 64-bit.