├── .gitattributes
├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── .idea
└── .idea.ExtensionBlocks
│ └── .idea
│ ├── .gitignore
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── ExtensionBlocks.Test
├── ExtensionBlocks.Test.csproj
├── ExtensionBlocks.Test.v2.ncrunchproject
└── TestMain.cs
├── ExtensionBlocks.Test2
├── App.config
├── ExtensionBlocks.Test2.csproj
└── Program.cs
├── ExtensionBlocks.sln
├── ExtensionBlocks.v2.ncrunchsolution
├── ExtensionBlocks.v3.ncrunchsolution
├── ExtensionBlocks
├── Beef0000.cs
├── Beef0001.cs
├── Beef0002.cs
├── Beef0003.cs
├── Beef0004.cs
├── Beef0005.cs
├── Beef0006.cs
├── Beef0008.cs
├── Beef0009.cs
├── Beef000a.cs
├── Beef000c.cs
├── Beef000e.cs
├── Beef0010.cs
├── Beef0013.cs
├── Beef0014.cs
├── Beef0016.cs
├── Beef0017.cs
├── Beef0019.cs
├── Beef001a.cs
├── Beef001b.cs
├── Beef001d.cs
├── Beef001e.cs
├── Beef0021.cs
├── Beef0024.cs
├── Beef0025.cs
├── Beef0026.cs
├── Beef0027.cs
├── Beef0029.cs
├── BeefBase.cs
├── BeefPlaceHolder.cs
├── BeefUnknown.cs
├── ExtensionBlocks.csproj
├── ExtensionBlocks.v2.ncrunchproject
├── IExtensionBlock.cs
├── IShellBag.cs
├── MFTInformation.cs
├── PropertySheet.cs
├── PropertyStore.cs
├── ShellBag.cs
├── ShellBag0X31.cs
└── Utils.cs
├── License.md
├── README.md
└── icon.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2 |
3 | name: publish
4 | on:
5 | workflow_dispatch: # Allow running the workflow manually from the GitHub UI
6 | push:
7 | branches:
8 | - 'main' # Run the workflow when pushing to the main branch
9 | pull_request:
10 | branches:
11 | - '*' # Run the workflow for all pull requests
12 | release:
13 | types:
14 | - published # Run the workflow when a new GitHub release is published
15 |
16 | env:
17 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
18 | DOTNET_NOLOGO: true
19 | NuGetDirectory: ${{ github.workspace}}/nuget
20 |
21 | defaults:
22 | run:
23 | shell: pwsh
24 |
25 | jobs:
26 | create_nuget:
27 | runs-on: ubuntu-latest
28 | steps:
29 | - uses: actions/checkout@v4
30 | with:
31 | fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
32 |
33 | # Install the .NET SDK indicated in the global.json file
34 | - name: Setup .NET
35 | uses: actions/setup-dotnet@v4
36 |
37 | # Create the NuGet package in the folder from the environment variable NuGetDirectory
38 | - run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
39 |
40 | # Publish the NuGet package as an artifact,so they can be used in the following jobs
41 | - uses: actions/upload-artifact@v4
42 | with:
43 | name: nuget
44 | if-no-files-found: error
45 | retention-days: 7
46 | path: ${{ env.NuGetDirectory }}/*.nupkg
47 |
48 | validate_nuget:
49 | runs-on: ubuntu-latest
50 | needs: [ create_nuget ]
51 | steps:
52 | # Install the .NET SDK indicated in the global.json file
53 | - name: Setup .NET
54 | uses: actions/setup-dotnet@v4
55 |
56 | # Download the NuGet package created in the previous job
57 | - uses: actions/download-artifact@v4
58 | with:
59 | name: nuget
60 | path: ${{ env.NuGetDirectory }}
61 |
62 | - name: Install nuget validator
63 | run: dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global
64 |
65 | # Validate metadata and content of the NuGet package
66 | # https://www.nuget.org/packages/Meziantou.Framework.NuGetPackageValidation.Tool#readme-body-tab
67 | # If some rules are not applicable, you can disable them
68 | # using the --excluded-rules or --excluded-rule-ids option
69 | - name: Validate package
70 | run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg")
71 |
72 | run_test:
73 | runs-on: ubuntu-latest
74 | steps:
75 | - uses: actions/checkout@v4
76 | - name: Setup .NET
77 | uses: actions/setup-dotnet@v4
78 | - name: Run tests
79 | run: dotnet test --configuration Release
80 |
81 | deploy:
82 | # Publish only when creating a GitHub Release
83 | # https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
84 | # You can update this logic if you want to manage releases differently
85 | if: github.event_name == 'release'
86 | runs-on: ubuntu-latest
87 | needs: [ validate_nuget ]
88 | steps:
89 | # Download the NuGet package created in the previous job
90 | - uses: actions/download-artifact@v4
91 | with:
92 | name: nuget
93 | path: ${{ env.NuGetDirectory }}
94 |
95 | # Install the .NET SDK indicated in the global.json file
96 | - name: Setup .NET Core
97 | uses: actions/setup-dotnet@v4
98 |
99 | # Publish all NuGet packages to NuGet.org
100 | # Use --skip-duplicate to prevent errors if a package with the same version already exists.
101 | # If you retry a failed workflow, already published packages will be skipped without error.
102 | - name: Publish NuGet package
103 | run: |
104 | foreach($file in (Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg)) {
105 | dotnet nuget push $file --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate
106 | }
107 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | # DNX
42 | project.lock.json
43 | artifacts/
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding add-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | ## TODO: Comment the next line if you want to checkin your
137 | ## web deploy settings but do note that will include unencrypted
138 | ## passwords
139 | #*.pubxml
140 |
141 | *.publishproj
142 |
143 | # NuGet Packages
144 | *.nupkg
145 | # The packages folder can be ignored because of Package Restore
146 | **/packages/*
147 | # except build/, which is used as an MSBuild target.
148 | !**/packages/build/
149 | # Uncomment if necessary however generally it will be regenerated when needed
150 | #!**/packages/repositories.config
151 |
152 | # Windows Azure Build Output
153 | csx/
154 | *.build.csdef
155 |
156 | # Windows Store app package directory
157 | AppPackages/
158 |
159 | # Visual Studio cache files
160 | # files ending in .cache can be ignored
161 | *.[Cc]ache
162 | # but keep track of directories ending in .cache
163 | !*.[Cc]ache/
164 |
165 | # Others
166 | ClientBin/
167 | [Ss]tyle[Cc]op.*
168 | ~$*
169 | *~
170 | *.dbmdl
171 | *.dbproj.schemaview
172 | *.pfx
173 | *.publishsettings
174 | node_modules/
175 | orleans.codegen.cs
176 |
177 | # RIA/Silverlight projects
178 | Generated_Code/
179 |
180 | # Backup & report files from converting an old project file
181 | # to a newer Visual Studio version. Backup files are not needed,
182 | # because we have git ;-)
183 | _UpgradeReport_Files/
184 | Backup*/
185 | UpgradeLog*.XML
186 | UpgradeLog*.htm
187 |
188 | # SQL Server files
189 | *.mdf
190 | *.ldf
191 |
192 | # Business Intelligence projects
193 | *.rdl.data
194 | *.bim.layout
195 | *.bim_*.settings
196 |
197 | # Microsoft Fakes
198 | FakesAssemblies/
199 |
200 | # Node.js Tools for Visual Studio
201 | .ntvs_analysis.dat
202 |
203 | # Visual Studio 6 build log
204 | *.plg
205 |
206 | # Visual Studio 6 workspace options file
207 | *.opt
208 |
209 | # LightSwitch generated files
210 | GeneratedArtifacts/
211 | _Pvt_Extensions/
212 | ModelManifest.xml
213 |
--------------------------------------------------------------------------------
/.idea/.idea.ExtensionBlocks/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /modules.xml
6 | /contentModel.xml
7 | /projectSettingsUpdater.xml
8 | /.idea.ExtensionBlocks.iml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/.idea/.idea.ExtensionBlocks/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.ExtensionBlocks/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.ExtensionBlocks/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test/ExtensionBlocks.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net462;net6.0
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test/ExtensionBlocks.Test.v2.ncrunchproject:
--------------------------------------------------------------------------------
1 |
2 | true
3 | 1000
4 | false
5 | false
6 | false
7 | true
8 | false
9 | false
10 | false
11 | false
12 | false
13 | true
14 | false
15 | true
16 | false
17 | true
18 | true
19 | true
20 | 60000
21 |
22 |
23 |
24 | AutoDetect
25 | STA
26 | x86
27 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test/TestMain.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using NUnit.Framework;
9 |
10 | namespace ExtensionBlocks.Test
11 | {
12 | [TestFixture]
13 | public class TestMain
14 | {
15 | [Test]
16 | public void foobar()
17 | {
18 | var fooBytes = File.ReadAllBytes(@"C:\Temp\beef0024.bin");
19 |
20 |
21 | var aa = Utils.GetExtensionBlockFromBytes(0xbeef0024, fooBytes);
22 |
23 | }
24 |
25 |
26 | [Test]
27 | public void guidLookup()
28 | {
29 |
30 | var aaa = Utils.GetDescriptionFromGuidAndKey("de35258c-c695-4cbc-b982-38b0ad24ced0", 2);
31 |
32 | Assert.Equals(aaa,"Shell Omit From View");
33 |
34 |
35 | // {"de35258c-c695-4cbc-b982-38b0ad24ced0",new HashSet()
36 | // {
37 | // new IdName (2, "Shell Omit From View"),
38 | // } },
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test2/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test2/ExtensionBlocks.Test2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net462;net6.0
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ExtensionBlocks.Test2/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ExtensionBlocks.Test2
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var fooBytes = File.ReadAllBytes(@"C:\Temp\prop.bin");
16 |
17 | var foo = new PropertyStore(fooBytes);
18 | Debug.WriteLine(foo);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ExtensionBlocks.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29215.179
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionBlocks", "ExtensionBlocks\ExtensionBlocks.csproj", "{1F3896D7-60D9-4D39-BE3E-55071D157D39}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionBlocks.Test", "ExtensionBlocks.Test\ExtensionBlocks.Test.csproj", "{7869D7FF-6BD3-41BC-87AC-F8AF28AE9F30}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionBlocks.Test2", "ExtensionBlocks.Test2\ExtensionBlocks.Test2.csproj", "{BBFBA517-895C-4B94-A2A2-28252A390F1A}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {1F3896D7-60D9-4D39-BE3E-55071D157D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {1F3896D7-60D9-4D39-BE3E-55071D157D39}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {1F3896D7-60D9-4D39-BE3E-55071D157D39}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {1F3896D7-60D9-4D39-BE3E-55071D157D39}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {7869D7FF-6BD3-41BC-87AC-F8AF28AE9F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {7869D7FF-6BD3-41BC-87AC-F8AF28AE9F30}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {7869D7FF-6BD3-41BC-87AC-F8AF28AE9F30}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {7869D7FF-6BD3-41BC-87AC-F8AF28AE9F30}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {BBFBA517-895C-4B94-A2A2-28252A390F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {BBFBA517-895C-4B94-A2A2-28252A390F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {BBFBA517-895C-4B94-A2A2-28252A390F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {BBFBA517-895C-4B94-A2A2-28252A390F1A}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {1EFC709B-40FB-4C31-ADD6-24A62191D72D}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/ExtensionBlocks.v2.ncrunchsolution:
--------------------------------------------------------------------------------
1 |
2 | 1
3 | false
4 | false
5 | true
6 | UseDynamicAnalysis
7 | UseStaticAnalysis
8 | UseStaticAnalysis
9 | UseStaticAnalysis
10 | UseDynamicAnalysis
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ExtensionBlocks.v3.ncrunchsolution:
--------------------------------------------------------------------------------
1 |
2 |
3 | False
4 | True
5 |
6 |
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0000.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0000 : BeefBase
8 | {
9 | public Beef0000(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0000)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0000 but is 0x{Signature:X}");
15 | }
16 |
17 | GUID1 = Utils.ExtractGuidFromShellItem(rawBytes.Skip(8).Take(16).ToArray());
18 |
19 | GUID1Folder = Utils.GetFolderNameFromGuid(GUID1);
20 |
21 | GUID2 = Utils.ExtractGuidFromShellItem(rawBytes.Skip(24).Take(16).ToArray());
22 |
23 | GUID2Folder = Utils.GetFolderNameFromGuid(GUID2);
24 |
25 | VersionOffset = BitConverter.ToInt16(rawBytes, 40);
26 | }
27 |
28 | public string GUID1 { get; }
29 |
30 | public string GUID1Folder { get; }
31 |
32 | public string GUID2 { get; }
33 |
34 | public string GUID2Folder { get; }
35 |
36 | public override string ToString()
37 | {
38 | var sb = new StringBuilder();
39 |
40 | sb.AppendLine(base.ToString());
41 |
42 | sb.AppendLine();
43 |
44 | sb.AppendLine($"GUID 1: {GUID1}");
45 | sb.AppendLine($"GUID 1 Folder: {GUID1Folder}");
46 | sb.AppendLine($"GUID 2: {GUID2}");
47 | sb.AppendLine($"GUID 2 Folder: {GUID2Folder}");
48 |
49 | return sb.ToString();
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0001.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef0001 : BeefBase
6 | {
7 | public Beef0001(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0002.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef0002 : BeefBase
6 | {
7 | public Beef0002(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0003.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0003 : BeefBase
8 | {
9 | public Beef0003(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0003)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0003 but is 0x{Signature:X}");
15 | }
16 |
17 | GUID1 = Utils.ExtractGuidFromShellItem(rawBytes.Skip(8).Take(16).ToArray());
18 |
19 | GUID1Folder = Utils.GetFolderNameFromGuid(GUID1);
20 |
21 | VersionOffset = BitConverter.ToInt16(rawBytes, 24);
22 | }
23 |
24 | public string GUID1 { get; }
25 |
26 | public string GUID1Folder { get; }
27 |
28 | public override string ToString()
29 | {
30 | var sb = new StringBuilder();
31 |
32 | sb.AppendLine(base.ToString());
33 |
34 | sb.AppendLine();
35 |
36 | sb.AppendLine($"GUID 1: {GUID1}");
37 | sb.AppendLine($"GUID 1 Folder: {GUID1Folder}");
38 |
39 | return sb.ToString();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0004.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace ExtensionBlocks
7 | {
8 | public class Beef0004 : BeefBase
9 | {
10 | public Beef0004(byte[] rawBytes)
11 | : base(rawBytes)
12 | {
13 | LocalisedName = string.Empty;
14 |
15 | MFTInformation = new MFTInformation();
16 |
17 | if (Signature != 0xbeef0004)
18 | {
19 | throw new Exception($"Signature mismatch! Should be 0xbeef0004 but is 0x{Signature:X}");
20 | }
21 |
22 | var createdDate =
23 | Utils.ExtractDateTimeOffsetFromBytes(rawBytes.Skip(8).Take(4).ToArray());
24 |
25 | CreatedOnTime = createdDate;
26 |
27 | var lastAccessDate =
28 | Utils.ExtractDateTimeOffsetFromBytes(rawBytes.Skip(12).Take(4).ToArray());
29 |
30 | LastAccessTime = lastAccessDate;
31 |
32 | Identifier = BitConverter.ToInt16(rawBytes, 16);
33 |
34 | var index = 18;
35 |
36 | if (Version >= 7)
37 | {
38 | index += 2; // skip empty 2
39 |
40 | MFTInformation = new MFTInformation(rawBytes.Skip(index).Take(8).ToArray());
41 |
42 | index += 8; //skip mft data
43 |
44 | // skip 8 unknown
45 | index += 8;
46 | }
47 |
48 | var longstringsize = 0;
49 |
50 | if (Version >= 3)
51 | {
52 | index += 2;
53 | }
54 |
55 | if (Version >= 9)
56 | {
57 | //skip 4 unknown
58 | index += 4;
59 | }
60 |
61 | if (Version >= 8)
62 | {
63 | // unknown, but skip 4
64 | index += 4;
65 | }
66 |
67 | // in this case we want the rest of the extension data, but again, we arent interested in the version offset yet
68 | longstringsize = rawBytes.Length - index;
69 |
70 | var stringBytes = rawBytes.Skip(index).Take(longstringsize).ToArray();
71 |
72 | var stringpieces =
73 | Utils.GetStringsFromMultistring(stringBytes);
74 |
75 | if (stringpieces.Count == 1)
76 | {
77 | LongName = stringpieces[0];
78 | }
79 | else
80 | {
81 | LongName = String.Empty;
82 | }
83 |
84 | if (stringpieces.Count > 1)
85 | {
86 | LocalisedName = stringpieces[1];
87 | }
88 |
89 | index += longstringsize - 2;
90 |
91 | if (index > rawBytes.Length)
92 | {
93 | index = rawBytes.Length - 2;
94 | }
95 |
96 | VersionOffset = BitConverter.ToUInt16(rawBytes, index);
97 |
98 | index += 2;
99 |
100 | #if DEBUG
101 | Trace.Assert(rawBytes.Length == index, "Still have bytes in beef0004");
102 | #endif
103 | }
104 |
105 | ///
106 | /// Created time of BagPath
107 | ///
108 | public DateTimeOffset? CreatedOnTime { get; }
109 |
110 | ///
111 | /// Last access time of BagPath
112 | ///
113 | public DateTimeOffset? LastAccessTime { get; }
114 |
115 | public int Identifier { get; set; }
116 |
117 | public MFTInformation MFTInformation { get; }
118 |
119 | public string LongName { get; }
120 |
121 | public string LocalisedName { get; }
122 |
123 | public override string ToString()
124 | {
125 | var sb = new StringBuilder();
126 |
127 | sb.AppendLine(base.ToString());
128 |
129 | var os = "Unknown operating system";
130 | switch (Identifier)
131 | {
132 | case 0x14:
133 | os = "Windows XP, 2003";
134 | break;
135 | case 0x26:
136 | os = "Windows Vista";
137 | break;
138 | case 0x2a:
139 | os = "Windows 2008, 7, 8";
140 | break;
141 | case 0x2e:
142 | os = "Windows 8.1, 10";
143 | break;
144 |
145 | }
146 |
147 | sb.AppendLine($"Identifier: {Identifier:X2} ({os})");
148 |
149 | if (CreatedOnTime.HasValue)
150 | {
151 | sb.AppendLine();
152 |
153 | sb.AppendLine($"Created On: {CreatedOnTime.Value}");
154 | }
155 |
156 | if (LastAccessTime.HasValue)
157 | {
158 | sb.AppendLine($"Last Access: {LastAccessTime.Value}");
159 | }
160 |
161 | sb.AppendLine();
162 |
163 | sb.AppendLine($"Long Name: {LongName}");
164 |
165 | if (LocalisedName.Length > 0)
166 | {
167 | sb.AppendLine($"Localised Name: {LocalisedName}");
168 | }
169 |
170 | if (MFTInformation.MFTEntryNumber.HasValue)
171 | {
172 | sb.AppendLine();
173 | sb.AppendLine($"MFT Entry Number: {MFTInformation.MFTEntryNumber.Value}");
174 | }
175 |
176 | if (MFTInformation.MFTSequenceNumber.HasValue)
177 | {
178 | sb.AppendLine($"MFT Sequence Number: {MFTInformation.MFTSequenceNumber.Value}");
179 | }
180 |
181 | sb.AppendLine();
182 |
183 |
184 | if (MFTInformation.MFTEntryNumber.HasValue && MFTInformation.MFTSequenceNumber.HasValue)
185 | {
186 | if (MFTInformation.MFTEntryNumber.Value > 0 && MFTInformation.MFTSequenceNumber.Value > 0)
187 | {
188 | MFTInformation.Note = "NTFS";
189 | }
190 | }
191 |
192 | if (MFTInformation.MFTEntryNumber.HasValue && MFTInformation.MFTSequenceNumber.HasValue == false)
193 | {
194 | if (LastAccessTime.HasValue)
195 | {
196 | if (LastAccessTime.Value.Minute == 0 && LastAccessTime.Value.Second == 0 &&
197 | LastAccessTime.Value.Millisecond == 0)
198 | {
199 | MFTInformation.Note = "FAT";
200 | }
201 | else
202 | {
203 | MFTInformation.Note = "exFAT";
204 | }
205 | }
206 | }
207 |
208 |
209 | sb.AppendLine($"File system hint: {MFTInformation.Note}");
210 |
211 | return sb.ToString();
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0005.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0005 : BeefBase
8 | {
9 | public Beef0005(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0005)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0005 but is 0x{Signature:X}");
15 | }
16 |
17 | var guid = Utils.ExtractGuidFromShellItem(rawBytes.Skip(8).Take(16).ToArray());
18 |
19 | Message =
20 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
21 |
22 | VersionOffset = BitConverter.ToInt16(rawBytes, 12);
23 | }
24 |
25 | public override string ToString()
26 | {
27 | var sb = new StringBuilder();
28 |
29 | sb.AppendLine(base.ToString());
30 |
31 | return sb.ToString();
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0006.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef0006 : BeefBase
7 | {
8 | public Beef0006(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef0006)
12 | {
13 | throw new Exception($"Signature mismatch! Should be 0xbeef0006 but is 0x{Signature:X}");
14 | }
15 |
16 | var len = 0;
17 | var index = 8;
18 |
19 | while ((rawBytes[index + len] != 0x0 || rawBytes[index + len + 1] != 0x0))
20 | {
21 | len += 1;
22 | }
23 |
24 | var uname = Encoding.Unicode.GetString(rawBytes, index, len + 1);
25 |
26 | UserName = uname;
27 |
28 | index += len + 3; // move past string and end of string marker
29 |
30 | VersionOffset = BitConverter.ToInt16(rawBytes, index);
31 | }
32 |
33 | public string UserName { get; }
34 |
35 | public override string ToString()
36 | {
37 | var sb = new StringBuilder();
38 |
39 | sb.AppendLine(base.ToString());
40 |
41 | sb.AppendLine();
42 |
43 | sb.AppendLine($"User Name: {UserName}");
44 |
45 | return sb.ToString();
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0008.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef0008 : BeefBase
6 | {
7 | public Beef0008(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0009.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef0009 : BeefBase
6 | {
7 | public Beef0009(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef000a.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef000a : BeefBase
7 | {
8 | public Beef000a(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef000a)
12 | {
13 | throw new Exception($"Signature mismatch! Should be 0xbeef000a but is 0x{Signature:X}");
14 | }
15 |
16 | VersionOffset = BitConverter.ToInt16(rawBytes, 12);
17 | }
18 |
19 | public override string ToString()
20 | {
21 | var sb = new StringBuilder();
22 |
23 | sb.AppendLine(base.ToString());
24 |
25 | return sb.ToString();
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef000c.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef000c : BeefBase
6 | {
7 | public Beef000c(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef000e.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | // namespaces...
7 | namespace ExtensionBlocks
8 | {
9 | // internal classes...
10 | internal class Beef000e : BeefBase
11 | {
12 | // public constructors...
13 | public Beef000e(byte[] rawBytes)
14 | : base(rawBytes)
15 | {
16 | if (Signature != 0xbeef000e)
17 | {
18 | throw new Exception($"Signature mismatch! Should be 0xbeef000e but is {Signature}");
19 | }
20 |
21 | ExtensionBlocks = new List();
22 |
23 | Bags = new List();
24 |
25 | var rawguid1 = new byte[16];
26 |
27 | var index = 16;
28 |
29 | Array.Copy(rawBytes, index, rawguid1, 0, 16);
30 |
31 | var rawguid = Utils.ExtractGuidFromShellItem(rawguid1);
32 |
33 | var foldername = Utils.GetFolderNameFromGuid(rawguid);
34 |
35 | GUIDName = foldername;
36 |
37 | index += 16;
38 |
39 | index += 18;
40 |
41 | PropertyStores = new List();
42 |
43 | for (var i = 0; i < 3; i++)
44 | {
45 | var len = BitConverter.ToUInt32(rawBytes, index);
46 |
47 | var propStore = new PropertyStore(rawBytes.Skip(index).Take((int)len).ToArray());
48 |
49 | PropertyStores.Add(propStore);
50 |
51 | index += (int)len;
52 | }
53 |
54 |
55 |
56 | index += 11;
57 |
58 |
59 |
60 | var chunks = new List();
61 | var len1 = 0;
62 | var s1 = string.Empty;
63 |
64 | var maxLoop = 0;
65 |
66 | while (maxLoop < 3)
67 | {
68 | len1 = 0;
69 | while (rawBytes[ index + len1] != 0x00)
70 | {
71 | len1 += 1;
72 | }
73 |
74 | s1 = Encoding.ASCII.GetString(rawBytes, index, len1);
75 |
76 | chunks.Add(s1);
77 | index += len1 + 1;
78 |
79 | maxLoop += 1;
80 | }
81 |
82 |
83 |
84 | index += 16;
85 |
86 |
87 | while (rawBytes[index + len1] != 0x00)
88 | {
89 | len1 += 1;
90 | }
91 |
92 | s1 = Encoding.ASCII.GetString(rawBytes, index, len1);
93 |
94 | chunks.Add(s1);
95 | index += len1 + 1;
96 |
97 |
98 | index += 1;
99 |
100 | var extSize = 0;
101 | extSize = BitConverter.ToUInt16(rawBytes, index);
102 |
103 | var sig = BitConverter.ToUInt32(rawBytes, index + 4);
104 |
105 | var block = Utils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());
106 |
107 | ExtensionBlocks.Add(block);
108 | index += extSize;
109 |
110 | extSize = BitConverter.ToUInt16(rawBytes, index);
111 |
112 | sig = BitConverter.ToUInt32(rawBytes, index + 4);
113 |
114 | block = Utils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());
115 |
116 | ExtensionBlocks.Add(block);
117 | index += extSize;
118 |
119 | extSize = BitConverter.ToUInt16(rawBytes, index);
120 |
121 |
122 |
123 | while (extSize > 0)
124 | {
125 | var sb = new ShellBag0X31(-1, -1, rawBytes.Skip(index).Take(extSize).ToArray(), "Inside Beef000e block");
126 |
127 | Bags.Add(sb);
128 |
129 | index += extSize; // end of the bag
130 | extSize = BitConverter.ToUInt16(rawBytes, index);
131 | }
132 |
133 | index += 2; //skip empty bag
134 |
135 |
136 |
137 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
138 | }
139 |
140 | // public properties...
141 | public List ExtensionBlocks { get; set; }
142 | public string GUIDName { get; set; }
143 | public List PropertyStores { get; private set; }
144 |
145 | public List Bags;
146 |
147 | // public methods...
148 | public override string ToString()
149 | {
150 | var sb = new StringBuilder();
151 |
152 | sb.AppendLine(base.ToString());
153 |
154 | var sheetNumber = 0;
155 |
156 | sb.AppendLine($"{GUIDName}");
157 | sb.AppendLine();
158 |
159 | foreach (var propertyStore in PropertyStores)
160 | {
161 | foreach (var propertySheet in propertyStore.Sheets)
162 | {
163 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
164 |
165 | sheetNumber += 1;
166 |
167 |
168 | foreach (var propertyName in propertySheet.PropertyNames)
169 | {
170 | sb.AppendLine($"Key: {propertyName.Key}, Value: {propertyName.Value}");
171 | }
172 | }
173 | }
174 |
175 | if (ExtensionBlocks.Count > 0)
176 | {
177 | var extensionNumber = 0;
178 |
179 | sb.AppendLine();
180 | sb.AppendLine($"Extension blocks found: {ExtensionBlocks.Count}");
181 |
182 | foreach (var extensionBlock in ExtensionBlocks)
183 | {
184 | sb.AppendLine($"---------------------- Block {extensionNumber:N0} ----------------------");
185 |
186 | sb.AppendLine(extensionBlock.ToString());
187 |
188 | extensionNumber += 1;
189 | }
190 |
191 | sb.AppendLine("--------------------------------------------------");
192 | }
193 |
194 | if (Bags.Count > 0)
195 | {
196 | var bagNumber = 0;
197 |
198 | sb.AppendLine();
199 | sb.AppendLine($"Internal ShellBags found: {Bags.Count}");
200 |
201 | foreach (var bag in Bags)
202 | {
203 | sb.AppendLine($"---------------------- Bag {bagNumber:N0} ----------------------");
204 |
205 | sb.AppendLine(bag.ToString());
206 |
207 |
208 |
209 | bagNumber += 1;
210 | }
211 |
212 | sb.AppendLine("--------------------------------------------------");
213 | }
214 |
215 |
216 |
217 | return sb.ToString();
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0010.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0010 : BeefBase
8 | {
9 | public Beef0010(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0010)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0010 but is 0x{Signature:X}");
15 | }
16 |
17 |
18 | var propStore = new PropertyStore(rawBytes.Skip(16).ToArray());
19 |
20 |
21 | PropertyStore = propStore;
22 |
23 |
24 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
25 | }
26 |
27 | public PropertyStore PropertyStore { get; }
28 |
29 |
30 | public override string ToString()
31 | {
32 | var sb = new StringBuilder();
33 |
34 | sb.AppendLine(base.ToString());
35 |
36 | var sheetNumber = 0;
37 |
38 | foreach (var propertySheet in PropertyStore.Sheets)
39 | {
40 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
41 |
42 | sheetNumber += 1;
43 |
44 | //foreach (var propertyName in propertySheet.PropertyNames)
45 | //{
46 | // sb.AppendLine(string.Format("Key: {0}, Value: {1}", propertyName.Key, propertyName.Value));
47 | //}
48 | }
49 |
50 | return sb.ToString();
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0013.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef0013 : BeefBase
7 | {
8 | public Beef0013(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef0013)
12 | {
13 | throw new Exception($"Signature mismatch! Should be 0xbeef0013 but is 0x{Signature:X}");
14 | }
15 |
16 | Message = "The purpose of this extension block is unknown";
17 |
18 | VersionOffset = BitConverter.ToInt16(rawBytes, 40);
19 | }
20 |
21 |
22 | public override string ToString()
23 | {
24 | var sb = new StringBuilder();
25 |
26 | sb.AppendLine(base.ToString());
27 |
28 |
29 | return sb.ToString();
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0014.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class Beef0014 : BeefBase
6 | {
7 | public Beef0014(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | sb.AppendLine();
21 |
22 | return sb.ToString();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0016.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef0016 : BeefBase
7 | {
8 | public Beef0016(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef0016)
12 | {
13 | throw new Exception($"Signature mismatch! Should be 0xbeef0016 but is 0x{Signature:X}");
14 | }
15 |
16 | Value = Encoding.Unicode.GetString(rawBytes, 10, rawBytes.Length - 14);
17 |
18 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
19 | }
20 |
21 | public string Value { get; }
22 |
23 |
24 | public override string ToString()
25 | {
26 | var sb = new StringBuilder();
27 |
28 | sb.AppendLine(base.ToString());
29 |
30 | sb.AppendLine($"Value: {Value}");
31 |
32 | return sb.ToString();
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0017.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef0017 : BeefBase
7 | {
8 | public Beef0017(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | Message = "The purpose of this extension block is unknown";
12 |
13 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
14 | }
15 |
16 | public override string ToString()
17 | {
18 | var sb = new StringBuilder();
19 |
20 | sb.AppendLine(base.ToString());
21 |
22 | return sb.ToString();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0019.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0019 : BeefBase
8 | {
9 | public Beef0019(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0019)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0019 but is 0x{Signature:X}");
15 | }
16 |
17 | GUID1 = Utils.ExtractGuidFromShellItem(rawBytes.Skip(8).Take(16).ToArray());
18 |
19 | GUID1Folder = Utils.GetFolderNameFromGuid(GUID1);
20 |
21 | GUID2 = Utils.ExtractGuidFromShellItem(rawBytes.Skip(24).Take(16).ToArray());
22 |
23 | GUID2Folder = Utils.GetFolderNameFromGuid(GUID2);
24 |
25 | VersionOffset = BitConverter.ToInt16(rawBytes, 40);
26 | }
27 |
28 | public string GUID1 { get; }
29 |
30 | public string GUID1Folder { get; }
31 |
32 | public string GUID2 { get; }
33 |
34 | public string GUID2Folder { get; }
35 |
36 | public override string ToString()
37 | {
38 | var sb = new StringBuilder();
39 |
40 | sb.AppendLine(base.ToString());
41 |
42 | sb.AppendLine();
43 |
44 | sb.AppendLine($"GUID 1: {GUID1}");
45 | sb.AppendLine($"GUID 1 Folder: {GUID1Folder}");
46 | sb.AppendLine($"GUID 2: {GUID2}");
47 | sb.AppendLine($"GUID 2 Folder: {GUID2Folder}");
48 |
49 | return sb.ToString();
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef001a.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef001a : BeefBase
7 | {
8 | public Beef001a(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef001a)
12 | {
13 | throw new Exception($"Signature mismatch! Should be Beef001a but is 0x{Signature:X}");
14 | }
15 |
16 | var len = 0;
17 | var index = 10;
18 |
19 | while ((rawBytes[index + len] != 0x0 || rawBytes[index + len + 1] != 0x0))
20 | {
21 | len += 1;
22 | }
23 |
24 | var uname = Encoding.Unicode.GetString(rawBytes, index, len + 1);
25 |
26 | FileDocumentTypeString = uname;
27 |
28 | index += len + 3; // move past string and end of string marker
29 |
30 | //is index 24?
31 |
32 | //TODO get shell item list
33 |
34 | // if (index != 38)
35 | // {
36 | // Message =
37 | // "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
38 | // }
39 |
40 | VersionOffset = BitConverter.ToInt16(rawBytes, index);
41 | }
42 |
43 | public string FileDocumentTypeString { get; }
44 |
45 | public override string ToString()
46 | {
47 | var sb = new StringBuilder();
48 |
49 | sb.AppendLine(base.ToString());
50 |
51 | sb.AppendLine();
52 |
53 | sb.AppendLine($"File Document Type String: {FileDocumentTypeString}");
54 |
55 | return sb.ToString();
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef001b.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef001b : BeefBase
7 | {
8 | public Beef001b(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef001b)
12 | {
13 | throw new Exception($"Signature mismatch! Should be Beef001b but is 0x{Signature:X}");
14 | }
15 |
16 | var len = 0;
17 | var index = 10;
18 |
19 | while ((rawBytes[index + len] != 0x0 || rawBytes[index + len + 1] != 0x0))
20 | {
21 | len += 1;
22 | }
23 |
24 | var uname = Encoding.Unicode.GetString(rawBytes, index, len + 1);
25 |
26 | FileDocumentTypeString = uname;
27 |
28 | index += len + 3; // move past string and end of string marker
29 |
30 | //is index 24?
31 |
32 | //TODO get shell item list
33 |
34 | // if (index != 38)
35 | // {
36 | // Message =
37 | // "Unsupported Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
38 | // }
39 |
40 | VersionOffset = BitConverter.ToInt16(rawBytes, index);
41 | }
42 |
43 | public string FileDocumentTypeString { get; }
44 |
45 | public override string ToString()
46 | {
47 | var sb = new StringBuilder();
48 |
49 | sb.AppendLine(base.ToString());
50 |
51 | sb.AppendLine();
52 |
53 | sb.AppendLine($"File Document Type String: {FileDocumentTypeString}");
54 |
55 | return sb.ToString();
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef001d.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef001d : BeefBase
7 | {
8 | public Beef001d(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef001d)
12 | {
13 | throw new Exception($"Signature mismatch! Should be Beef001d but is 0x{Signature:X}");
14 | }
15 |
16 | var index = 10;
17 |
18 |
19 | var uname = Encoding.Unicode.GetString(rawBytes, index, rawBytes.Length- 10 - 2).Trim('\0');
20 |
21 | Executable = uname;
22 |
23 |
24 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length-2);
25 | }
26 |
27 | public string Executable { get; }
28 |
29 | public override string ToString()
30 | {
31 | var sb = new StringBuilder();
32 |
33 | sb.AppendLine(base.ToString());
34 |
35 | sb.AppendLine();
36 |
37 | sb.AppendLine($"Executable: {Executable}");
38 |
39 | return sb.ToString();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef001e.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef001e : BeefBase
7 | {
8 | public Beef001e(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef001e)
12 | {
13 | throw new Exception($"Signature mismatch! Should be Beef001e but is 0x{Signature:X}");
14 | }
15 |
16 | var index = 10;
17 |
18 |
19 |
20 | var uname = Encoding.Unicode.GetString(rawBytes, index, rawBytes.Length- 10 - 2).Trim('\0');
21 |
22 | PinType = uname;
23 |
24 |
25 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length-2);
26 | }
27 |
28 | public string PinType { get; }
29 |
30 | public override string ToString()
31 | {
32 | var sb = new StringBuilder();
33 |
34 | sb.AppendLine(base.ToString());
35 |
36 | sb.AppendLine();
37 |
38 | sb.AppendLine($"Pin Type: {PinType}");
39 |
40 | return sb.ToString();
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0021.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0021 : BeefBase
8 | {
9 | public Beef0021(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0021)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0021 but is 0x{Signature:X}");
15 | }
16 |
17 | var propStore = new PropertyStore(rawBytes.Skip(8).ToArray());
18 |
19 |
20 | PropertyStore = propStore;
21 |
22 |
23 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
24 | }
25 |
26 | public PropertyStore PropertyStore { get; }
27 |
28 |
29 | public override string ToString()
30 | {
31 | var sb = new StringBuilder();
32 |
33 | sb.AppendLine(base.ToString());
34 |
35 | var sheetNumber = 0;
36 |
37 | foreach (var propertySheet in PropertyStore.Sheets)
38 | {
39 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
40 |
41 | sheetNumber += 1;
42 | }
43 |
44 |
45 | return sb.ToString();
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0024.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0024 : BeefBase
8 | {
9 | public Beef0024(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0024)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0024 but is 0x{Signature:X}");
15 | }
16 |
17 | var propStore = new PropertyStore(rawBytes.Skip(8).ToArray());
18 |
19 |
20 | PropertyStore = propStore;
21 |
22 |
23 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
24 | }
25 |
26 | public PropertyStore PropertyStore { get; }
27 |
28 |
29 | public override string ToString()
30 | {
31 | var sb = new StringBuilder();
32 |
33 | sb.AppendLine(base.ToString());
34 |
35 | var sheetNumber = 0;
36 |
37 | foreach (var propertySheet in PropertyStore.Sheets)
38 | {
39 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
40 |
41 | sheetNumber += 1;
42 | }
43 |
44 |
45 | return sb.ToString();
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0025.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public class Beef0025 : BeefBase
7 | {
8 | public Beef0025(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef0025)
12 | {
13 | throw new Exception($"Signature mismatch! Should be Beef0025 but is 0x{Signature:X}");
14 | }
15 |
16 | var ft1 = DateTimeOffset.FromFileTime((long) BitConverter.ToUInt64(rawBytes, 12));
17 |
18 | FileTime1 = ft1.ToUniversalTime();
19 |
20 |
21 | var ft2 = DateTimeOffset.FromFileTime((long) BitConverter.ToUInt64(rawBytes, 20));
22 |
23 | FileTime2 = ft2.ToUniversalTime();
24 |
25 |
26 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 4);
27 | }
28 |
29 | public DateTimeOffset? FileTime1 { get; }
30 |
31 | public DateTimeOffset? FileTime2 { get; }
32 |
33 | public override string ToString()
34 | {
35 | var sb = new StringBuilder();
36 |
37 | sb.AppendLine(base.ToString());
38 | sb.AppendLine();
39 |
40 | if (FileTime1.HasValue)
41 | {
42 | sb.AppendLine(
43 | $"FileTime 1: {FileTime1.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
44 | }
45 |
46 | if (FileTime2.HasValue)
47 | {
48 | sb.AppendLine(
49 | $"FileTime 2: {FileTime2.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
50 | }
51 |
52 | return sb.ToString();
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0026.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0026 : BeefBase
8 | {
9 | public Beef0026(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0026)
13 | {
14 | throw new Exception($"Signature mismatch! Should be Beef0026 but is {Signature}");
15 | }
16 |
17 |
18 | if (rawBytes[8] == 0x11 || rawBytes[8] == 0x10|| rawBytes[8] == 0x12 || rawBytes[8] == 0x34 || rawBytes[8] == 0x31)
19 | {
20 | var ft1 = DateTimeOffset.FromFileTime((long) BitConverter.ToUInt64(rawBytes, 12)).ToUniversalTime();
21 |
22 | CreatedOn = ft1.ToUniversalTime();
23 |
24 |
25 | var ft2 = DateTimeOffset.FromFileTime((long) BitConverter.ToUInt64(rawBytes, 20)).ToUniversalTime();
26 |
27 | LastModified = ft2.ToUniversalTime();
28 |
29 |
30 | var ft3 = DateTimeOffset.FromFileTime((long) BitConverter.ToUInt64(rawBytes, 28)).ToUniversalTime();
31 |
32 | LastAccessed = ft3.ToUniversalTime();
33 |
34 |
35 | return;
36 | }
37 |
38 | var shellPropertySheetListSize = BitConverter.ToUInt16(rawBytes, 8);
39 |
40 | if (shellPropertySheetListSize > rawBytes.Length - 8)
41 | {
42 | //not enough data for there to be a property store, so bail
43 | return;
44 | }
45 |
46 | var propBytes = rawBytes.Skip(8).Take(shellPropertySheetListSize).ToArray();
47 | PropertyStore = new PropertyStore(propBytes);
48 |
49 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 4);
50 | }
51 |
52 | public PropertyStore PropertyStore { get; }
53 |
54 | public DateTimeOffset? CreatedOn { get; }
55 |
56 | public DateTimeOffset? LastModified { get; }
57 | public DateTimeOffset? LastAccessed { get; }
58 |
59 | public override string ToString()
60 | {
61 | var sb = new StringBuilder();
62 |
63 | sb.AppendLine(base.ToString());
64 | sb.AppendLine();
65 |
66 | if (CreatedOn.HasValue)
67 | {
68 | sb.AppendLine(
69 | $"Created: {CreatedOn.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
70 | }
71 |
72 | if (LastModified.HasValue)
73 | {
74 | sb.AppendLine(
75 | $"Last modified: {LastModified.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
76 | }
77 |
78 | if (LastAccessed.HasValue)
79 | {
80 | sb.AppendLine(
81 | $"Last accessed: {LastAccessed.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
82 | }
83 |
84 | if (PropertyStore != null)
85 | {
86 | if (PropertyStore.Sheets.Count > 0)
87 | {
88 | sb.AppendLine("Property Sheets");
89 |
90 | sb.AppendLine(PropertyStore.ToString());
91 | sb.AppendLine();
92 | }
93 | }
94 |
95 | return sb.ToString();
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0027.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class Beef0027 : BeefBase
8 | {
9 | public Beef0027(byte[] rawBytes)
10 | : base(rawBytes)
11 | {
12 | if (Signature != 0xbeef0027)
13 | {
14 | throw new Exception($"Signature mismatch! Should be 0xbeef0027 but is {Signature}");
15 | }
16 |
17 | var propStore = new PropertyStore(rawBytes.Skip(8).ToArray());
18 |
19 |
20 | PropertyStore = propStore;
21 |
22 |
23 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
24 | }
25 |
26 | public PropertyStore PropertyStore { get; }
27 |
28 |
29 | public override string ToString()
30 | {
31 | var sb = new StringBuilder();
32 |
33 | sb.AppendLine(base.ToString());
34 |
35 | var sheetNumber = 0;
36 |
37 | foreach (var propertySheet in PropertyStore.Sheets)
38 | {
39 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
40 |
41 | sheetNumber += 1;
42 | }
43 |
44 |
45 | return sb.ToString();
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/Beef0029.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | internal class Beef0029 : BeefBase
7 | {
8 | public Beef0029(byte[] rawBytes)
9 | : base(rawBytes)
10 | {
11 | if (Signature != 0xbeef0029)
12 | {
13 | throw new Exception($"Signature mismatch! Should be 0xbeef0029 but is {Signature}");
14 | }
15 |
16 | Message = "The purpose of this extension block is unknown";
17 |
18 | VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
19 | }
20 |
21 |
22 | public override string ToString()
23 | {
24 | var sb = new StringBuilder();
25 |
26 | sb.AppendLine(base.ToString());
27 |
28 |
29 | return sb.ToString();
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/BeefBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public abstract class BeefBase : IExtensionBlock
7 | {
8 | protected BeefBase(byte[] rawBytes)
9 | {
10 | if (rawBytes == null)
11 | {
12 | return;
13 | }
14 |
15 | Size = BitConverter.ToUInt16(rawBytes, 0);
16 |
17 | Version = BitConverter.ToUInt16(rawBytes, 2);
18 |
19 | Signature = BitConverter.ToUInt32(rawBytes, 4);
20 |
21 | Message = "";
22 | }
23 |
24 | public string Message { get; set; }
25 | public int Size { get; }
26 |
27 | public int Version { get; }
28 |
29 | public uint Signature { get; }
30 |
31 | public int VersionOffset { get; set; }
32 |
33 | public override string ToString()
34 | {
35 | var sb = new StringBuilder();
36 |
37 | sb.AppendLine($"Signature: 0x{Signature:x8}");
38 | sb.AppendLine($"Size: {Size:N0}");
39 | sb.AppendLine($"Version: {Version:N0}");
40 | sb.AppendLine($"Version Offset: 0x{VersionOffset:X2}");
41 |
42 | if (Message.Length > 0)
43 | {
44 | sb.AppendLine();
45 | sb.AppendLine($"Message: {Message}");
46 | }
47 |
48 | return sb.ToString();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/BeefPlaceHolder.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class BeefPlaceHolder : BeefBase
6 | {
7 | public BeefPlaceHolder(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | }
11 |
12 |
13 | public override string ToString()
14 | {
15 | var sb = new StringBuilder();
16 |
17 | sb.AppendLine(
18 | "This is a placeholder bag to account for additional extension blocks inside internal ShellBags");
19 |
20 |
21 | return sb.ToString();
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/BeefUnknown.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class BeefUnknown : BeefBase
6 | {
7 | public BeefUnknown(byte[] rawBytes)
8 | : base(rawBytes)
9 | {
10 | Message =
11 | "********UNKNOWN Extension block. Please report to Report to saericzimmerman@gmail.com to get it added!";
12 | }
13 |
14 | public override string ToString()
15 | {
16 | var sb = new StringBuilder();
17 |
18 | sb.AppendLine(base.ToString());
19 |
20 | return sb.ToString();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/ExtensionBlocks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 | Eric Zimmerman
7 | Eric Zimmerman
8 | Extension blocks
9 | ExtensionBlocks
10 | Eric Zimmerman
11 | https://github.com/EricZimmerman/ExtensionBlocks
12 | https://github.com/EricZimmerman/ExtensionBlocks
13 | 1.4.2
14 | MIT
15 |
16 |
17 | beef, extension block
18 | README.md
19 | icon.png
20 | True
21 |
22 | $(NoWarn);CS1591
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | all
36 | runtime; build; native; contentfiles; analyzers; buildtransitive
37 |
38 |
39 | all
40 | runtime; build; native; contentfiles; analyzers; buildtransitive
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ExtensionBlocks/ExtensionBlocks.v2.ncrunchproject:
--------------------------------------------------------------------------------
1 |
2 | true
3 | 1000
4 | false
5 | false
6 | false
7 | true
8 | false
9 | false
10 | false
11 | false
12 | false
13 | true
14 | false
15 | true
16 | false
17 | true
18 | true
19 | true
20 | 60000
21 |
22 |
23 |
24 | AutoDetect
25 | STA
26 | x86
27 |
--------------------------------------------------------------------------------
/ExtensionBlocks/IExtensionBlock.cs:
--------------------------------------------------------------------------------
1 | namespace ExtensionBlocks
2 | {
3 | public interface IExtensionBlock
4 | {
5 | int Size { get; }
6 |
7 | int Version { get; }
8 |
9 | uint Signature { get; }
10 |
11 | int VersionOffset { get; }
12 | }
13 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/IShellBag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ExtensionBlocks
5 | {
6 | public interface IShellBag
7 | {
8 | ///
9 | /// ID used for uniqueness. can be used to find a shellbag among a collection of shellbags
10 | ///
11 | string InternalId { get; }
12 |
13 | ///
14 | /// Used for tracking purposes by end user
15 | ///
16 | int NodeId { get; set; }
17 |
18 | ///
19 | /// A nice looking name vs the technical representation of the ShellBag item
20 | ///
21 | string FriendlyName { get; }
22 |
23 | ///
24 | /// ShellBag data in its unparsed format as a string of hex characters separated by -
25 | ///
26 | byte[] HexValue { get; }
27 |
28 | ///
29 | /// BagPath is the *root* path to the ShellBag.
30 | ///
31 | string BagPath { get; }
32 |
33 | ///
34 | /// AbsolutePath is the path to the ShellBag.
35 | ///
36 | string AbsolutePath { get; set; }
37 |
38 | ///
39 | /// Slot is the value name in BagPath
40 | ///
41 | int Slot { get; }
42 |
43 | ///
44 | /// True if the ShellBag is from a deleted Registry key
45 | ///
46 | bool IsDeleted { get; set; }
47 |
48 | Utils.ShellBagTypes ShellBagType { get; set; }
49 |
50 | ///
51 | /// The position this ShellBag item was opened
52 | ///
53 | int MruPosition { get; }
54 |
55 | ///
56 | /// Gets the node slot.
57 | ///
58 | /// The node slot.
59 | int NodeSlot { get; set; }
60 |
61 | ///
62 | /// Child ShellBag items for this ShellBag
63 | ///
64 | List ChildShellBags { get; set; }
65 |
66 | ///
67 | /// The name of the ShellBag. Can be based on file name, directory name, or GUID
68 | ///
69 | string Value { get; }
70 |
71 | ///
72 | /// last write time of BagPath key
73 | ///
74 | DateTimeOffset? LastWriteTime { get; set; }
75 |
76 | ///
77 | /// First explored time
78 | ///
79 | DateTimeOffset? FirstInteracted { get; set; }
80 |
81 | bool HasExplored { get; set; }
82 |
83 | ///
84 | /// First explored time
85 | ///
86 | DateTimeOffset? LastInteracted { get; set; }
87 |
88 | List ExtensionBlocks { get; set; }
89 |
90 | }
91 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/MFTInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ExtensionBlocks
4 | {
5 | public class MFTInformation
6 | {
7 | public MFTInformation()
8 | {
9 | Note = string.Empty;
10 | }
11 |
12 | public MFTInformation(byte[] rawMFTInfo)
13 | {
14 | if (rawMFTInfo.Length != 8)
15 | {
16 | throw new ArgumentException("rawMFTInfo must be 8 bytes long!");
17 | }
18 |
19 | var sequenceNumber = BitConverter.ToUInt16(rawMFTInfo, 6);
20 |
21 | ulong entryIndex = 0;
22 |
23 | ulong entryIndex1 = BitConverter.ToUInt32(rawMFTInfo, 0);
24 | ulong entryIndex2 = BitConverter.ToUInt16(rawMFTInfo, 4);
25 |
26 | if (entryIndex2 == 0)
27 | {
28 | entryIndex = entryIndex1;
29 | }
30 | else
31 | {
32 | entryIndex2 = (entryIndex2*16777216); //2^24
33 | entryIndex = (entryIndex1 + entryIndex2);
34 | }
35 |
36 | MFTEntryNumber = entryIndex;
37 | MFTSequenceNumber = sequenceNumber;
38 |
39 | if (sequenceNumber == 0)
40 | {
41 | MFTSequenceNumber = null;
42 | }
43 |
44 |
45 | if (entryIndex > 0 && sequenceNumber > 0)
46 | {
47 | Note = "NTFS";
48 | }
49 |
50 | if (entryIndex > 0 && sequenceNumber == 0)
51 | {
52 | Note = "FAT";
53 | }
54 |
55 | if (entryIndex == 0 && sequenceNumber == 0)
56 | {
57 | Note = "Network/special item";
58 | }
59 | }
60 |
61 | public ulong? MFTEntryNumber { get; set; }
62 |
63 | public int? MFTSequenceNumber { get; set; }
64 |
65 | public string Note { get; set; }
66 | }
67 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/PropertySheet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Text;
7 |
8 | namespace ExtensionBlocks
9 | {
10 | public class PropertySheet
11 | {
12 | public enum PropertySheetTypeEnum
13 | {
14 | Named,
15 | Numeric
16 | }
17 |
18 | public PropertySheet(byte[] contents)
19 | {
20 | PropertyNames = new Dictionary();
21 |
22 | var sheetindex = 0;
23 |
24 | var serializedSize = BitConverter.ToInt32(contents, sheetindex);
25 | sheetindex = 4; //skip size
26 |
27 | Size = serializedSize;
28 |
29 | var serializedVersion = BitConverter.ToString(contents, sheetindex, 4);
30 |
31 | sheetindex += 4;
32 |
33 | if (serializedVersion != "31-53-50-53")
34 | {
35 | throw new Exception($"Version mismatch! {serializedVersion} != 31-53-50-53");
36 | }
37 |
38 | Version = serializedVersion;
39 |
40 | var rawguidshellProperty = new byte[16];
41 |
42 | Array.Copy(contents, sheetindex, rawguidshellProperty, 0, 16);
43 |
44 | var formatClassIdguid = Utils.ExtractGuidFromShellItem(rawguidshellProperty);
45 |
46 | sheetindex += 16;
47 |
48 | GUID = formatClassIdguid;
49 |
50 | if (formatClassIdguid == "d5cdd505-2e9c-101b-9397-08002b2cf9ae")
51 | {
52 | //all serialized property values are named properties
53 | PropertySheetType = PropertySheetTypeEnum.Named;
54 |
55 | var valueSize = 0;
56 | var propertyName = "";
57 |
58 | var propertyValues = new Dictionary();
59 | var propertySlotNumber = 0;
60 |
61 | while (sheetindex < contents.Length)
62 | {
63 | //cut up shellPropertySheetList into byte arrays based on length, then process each one
64 | valueSize = BitConverter.ToInt32(contents, sheetindex);
65 |
66 | if (valueSize == 0)
67 | {
68 | break; // we are out of lists
69 | }
70 |
71 | var sheetListBytes = new byte[valueSize];
72 | Array.Copy(contents, sheetindex, sheetListBytes, 0, valueSize);
73 |
74 | propertyValues.Add(propertySlotNumber, sheetListBytes);
75 | propertySlotNumber += 1;
76 |
77 | sheetindex += valueSize;
78 | } //end of while in shellPropertySheetList
79 |
80 | foreach (var propertyValue in propertyValues)
81 | {
82 | var propertyIndex = 0;
83 |
84 | valueSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
85 | propertyIndex += 4;
86 |
87 | var nameSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
88 | propertyIndex += 4;
89 |
90 | propertyIndex += 1; //reserved
91 |
92 | propertyName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, nameSize - 2);
93 |
94 | propertyIndex += (nameSize);
95 |
96 | var namedType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);
97 |
98 | propertyIndex += 2; //skip type
99 | propertyIndex += 2; //skip padding?
100 |
101 | //TODO Combine these with what is below. Make a function to take the type, process and return a string?
102 | switch (namedType)
103 | {
104 | case 0x000b:
105 | //VT_BOOL (0x000B)
106 | var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
107 | propertyIndex += 8;
108 |
109 | var boolval = boolInt > 0;
110 |
111 | PropertyNames.Add(propertyName,
112 | boolval.ToString(CultureInfo.InvariantCulture));
113 |
114 | break;
115 |
116 | case 0x0:
117 | case 0x1:
118 | PropertyNames.Add(propertyName, "");
119 | break;
120 |
121 | case 0x0002:
122 | PropertyNames.Add(propertyName,
123 | BitConverter.ToInt16(propertyValue.Value, propertyIndex)
124 | .ToString(CultureInfo.InvariantCulture));
125 | break;
126 |
127 | case 0x0003:
128 | PropertyNames.Add(propertyName,
129 | BitConverter.ToInt32(propertyValue.Value, propertyIndex)
130 | .ToString(CultureInfo.InvariantCulture));
131 | break;
132 |
133 | case 0x0004:
134 | PropertyNames.Add(propertyName,
135 | BitConverter.ToSingle(propertyValue.Value, propertyIndex)
136 | .ToString(CultureInfo.InvariantCulture));
137 | break;
138 |
139 | case 0x0005:
140 | PropertyNames.Add(propertyName,
141 | BitConverter.ToDouble(propertyValue.Value, propertyIndex)
142 | .ToString(CultureInfo.InvariantCulture));
143 | break;
144 |
145 | case 0x0008:
146 |
147 | var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
148 | propertyIndex += 4;
149 |
150 | var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
151 | uniLength - 2);
152 | propertyIndex += (uniLength);
153 |
154 | PropertyNames.Add(propertyName, unicodeName);
155 |
156 | // PropertyNames.Add(propertyName, BitConverter.ToDouble(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));
157 | break;
158 |
159 |
160 | case 0x000a:
161 | PropertyNames.Add(propertyName,
162 | BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
163 | .ToString(CultureInfo.InvariantCulture));
164 | break;
165 |
166 | case 0x0014:
167 | //VT_I8 (0x0014) MUST be an 8-byte signed integer.
168 |
169 | PropertyNames.Add(propertyName,
170 | BitConverter.ToInt64(propertyValue.Value, propertyIndex)
171 | .ToString(CultureInfo.InvariantCulture));
172 |
173 | break;
174 |
175 | case 0x0015:
176 | //VT_I8 (0x0014) MUST be an 8-byte unsigned integer.
177 |
178 | PropertyNames.Add(propertyName,
179 | BitConverter.ToUInt64(propertyValue.Value, propertyIndex)
180 | .ToString(CultureInfo.InvariantCulture));
181 |
182 | break;
183 |
184 | case 0x0016:
185 | //VT_I8 (0x0014) MUST be an 4-byte signed integer.
186 |
187 | PropertyNames.Add(propertyName,
188 | BitConverter.ToInt32(propertyValue.Value, propertyIndex)
189 | .ToString(CultureInfo.InvariantCulture));
190 |
191 | break;
192 |
193 | case 0x0013:
194 | case 0x0017:
195 | //VT_I8 (0x0014) MUST be an 4-byte unsigned integer.
196 |
197 | PropertyNames.Add(propertyName,
198 | BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
199 | .ToString(CultureInfo.InvariantCulture));
200 |
201 | break;
202 |
203 | case 0x001f: //unicode string
204 |
205 | uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
206 | propertyIndex += 4;
207 |
208 | if (uniLength <= 0)
209 | {
210 | PropertyNames.Add(propertyName, string.Empty);
211 | break;
212 | }
213 |
214 | unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
215 | (uniLength*2) - 2);
216 | propertyIndex += (uniLength*2);
217 |
218 | PropertyNames.Add(propertyName, unicodeName);
219 |
220 | break;
221 |
222 | case 0x0040:
223 | // VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.
224 |
225 | var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
226 | // "01CDF407";
227 |
228 | propertyIndex += 8;
229 |
230 | var dd = DateTime.FromFileTimeUtc(hexNumber);
231 |
232 | PropertyNames.Add(propertyName,
233 | dd.ToString(CultureInfo.InvariantCulture));
234 |
235 | break;
236 |
237 | case 0x0041:
238 | //VT_BLOB 0x0041 Type is binary large object (BLOB), and the minimum property set version is 0
239 |
240 | //TODO FINISH THIS
241 |
242 | var blobSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
243 | propertyIndex += 4;
244 |
245 | var bytes = propertyValue.Value.Skip(0x69).ToArray();
246 |
247 | var props = new PropertyStore(bytes);
248 |
249 | PropertyNames.Add(propertyName,
250 | $"BLOB data: {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
251 |
252 | foreach (var prop in props.Sheets)
253 | {
254 | foreach (var name in prop.PropertyNames)
255 | {
256 | PropertyNames.Add($"{name.Key}", name.Value); // (From BLOB data)
257 | }
258 | }
259 |
260 | propertyIndex += blobSize;
261 |
262 | break;
263 |
264 | case 0x0042:
265 | //TODO FINISH THIS
266 |
267 | //Type is Stream, and the minimum property set version is 0. VT_STREAM is not allowed in a simple property set.
268 | PropertyNames.Add(propertyName,
269 | "VT_STREAM not implemented (yet) See extension block section for contents for now");
270 |
271 | break;
272 |
273 | default:
274 | PropertyNames.Add(propertyName,
275 | $"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to saericzimmerman@gmail.com to get support added");
276 | break;
277 | //throw new Exception($"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
278 | }
279 | }
280 |
281 | var terminator = BitConverter.ToInt32(contents, sheetindex);
282 |
283 | if (terminator != 0)
284 | {
285 | throw new Exception($"Expected terminator of 0, but got {terminator}");
286 | }
287 | }
288 | else
289 | {
290 | //treat as numeric property values
291 |
292 | PropertySheetType = PropertySheetTypeEnum.Numeric;
293 |
294 | var valueSize = 0;
295 | var propertyId = 0;
296 |
297 | var propertyValues = new Dictionary();
298 | var propertySlotNumber = 0;
299 |
300 | while (sheetindex < contents.Length)
301 | {
302 | //cut up shellPropertySheetList into byte arrays based on length, then process each one
303 | var sheetSize = BitConverter.ToInt32(contents, sheetindex);
304 |
305 | if (sheetSize == 0 || (uint)sheetSize >= contents.Length)
306 | {
307 | break; // we are out of lists
308 | }
309 |
310 | var sheetListBytes = new byte[sheetSize];
311 | Array.Copy(contents, sheetindex, sheetListBytes, 0, sheetSize);
312 |
313 | propertyValues.Add(propertySlotNumber, sheetListBytes);
314 | propertySlotNumber += 1;
315 |
316 | sheetindex += sheetSize;
317 | } //end of while in shellPropertySheetList
318 |
319 | foreach (var propertyValue in propertyValues)
320 | {
321 | var propertyIndex = 0;
322 |
323 | valueSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
324 | propertyIndex += 4;
325 |
326 | propertyId = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
327 | propertyIndex += 4;
328 |
329 | propertyIndex += 1; //skip reserved
330 |
331 | var numericType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);
332 |
333 | propertyIndex += 2; //skip type
334 | propertyIndex += 2; //skip padding?
335 |
336 | //TODO Combine these with what is below. Make a function to take the type, process and return a string?
337 | switch (numericType)
338 | {
339 | case 0x1048:
340 | //MUST be a VectorHeader followed by a sequence of GUID (Packet Version) packets.
341 |
342 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
343 | "VT_VECTOR data not implemented (yet)");
344 |
345 | break;
346 | case 0x01e:
347 | var uniLength1e = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
348 | propertyIndex += 4;
349 |
350 | var unicodeName1e =
351 | Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, uniLength1e)
352 | .Split('\0')
353 | .First();
354 |
355 | // Debug.WriteLine($"Find me: {BitConverter.ToString(propertyValue.Value)}, propertyIndex: {propertyIndex} unicodeName1e: {unicodeName1e}");
356 |
357 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName1e);
358 |
359 | break;
360 | case 0x001f: //unicode string
361 |
362 | var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
363 | propertyIndex += 4;
364 |
365 |
366 | if (uniLength <= 0)
367 | {
368 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), string.Empty);
369 | break;
370 | }
371 |
372 | var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
373 | (uniLength*2) - 2);
374 | propertyIndex += (uniLength*2);
375 |
376 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);
377 |
378 | break;
379 |
380 | case 0x000b:
381 | //VT_BOOL (0x000B) MUST be a VARIANT_BOOL as specified in [MS-OAUT] section 2.2.27, followed by zero padding to 4 bytes.
382 |
383 | var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
384 | propertyIndex += 8;
385 |
386 | var boolval = boolInt > 0;
387 |
388 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
389 | boolval.ToString(CultureInfo.InvariantCulture));
390 |
391 | break;
392 |
393 | case 0x0003:
394 | //VT_I4 (0x0003) MUST be a 32-bit signed integer.
395 |
396 | var signedInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
397 | propertyIndex += 4;
398 |
399 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
400 | signedInt.ToString(CultureInfo.InvariantCulture));
401 |
402 | break;
403 |
404 | case 0x0015:
405 | //VT_UI8 (0x0015) MUST be an 8-byte unsigned integer
406 |
407 | var unsigned8int = BitConverter.ToUInt64(propertyValue.Value, propertyIndex);
408 | propertyIndex += 8;
409 |
410 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
411 | unsigned8int.ToString(CultureInfo.InvariantCulture));
412 |
413 | break;
414 |
415 | case 0x0042:
416 | //VT_STREAM (0x0042) MUST be an IndirectPropertyName. The storage representing the
417 | //(non-simple) property set MUST have a stream element with this name
418 |
419 | //defer for now
420 |
421 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
422 | "VT_STREAM not implemented");
423 |
424 | break;
425 |
426 | case 0x0013:
427 | //VT_UI4 (0x0013) MUST be a 4-byte unsigned integer
428 |
429 | var unsigned4int = BitConverter.ToUInt32(propertyValue.Value, propertyIndex);
430 | propertyIndex += 4;
431 |
432 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
433 | unsigned4int.ToString(CultureInfo.InvariantCulture));
434 |
435 | break;
436 |
437 | case 0x0001:
438 | //VT_NULL (0x0001) MUST be zero bytes in length.
439 |
440 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), "Null");
441 |
442 | break;
443 |
444 | case 0x0002:
445 | //VT_I2 (0x0002) Either the specified type, or the type of the element or contained field MUST be a 2-byte signed int
446 |
447 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), BitConverter.ToUInt16(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));
448 |
449 | break;
450 |
451 | case 0x101f:
452 | //VT_VECTOR | VT_LPWSTR 0x101F Type is Vector of UnicodeString, and the minimum property set version is 0
453 |
454 | propertyIndex += 4;
455 |
456 | unicodeName = string.Empty;
457 |
458 | if (propertyValue.Value.Length>propertyIndex)
459 | {
460 | uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
461 | propertyIndex += 4;
462 |
463 | unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
464 | (uniLength * 2) - 2);
465 | propertyIndex += (uniLength * 2);
466 | }
467 |
468 |
469 |
470 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);
471 |
472 | break;
473 |
474 | case 0x0048:
475 | //VT_CLSID 0x0048 Type is CLSID, and the minimum property set version is 0.
476 |
477 | var rawguid1 = new byte[16];
478 |
479 | Array.Copy(propertyValue.Value, propertyIndex, rawguid1, 0, 16);
480 |
481 | propertyIndex += 16;
482 |
483 | var rawguid = Utils.ExtractGuidFromShellItem(rawguid1);
484 |
485 | var foldername = Utils.GetFolderNameFromGuid(rawguid);
486 |
487 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), foldername);
488 |
489 | break;
490 |
491 | case 0x1011:
492 | //VT_VECTOR | VT_UI1 0x1011 Type is Vector of 1-byte unsigned integers, and the minimum property set version is 0.
493 |
494 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
495 | "VT_VECTOR data not implemented (yet) See extension block section for contents for now");
496 |
497 | //TODO i see indicators from 0x00, case 0x23febbee: ProcessPropertyViewGUID(rawBytes) in the bits for this
498 | // can we pull out the property sheet and add them to the property names here?
499 |
500 | break;
501 |
502 | case 0x0040:
503 | //VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.
504 |
505 | var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
506 | // "01CDF407";
507 |
508 | propertyIndex += 8;
509 |
510 | var dd = DateTime.FromFileTimeUtc(hexNumber);
511 |
512 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
513 | dd.ToString(CultureInfo.InvariantCulture));
514 |
515 | break;
516 |
517 | case 0x0008:
518 |
519 | var codePageSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
520 | propertyIndex += 4;
521 |
522 | var codePageName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
523 | codePageSize - 2);
524 | propertyIndex += (codePageSize);
525 |
526 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), codePageName);
527 |
528 | break;
529 |
530 | default:
531 | PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
532 | $"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to saericzimmerman@gmail.com to get support added");
533 | break;
534 | // throw new Exception($"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
535 | }
536 | }
537 |
538 | var terminator = BitConverter.ToInt32(contents, sheetindex);
539 |
540 | if (terminator != 0)
541 | {
542 | throw new Exception($"Expected terminator of 0, but got {terminator}");
543 | }
544 | }
545 | }
546 |
547 | public int Size { get; private set; }
548 |
549 | public string Version { get; private set; }
550 |
551 | public string GUID { get; private set; }
552 |
553 | public byte[] HexValue { get; set; }
554 |
555 | public Dictionary PropertyNames { get; }
556 |
557 | public PropertySheetTypeEnum PropertySheetType { get; private set; }
558 |
559 | public override string ToString()
560 | {
561 | var sb = new StringBuilder();
562 |
563 | if (PropertySheetType == PropertySheetTypeEnum.Numeric)
564 | {
565 | var s = string.Join("; ", PropertyNames.Select(x => $"Guid: {GUID}, Key: {x.Key} ==> {Utils.GetDescriptionFromGuidAndKey(GUID, int.Parse(x.Key))}, Value: {x.Value}"));
566 |
567 | sb.Append(s);
568 | }
569 | else
570 | {
571 | var s = string.Join("; ", PropertyNames.Select(x => $"Guid: {GUID}, Key: {x.Key} ==> {x.Key}, Value: {x.Value}"));
572 |
573 | sb.Append(s);
574 | }
575 |
576 |
577 |
578 | return sb.ToString();
579 | }
580 | }
581 | }
582 |
--------------------------------------------------------------------------------
/ExtensionBlocks/PropertyStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public class PropertyStore
8 | {
9 | public PropertyStore()
10 | {
11 | Sheets = new List();
12 | }
13 |
14 | public PropertyStore(byte[] rawBytes)
15 | {
16 | Sheets = new List();
17 |
18 | //shellPropertySheetList now contains what we need to parse for the rest of this process
19 |
20 | var shellPropertyIndex = 0;
21 |
22 | var sheetLists = new Dictionary();
23 | var sheetListslot = 0;
24 |
25 | while (shellPropertyIndex < rawBytes.Length)
26 | {
27 | //cut up shellPropertySheetList into byte arrays based on length, then process each one
28 | var serializedSize = BitConverter.ToInt32(rawBytes, shellPropertyIndex);
29 |
30 | if (serializedSize == 0 || (uint)serializedSize >= rawBytes.Length)
31 | {
32 | break; // we are out of lists
33 | }
34 |
35 | var sheetListBytes = new byte[serializedSize];
36 | Array.Copy(rawBytes, shellPropertyIndex, sheetListBytes, 0, serializedSize);
37 |
38 | sheetLists.Add(sheetListslot, sheetListBytes);
39 | sheetListslot += 1;
40 |
41 | shellPropertyIndex += serializedSize;
42 | } //end of while in shellPropertySheetList
43 |
44 | foreach (var sheetList in sheetLists)
45 | {
46 | var sheet = new PropertySheet(sheetList.Value);
47 |
48 | Sheets.Add(sheet);
49 | }
50 | }
51 |
52 | public List Sheets { get; }
53 |
54 | public override string ToString()
55 | {
56 | var sb = new StringBuilder();
57 |
58 | var sheetNumber = 0;
59 |
60 | foreach (var propertySheet in Sheets)
61 | {
62 | sb.AppendLine($"Sheet #{sheetNumber} => {propertySheet}");
63 |
64 | sheetNumber += 1;
65 |
66 | }
67 |
68 | return sb.ToString();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/ExtensionBlocks/ShellBag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ExtensionBlocks
6 | {
7 | public abstract class ShellBag : IShellBag
8 | {
9 | public static bool ShowHexInString { get; set; }
10 | public string InternalId { get; set; }
11 |
12 | public string FriendlyName { get; set; }
13 |
14 | public byte[] HexValue { get; set; }
15 |
16 | public string BagPath { get; set; }
17 |
18 | public virtual string AbsolutePath { get; set; }
19 |
20 | public int Slot { get; set; }
21 |
22 | public bool IsDeleted { get; set; }
23 |
24 | public int MruPosition { get; set; }
25 | public int NodeSlot { get; set; }
26 |
27 | public List ChildShellBags { get; set; }
28 |
29 | public string Value { get; set; }
30 |
31 | public DateTimeOffset? LastWriteTime { get; set; }
32 |
33 | public DateTimeOffset? FirstInteracted { get; set; }
34 | public bool HasExplored { get; set; }
35 |
36 | public DateTimeOffset? LastInteracted { get; set; }
37 |
38 | public Utils.ShellBagTypes ShellBagType { get; set; }
39 |
40 |
41 | public List ExtensionBlocks { get; set; }
42 |
43 | public int NodeId { get; set; }
44 |
45 | public override string ToString()
46 | {
47 | var sb = new StringBuilder();
48 |
49 | sb.AppendLine($"Value: {Value}");
50 | sb.AppendLine($"Shell Type: {FriendlyName}");
51 |
52 | sb.AppendLine();
53 |
54 | if (BagPath.Length > 0)
55 | {
56 | sb.AppendLine($"Bag Path: {BagPath}, Slot #: {Slot}, MRU Position: {MruPosition}, Node Slot: {NodeSlot}");
57 | sb.AppendLine($"Absolute Path: {AbsolutePath}");
58 | sb.AppendLine();
59 | }
60 |
61 | sb.AppendLine($"Has been explored: {HasExplored}");
62 | sb.AppendLine();
63 |
64 | if (IsDeleted)
65 | {
66 | sb.AppendLine("Deleted: True");
67 | sb.AppendLine();
68 | }
69 |
70 | sb.AppendLine($"# Child Bags: {ChildShellBags.Count}");
71 |
72 | if (FirstInteracted.HasValue)
73 | {
74 | sb.AppendLine();
75 | sb.AppendLine(
76 | $"First interacted: {FirstInteracted.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
77 | }
78 |
79 | if (LastInteracted.HasValue)
80 | {
81 | sb.AppendLine();
82 | sb.AppendLine(
83 | $"Last interacted: {LastInteracted.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
84 | }
85 |
86 | if (ExtensionBlocks.Count > 0)
87 | {
88 | var extensionNumber = 0;
89 |
90 | sb.AppendLine();
91 | sb.AppendLine($"Extension blocks found: {ExtensionBlocks.Count}");
92 |
93 | foreach (var extensionBlock in ExtensionBlocks)
94 | {
95 | if (extensionBlock is BeefPlaceHolder)
96 | {
97 | continue;
98 | }
99 |
100 | sb.AppendLine($"---------------------- Block {extensionNumber:N0} ----------------------");
101 |
102 | sb.AppendLine(extensionBlock.ToString());
103 |
104 | extensionNumber += 1;
105 | }
106 |
107 | sb.AppendLine("--------------------------------------------------");
108 | }
109 |
110 | if (LastWriteTime.HasValue)
111 | {
112 | sb.AppendLine();
113 | sb.AppendLine(
114 | $"Last Write Time: {LastWriteTime.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
115 | }
116 |
117 | if (ShowHexInString)
118 | {
119 | sb.AppendLine($"\r\nHex Value: {BitConverter.ToString(HexValue)}");
120 | }
121 |
122 | return sb.ToString();
123 | }
124 | }
125 | }
--------------------------------------------------------------------------------
/ExtensionBlocks/ShellBag0X31.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace ExtensionBlocks
7 | {
8 | public class ShellBag0X31 : ShellBag
9 | {
10 | public ShellBag0X31(int slot, int mruPosition, byte[] rawBytes, string bagPath)
11 | {
12 | Slot = slot;
13 | MruPosition = mruPosition;
14 |
15 | FriendlyName = "Directory";
16 | ShellBagType = Utils.ShellBagTypes.Directory;
17 |
18 | ChildShellBags = new List();
19 |
20 | InternalId = Guid.NewGuid().ToString();
21 |
22 | HexValue = rawBytes;
23 |
24 | ExtensionBlocks = new List();
25 |
26 | BagPath = bagPath;
27 |
28 | var index = 2;
29 |
30 |
31 | index += 1;
32 |
33 | //skip unknown byte
34 | index += 1;
35 |
36 | index += 4; // skip file size since always 0 for directory
37 |
38 | LastModificationTime = Utils.ExtractDateTimeOffsetFromBytes(rawBytes.Skip(index).Take(4).ToArray());
39 |
40 | index += 4;
41 |
42 | index += 2;
43 |
44 | var len = 0;
45 |
46 |
47 | var beefPos = BitConverter.ToString(rawBytes).IndexOf("04-00-EF-BE", StringComparison.InvariantCulture) / 3;
48 |
49 | if (beefPos == 0)
50 | {
51 | var hackName = CodePagesEncodingProvider.Instance.GetEncoding(1252).GetString(rawBytes, index, rawBytes.Length - index);
52 |
53 | var segs = hackName.Split(new[] {'\0'}, StringSplitOptions.RemoveEmptyEntries);
54 |
55 | ShortName = string.Join("|", segs);
56 |
57 | Value = ShortName;
58 | return;
59 | }
60 |
61 |
62 | beefPos = beefPos - 4; //add header back for beef
63 |
64 | var strLen = beefPos - index;
65 |
66 | if (rawBytes[2] == 0x35|| rawBytes[2] == 0x36)
67 | {
68 | len = strLen;
69 | }
70 | else
71 | {
72 | while (rawBytes[index + len] != 0x0)
73 | {
74 | len += 1;
75 | }
76 | }
77 |
78 | var tempBytes = new byte[len];
79 | Array.Copy(rawBytes, index, tempBytes, 0, len);
80 |
81 | var shortName = "";
82 |
83 | if (rawBytes[2] == 0x35|| rawBytes[2] == 0x36)
84 | {
85 | shortName = Encoding.Unicode.GetString(tempBytes);
86 | }
87 | else
88 | {
89 | shortName = CodePagesEncodingProvider.Instance.GetEncoding(1252).GetString(tempBytes);
90 | }
91 |
92 | ShortName = shortName;
93 |
94 | Value = shortName;
95 |
96 | index = beefPos;
97 |
98 | // here is where we need to cut up the rest into extension blocks
99 | var chunks = new List();
100 |
101 | while (index < rawBytes.Length)
102 | {
103 | var subshellitemdatasize = BitConverter.ToInt16(rawBytes, index);
104 | //index += 2;
105 |
106 | if (subshellitemdatasize == 0)
107 | {
108 | index += 2; //some kind of separator
109 | }
110 |
111 | if (subshellitemdatasize == 1)
112 | {
113 | //some kind of separator
114 | index += 2;
115 | }
116 | else
117 | {
118 | if (subshellitemdatasize > 0)
119 | {
120 | var shellBuff = new byte[subshellitemdatasize];
121 | Buffer.BlockCopy(rawBytes, index, shellBuff, 0, subshellitemdatasize);
122 |
123 | chunks.Add(shellBuff);
124 | index += subshellitemdatasize;
125 | }
126 | }
127 | }
128 |
129 | foreach (var bytes in chunks)
130 | {
131 | index = 0;
132 |
133 | var extsize = BitConverter.ToInt16(bytes, index);
134 |
135 | var signature = BitConverter.ToUInt32(bytes, 0x04);
136 |
137 | //TODO does this need to check if its a 0xbeef?? regex?
138 | var block = Utils.GetExtensionBlockFromBytes(signature, bytes);
139 |
140 | if (block.Signature.ToString("X").StartsWith("BEEF00"))
141 | {
142 | ExtensionBlocks.Add(block);
143 | }
144 |
145 |
146 | var beef0004 = block as Beef0004;
147 | if (beef0004 != null)
148 | {
149 | Value = beef0004.LongName;
150 | }
151 |
152 |
153 |
154 | index += extsize;
155 | }
156 | }
157 |
158 | ///
159 | /// last modified time of BagPath
160 | ///
161 | public DateTimeOffset? LastModificationTime { get; set; }
162 |
163 |
164 | ///
165 | /// Last access time of BagPath
166 | ///
167 | public DateTimeOffset? LastAccessTime { get; set; }
168 |
169 |
170 | public string ShortName { get; }
171 |
172 |
173 |
174 | public override string ToString()
175 | {
176 | var sb = new StringBuilder();
177 |
178 | if (ShortName.Length > 0)
179 | {
180 | sb.AppendLine($"Short name: {ShortName}");
181 | }
182 |
183 | if (LastModificationTime.HasValue)
184 | {
185 | sb.AppendLine(
186 | $"Modified: {LastModificationTime.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
187 | }
188 |
189 | if (LastAccessTime.HasValue)
190 | {
191 | sb.AppendLine(
192 | $"Last Access: {LastAccessTime.Value.ToString(Utils.GetDateTimeFormatWithMilliseconds())}");
193 | }
194 |
195 | sb.AppendLine();
196 | sb.AppendLine(base.ToString());
197 |
198 | return sb.ToString();
199 | }
200 | }
201 | }
--------------------------------------------------------------------------------
/License.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Eric Zimmerman
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ExtensionBlocks
2 | Extension blocks as found in ShellBags and other places in the Registry
3 |
4 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EricZimmerman/ExtensionBlocks/58e35b8457bf3006f672c972619bc0fb913fb7e4/icon.png
--------------------------------------------------------------------------------