├── .gitignore
├── LICENSE.md
├── README.md
└── src
├── Common
├── CommandLineParser.cs
├── DosToolsApplication.cs
└── StringExtensions.cs
├── firmwaretables.sln
└── firmwaretables
├── AcpiTable.cs
├── Application.cs
├── FirmwareTables.cs
├── Program.cs
├── Properties
└── AssemblyInfo.cs
└── firmwaretables.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Rr]elease/
19 | x64/
20 | *_i.c
21 | *_p.c
22 | *.ilk
23 | *.meta
24 | *.obj
25 | *.pch
26 | *.pdb
27 | *.pgc
28 | *.pgd
29 | *.rsp
30 | *.sbr
31 | *.tlb
32 | *.tli
33 | *.tlh
34 | *.tmp
35 | *.log
36 | *.vspscc
37 | *.vssscc
38 | .builds
39 |
40 | # Visual C++ cache files
41 | ipch/
42 | *.aps
43 | *.ncb
44 | *.opensdf
45 | *.sdf
46 |
47 | # Visual Studio profiler
48 | *.psess
49 | *.vsp
50 | *.vspx
51 |
52 | # Guidance Automation Toolkit
53 | *.gpState
54 |
55 | # ReSharper is a .NET coding add-in
56 | _ReSharper*
57 |
58 | # NCrunch
59 | *.ncrunch*
60 | .*crunch*.local.xml
61 |
62 | # Installshield output folder
63 | [Ee]xpress
64 |
65 | # DocProject is a documentation generator add-in
66 | DocProject/buildhelp/
67 | DocProject/Help/*.HxT
68 | DocProject/Help/*.HxC
69 | DocProject/Help/*.hhc
70 | DocProject/Help/*.hhk
71 | DocProject/Help/*.hhp
72 | DocProject/Help/Html2
73 | DocProject/Help/html
74 |
75 | # Click-Once directory
76 | publish
77 |
78 | # Publish Web Output
79 | *.Publish.xml
80 |
81 | # NuGet Packages Directory
82 | packages
83 |
84 | # Windows Azure Build Output
85 | csx
86 | *.build.csdef
87 |
88 | # Windows Store app package directory
89 | AppPackages/
90 |
91 | # Others
92 | [Bb]in
93 | [Oo]bj
94 | sql
95 | TestResults
96 | [Tt]est[Rr]esult*
97 | *.Cache
98 | ClientBin
99 | [Ss]tyle[Cc]op.*
100 | ~$*
101 | *.dbmdl
102 | Generated_Code #added for RIA/Silverlight projects
103 |
104 | # Backup & report files from converting an old project file to a newer
105 | # Visual Studio version. Backup files are not needed, because we have git ;-)
106 | _UpgradeReport_Files/
107 | Backup*/
108 | UpgradeLog*.XML
109 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Vurdalakov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FirmwareTables
2 |
3 | ### Overview
4 |
5 | A set of classes and command line tools that work with system firmware tables (ACPI, SMBIOS).
6 |
7 | Distributed under the [MIT license](http://opensource.org/licenses/MIT).
8 |
9 | ### `FirmwareTables` class
10 |
11 | `FirmwareTables` class enumerates system firmware tables and gets them in binary form, using [EnumSystemFirmwareTables](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724259.aspx) and [GetSystemFirmwareTable](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379.aspx) Windows API functions.
12 |
13 | Example 1: System firmware tables enumaration
14 |
15 | ```
16 | foreach (FirmwareTableType tableType in Enum.GetValues(typeof(FirmwareTableType)))
17 | {
18 | var tableIds = EnumFirmwareTables(tableType);
19 |
20 | foreach (var tableId in tableIds)
21 | {
22 | Console.WriteLine("'{0}' - 0x{1:X8}", tableType.ToString().ToUpper(), tableId);
23 | }
24 | }
25 | ```
26 |
27 | Example 2: Save specific firmware table to binary file.
28 |
29 | ```
30 | var data = FirmwareTables.GetFirmwareTable("ACPI", "MDSM");
31 |
32 | File.WriteAllBytes("Acpi-Windows-License-Key.bin", data);
33 | ```
34 |
35 | ### `AcpiTable` class
36 |
37 | `AcpiTable` class parses a given ACPI table binary and provides access to ACPI table header fields and table payload.
38 |
39 | Example 1: Extract OEM Windows product key from ACPI MSDM table
40 |
41 | ```
42 | var table = FirmwareTables.GetAcpiTable("MDSM");
43 | var productKeyLength = (int)table.GetPayloadUInt32(16);
44 | var productKey = table.GetPayloadString(20, productKeyLength);
45 |
46 | Console.WriteLine("OEM Windows product key: '{0}'", productKey);
47 | ```
48 |
49 | ### `firmwaretables` tool
50 |
51 | **FirmwareTables** is a command-line C# program that lists system firmware tables and saves them to binary files.
52 |
53 | This tool is part of [`dostools` collection](https://github.com/vurdalakov/dostools).
54 |
55 | Syntax:
56 |
57 | ```
58 | firmwaretables -list # lists available system firmware tables
59 | firmwaretables -save
[filename] [-silent] # saves specific system firmware table to binary file
60 | firmwaretables -all [-silent] # saves all system firmware tables to binary files
61 | firmwaretables -decode # decodes given table
62 | ```
63 |
64 | `table type` and `table id` can be a string (e.g. `ACPI`) or a hex number (e.g. `0x52534D42`).
65 |
66 | If file name is omitted, it is created based on table type and ID in hex form, e.g. `52534D42_00000000.bin`.
67 |
68 | Exit codes:
69 |
70 | * 0 - operation succeeded;
71 | * 1 - operation failed;
72 | * -1 - invalid command line syntax.
73 |
74 | Example 1: List all available system firmware tables.
75 |
76 | ```
77 | firmwaretables -list
78 | firmwaretables -l
79 | ```
80 |
81 | Example 2: Save specific firmware table to binary file.
82 |
83 | ```
84 | firmwaretables -save ACPI MDSM "Acpi-Windows-License-Key.bin"
85 | firmwaretables -s 0x52534D42 0x00000000 -silent
86 | ```
87 |
88 | Example 3: Save all firmware tables to binary files.
89 |
90 | ```
91 | firmwaretables -all"
92 | firmwaretables -a -silent
93 | ```
94 |
95 | Example 4: Decode specific firmware table.
96 |
97 | ```
98 | firmwaretables -decode acpi mdsm
99 | firmwaretables -d -0x52534D42 0x00000000
100 | ```
101 |
102 | Example 1 output: List all available system firmware tables.
103 |
104 | ```
105 | C:\temp>firmwaretables.exe -l
106 | 0x41435049 'ACPI' - 0x50474244 'PGBD'
107 | 0x41435049 'ACPI' - 0x4746434D 'GFCM'
108 | 0x41435049 'ACPI' - 0x50434146 'PCAF'
109 | 0x41435049 'ACPI' - 0x43495041 'CIPA'
110 | 0x41435049 'ACPI' - 0x544F4F42 'TOOB'
111 | 0x41435049 'ACPI' - 0x52414D44 'RAMD'
112 | 0x41435049 'ACPI' - 0x54455048 'TEPH'
113 | 0x41435049 'ACPI' - 0x54445046 'TDPF'
114 | 0x41435049 'ACPI' - 0x41504354 'APCT'
115 | 0x41435049 'ACPI' - 0x49464555 'IFEU'
116 | 0x41435049 'ACPI' - 0x54445353 'TDSS'
117 | 0x41435049 'ACPI' - 0x324D5054 '2MPT'
118 | 0x41435049 'ACPI' - 0x4D44534D 'MDSM'
119 | 0x41435049 'ACPI' - 0x32474244 '2GBD'
120 | 0x41435049 'ACPI' - 0x21465341 '!FSA'
121 | 0x41435049 'ACPI' - 0x54505341 'TPSA'
122 | 0x41435049 'ACPI' - 0x5449504C 'TIPL'
123 | 0x4649524D 'FIRM' - 0x000C0000 ' ♀ '
124 | 0x4649524D 'FIRM' - 0x000E0000 ' ♫ '
125 | 0x52534D42 'RSMB' - 0x00000000 ' '
126 | ```
127 |
128 | Example 4 output: Decode specific firmware table.
129 |
130 | ```
131 | C:\temp>firmwaretables -decode acpi mdsm
132 | === 'MSDM' ACPI table 0x4D44534D or 'MDSM'
133 | Table size: 85 bytes
134 | --- ACPI table header
135 | Signature: 'MSDM'
136 | Length: 85 bytes
137 | Revision: 3
138 | Checksum: 0x24 - OK
139 | OEM ID: 'LENOVO'
140 | OEM Table ID: 'CB-01 '
141 | OEM Revison: 1
142 | Creator ID: 'ACPI'
143 | Creator Revison: 262144 or 0x00040000
144 | --- ACPI table payload
145 | Version: 1
146 | Reserved: 0
147 | Data Type: 1
148 | Data Reserved: 0
149 | Data Length: 29
150 | Product Key: XYQGN-7YFFX-2FCYC-8T4FY-MY47F
151 | ```
152 |
153 | ```
154 | C:\temp>firmwaretables.exe -d acpi tdsx
155 | === 'XSDT' ACPI table 0x54445358 or 'TDSX'
156 | Table size: 252 bytes
157 | --- ACPI table header
158 | Signature: 'XSDT'
159 | Length: 252 bytes
160 | Revision: 1
161 | Checksum: 0x29 - OK
162 | OEM ID: 'LENOVO'
163 | OEM Table ID: 'CB-01 '
164 | OEM Revison: 1
165 | Creator ID: ' '
166 | Creator Revison: 16777235 or 0x01000013
167 | --- ACPI table payload
168 | Length: 216 bytes
169 | 000000: 00 90 FE 77 00 00 00 00 00 C0 FF 77 00 00 00 00 ??w Ayw
170 | 000010: 00 B0 FF 77 00 00 00 00 00 A0 FF 77 00 00 00 00 °yw yw
171 | 000020: 00 90 FF 77 00 00 00 00 00 80 FF 77 00 00 00 00 ?yw ?yw
172 | 000030: 00 70 FF 77 00 00 00 00 00 60 FF 77 00 00 00 00 pyw `yw
173 | 000040: 00 00 FF 77 00 00 00 00 00 F0 FE 77 00 00 00 00 yw ??w
174 | 000050: 00 E0 FE 77 00 00 00 00 00 D0 FE 77 00 00 00 00 a?w ??w
175 | 000060: 00 C0 FE 77 00 00 00 00 00 B0 FE 77 00 00 00 00 A?w °?w
176 | 000070: 00 A0 FE 77 00 00 00 00 00 80 FE 77 00 00 00 00 ?w ??w
177 | 000080: 00 70 FE 77 00 00 00 00 00 60 FE 77 00 00 00 00 p?w `?w
178 | 000090: 00 50 FE 77 00 00 00 00 00 50 FC 77 00 00 00 00 P?w Puw
179 | 0000A0: 00 40 FC 77 00 00 00 00 00 20 FC 77 00 00 00 00 @uw uw
180 | 0000B0: 00 10 FC 77 00 00 00 00 00 00 FC 77 00 00 00 00 uw uw
181 | 0000C0: 00 B0 FB 77 00 00 00 00 00 A0 FB 77 00 00 00 00 °uw uw
182 | 0000D0: 00 90 FB 77 00 00 00 00 ?uw
183 | ```
184 |
--------------------------------------------------------------------------------
/src/Common/CommandLineParser.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | // Command format: [/option] [/option=value] [filename1 [filename2 ...]]
8 |
9 | public class CommandLineParser
10 | {
11 | private readonly Dictionary _options = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
12 |
13 | public CommandLineParser(Char[] prefixes = null, Char[] valueSeparators = null, Boolean caseInsensitiveNames = true)
14 | {
15 | if (null == prefixes)
16 | {
17 | prefixes = new[] { '/', '-' };
18 | }
19 |
20 | if (null == valueSeparators)
21 | {
22 | valueSeparators = new[] { '=', ':' };
23 | }
24 |
25 | _options = new Dictionary(caseInsensitiveNames ? StringComparer.InvariantCultureIgnoreCase : null);
26 |
27 | ParseArguments(prefixes, valueSeparators);
28 | }
29 |
30 | public String ExecutableFileName { get; private set; }
31 |
32 | public String ExecutablePath { get; private set; }
33 |
34 | public String[] FileNames { get; private set; }
35 |
36 | public Boolean IsOptionSet(String optionName)
37 | {
38 | return _options.ContainsKey(optionName);
39 | }
40 |
41 | public Boolean IsOptionSet(params String[] optionNames)
42 | {
43 | foreach (var optionName in optionNames)
44 | {
45 | if (IsOptionSet(optionName))
46 | {
47 | return true;
48 | }
49 | }
50 |
51 | return false;
52 | }
53 |
54 | public Boolean OptionHasValue(String optionName)
55 | {
56 | return IsOptionSet(optionName) && !String.IsNullOrEmpty(_options[optionName]);
57 | }
58 |
59 | public Boolean OptionHasValue(params String[] optionNames)
60 | {
61 | foreach (var optionName in optionNames)
62 | {
63 | if (OptionHasValue(optionName))
64 | {
65 | return true;
66 | }
67 | }
68 |
69 | return false;
70 | }
71 |
72 | public String GetOptionString(String optionName)
73 | {
74 | return GetOptionString(optionName, null);
75 | }
76 |
77 | public String GetOptionString(String optionName, String defaultValue)
78 | {
79 | return OptionHasValue(optionName) ? _options[optionName] : defaultValue;
80 | }
81 |
82 | public String GetOptionString(params String[] optionNames)
83 | {
84 | var last = optionNames.Length - 1;
85 |
86 | var defaultValue = optionNames[last];
87 |
88 | for (var i = 0; i < last; i++)
89 | {
90 | var optionName = optionNames[i];
91 | if (OptionHasValue(optionName))
92 | {
93 | return GetOptionString(optionName, defaultValue);
94 | }
95 | }
96 |
97 | return defaultValue;
98 | }
99 |
100 | public Int32 GetOptionInt(String optionName)
101 | {
102 | return GetOptionInt(optionName, -1);
103 | }
104 |
105 | public Int32 GetOptionInt(String optionName, Int32 defaultValue)
106 | {
107 | try
108 | {
109 | return OptionHasValue(optionName) ? Convert.ToInt32(GetOptionString(optionName)) : defaultValue;
110 | }
111 | catch
112 | {
113 | return defaultValue;
114 | }
115 | }
116 |
117 | public Int32 GetOptionInt(params Object[] parameters)
118 | {
119 | if (parameters.Length < 3)
120 | {
121 | throw new ArgumentException("Function takes 3 or more parameters");
122 | }
123 |
124 | var last = parameters.Length - 1;
125 |
126 | var defaultValue = (Int32)parameters[last];
127 |
128 | for (var i = 0; i < last; i++)
129 | {
130 | var optionName = parameters[i] as String;
131 |
132 | if (String.IsNullOrEmpty(optionName))
133 | {
134 | throw new ArgumentException(String.Format("Parameter {0} must be a string", i));
135 | }
136 |
137 | if (OptionHasValue(optionName))
138 | {
139 | return GetOptionInt(optionName, defaultValue);
140 | }
141 | }
142 |
143 | return defaultValue;
144 | }
145 |
146 | private void ParseArguments(Char[] prefixes, Char[] valueSeparators)
147 | {
148 | var args = Environment.GetCommandLineArgs();
149 |
150 | ExecutableFileName = args[0];
151 | ExecutablePath = Path.GetDirectoryName(ExecutableFileName);
152 |
153 | var fileNames = new List();
154 |
155 | for (int i = 1; i < args.Length; i++)
156 | {
157 | var s = args[i];
158 |
159 | if (String.IsNullOrEmpty(s))
160 | {
161 | // just skip
162 | }
163 | else if (0 == s.IndexOfAny(prefixes)) // options
164 | {
165 | if (s.IndexOfAny(valueSeparators) > 0) // option with value
166 | {
167 | var optionParts = s.Split(valueSeparators);
168 | _options.Add(optionParts[0].TrimStart(prefixes).ToLower(), optionParts[1]);
169 | }
170 | else // option without value
171 | {
172 | _options.Add(s.TrimStart(prefixes).ToLower(), null);
173 | }
174 | }
175 | else // file names
176 | {
177 | fileNames.Add(s);
178 | }
179 | }
180 |
181 | FileNames = fileNames.ToArray();
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/Common/DosToolsApplication.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.Reflection;
5 |
6 | public abstract class DosToolsApplication
7 | {
8 | protected CommandLineParser _commandLineParser;
9 |
10 | public String ApplicationVersion
11 | {
12 | get
13 | {
14 | var parts = Assembly.GetExecutingAssembly().FullName.Split(',');
15 | return parts[1].Split('=')[1];
16 | }
17 | }
18 |
19 | public DosToolsApplication()
20 | {
21 | try
22 | {
23 | _commandLineParser = new CommandLineParser();
24 |
25 | if (_commandLineParser.IsOptionSet("?", "h", "help"))
26 | {
27 | Help();
28 | }
29 |
30 | _silent = _commandLineParser.IsOptionSet("silent");
31 | }
32 | catch
33 | {
34 | Help();
35 | }
36 | }
37 |
38 | public void Run()
39 | {
40 | try
41 | {
42 | var result = Execute();
43 | Environment.Exit(result);
44 | }
45 | catch (Exception ex)
46 | {
47 | Print("{0}", ex.Message);
48 | Environment.Exit(1);
49 | }
50 | }
51 |
52 | protected abstract Int32 Execute();
53 |
54 | protected virtual void Help()
55 | {
56 | Environment.Exit(-1);
57 | }
58 |
59 | private Boolean _silent;
60 |
61 | protected void Print(String format, params Object[] args)
62 | {
63 | if (!_silent)
64 | {
65 | Console.WriteLine(String.Format(format, args));
66 | }
67 | }
68 |
69 | protected void Error(Int32 errorCode, String format, params Object[] args)
70 | {
71 | Print(format, args);
72 | Environment.Exit(errorCode);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Common/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.Globalization;
5 | using System.Text;
6 |
7 | public static class StringExtensions
8 | {
9 | public static Boolean ContainsWord(this String text, String word)
10 | {
11 | return !String.IsNullOrEmpty(text) && (text.Equals(word) || text.StartsWith(word + " ") || text.Contains(" " + word + " ") || text.EndsWith(" " + word));
12 | }
13 |
14 | public static String ToUpperFirst(this String text, CultureInfo cultureInfo = null)
15 | {
16 | if (null == cultureInfo)
17 | {
18 | cultureInfo = CultureInfo.CurrentUICulture;
19 | }
20 |
21 | return String.IsNullOrEmpty(text) ? text : Char.ToUpper(text[0], cultureInfo) + text.Substring(1);
22 | }
23 |
24 | public static String XmlEscape(this String text)
25 | {
26 | return String.IsNullOrEmpty(text) ? text : text.Replace("\"", """).Replace("'", "'").Replace("<", "<").Replace(">", ">").Replace("&", "&");
27 | }
28 |
29 | public static String XmlUnescape(this String text)
30 | {
31 | return String.IsNullOrEmpty(text) ? text : text.Replace(""", "\"").Replace("'", "'").Replace("<", "<").Replace(">", ">").Replace("&", "&");
32 | }
33 |
34 | public static String Base64Encode(this String text)
35 | {
36 | var bytes = Encoding.UTF8.GetBytes(text);
37 | return Convert.ToBase64String(bytes);
38 | }
39 |
40 | public static String Base64Decode(this String text)
41 | {
42 | var bytes = Convert.FromBase64String(text);
43 | return Encoding.UTF8.GetString(bytes);
44 | }
45 |
46 | public static string Reverse(this String text)
47 | {
48 | var charArray = text.ToCharArray();
49 | Array.Reverse(charArray);
50 | return new String(charArray);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/firmwaretables.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "firmwaretables", "firmwaretables\firmwaretables.csproj", "{6A4828A3-191E-4E1B-841E-05F0DFACFBB8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {6A4828A3-191E-4E1B-841E-05F0DFACFBB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {6A4828A3-191E-4E1B-841E-05F0DFACFBB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {6A4828A3-191E-4E1B-841E-05F0DFACFBB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {6A4828A3-191E-4E1B-841E-05F0DFACFBB8}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/src/firmwaretables/AcpiTable.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.Text;
5 |
6 | public class AcpiTable
7 | {
8 | const Int32 AcpiTableHeaderLength = 36;
9 |
10 | //public static AcpiTable Parse(Byte[] data)
11 | //{
12 | // if (data.Length < AcpiTableHeaderLength)
13 | // {
14 | // throw new ArgumentException("Invalid ACPI data");
15 | // }
16 |
17 | // var signature = Encoding.ASCII.GetString(data, 0, 4);
18 |
19 | // AcpiTable acpiTable = null;
20 | // switch (signature.ToUpper())
21 | // {
22 | // case "MSDM":
23 | // acpiTable = new AcpiTableMsdm(data);
24 | // break;
25 | // default:
26 | // acpiTable = new AcpiTable(data);
27 | // break;
28 | // }
29 |
30 | // return acpiTable;
31 | //}
32 |
33 | public AcpiTable(Byte[] data)
34 | {
35 | if (data.Length < AcpiTableHeaderLength)
36 | {
37 | throw new ArgumentException("Invalid ACPI data");
38 | }
39 |
40 | this.RawData = data;
41 |
42 | this.Signature = Encoding.ASCII.GetString(data, 0, 4);
43 | this.Length = BitConverter.ToUInt32(data, 4);
44 | this.Revision = data[8];
45 | this.Checksum = data[9];
46 | this.OemId = Encoding.ASCII.GetString(data, 10, 6);
47 | this.OemTableId = Encoding.ASCII.GetString(data, 16, 8);
48 | this.OemRevision = BitConverter.ToUInt32(data, 24);
49 | this.CreatorId = Encoding.ASCII.GetString(data, 28, 4);
50 | this.CreatorRevision = BitConverter.ToUInt32(data, 32);
51 |
52 | var payloadLength = data.Length - AcpiTableHeaderLength;
53 | this.Payload = new Byte[payloadLength];
54 | Array.Copy(data, AcpiTableHeaderLength, this.Payload, 0, payloadLength);
55 |
56 | this.ChecksumIsValid = ValidateChecksum(data);
57 | }
58 |
59 | public Byte[] RawData { get; private set; }
60 |
61 | public String Signature { get; private set; }
62 | public UInt32 Length { get; private set; }
63 | public Byte Revision { get; private set; }
64 | public Byte Checksum { get; private set; }
65 | public Boolean ChecksumIsValid { get; private set; }
66 | public String OemId { get; private set; }
67 | public String OemTableId { get; private set; }
68 | public UInt32 OemRevision { get; private set; }
69 | public String CreatorId { get; private set; }
70 | public UInt32 CreatorRevision { get; private set; }
71 | public Byte[] Payload { get; private set; }
72 |
73 | public Byte GetPayloadByte(Int32 index)
74 | {
75 | return this.Payload[index];
76 | }
77 |
78 | public UInt16 GetPayloadUInt16(Int32 index)
79 | {
80 | return BitConverter.ToUInt16(this.Payload, index);
81 | }
82 |
83 | public UInt32 GetPayloadUInt32(Int32 index)
84 | {
85 | return BitConverter.ToUInt32(this.Payload, index);
86 | }
87 |
88 | public UInt64 GetPayloadUInt64(Int32 index)
89 | {
90 | return BitConverter.ToUInt64(this.Payload, index);
91 | }
92 |
93 | public String GetPayloadString(Int32 index, Int32 length)
94 | {
95 | return Encoding.ASCII.GetString(this.Payload, index, length);
96 | }
97 |
98 | private static Boolean ValidateChecksum(Byte[] data)
99 | {
100 | Byte sum = 0;
101 |
102 | for (var i = 0; i < data.Length; i++)
103 | {
104 | sum += data[i];
105 | }
106 |
107 | return 0 == sum;
108 | }
109 | }
110 |
111 | //public class AcpiTableMsdm : AcpiTable
112 | //{
113 | // public AcpiTableMsdm(Byte[] data) : base(data)
114 | // {
115 | // this.Version = BitConverter.ToUInt32(data, 36);
116 | // this.Reserved = BitConverter.ToUInt32(data, 40);
117 | // this.DataType = BitConverter.ToUInt32(data, 44);
118 | // this.DataReserved = BitConverter.ToUInt32(data, 48);
119 | // this.DataLength = BitConverter.ToUInt32(data, 52);
120 | // this.ProductKey = Encoding.ASCII.GetString(data, 56, (int)this.DataLength);
121 | // }
122 |
123 | // public UInt32 Version { get; private set; }
124 | // public UInt32 Reserved { get; private set; }
125 | // public UInt32 DataType { get; private set; }
126 | // public UInt32 DataReserved { get; private set; }
127 | // public UInt32 DataLength { get; private set; }
128 | // public String ProductKey { get; private set; }
129 | //}
130 | }
131 |
--------------------------------------------------------------------------------
/src/firmwaretables/Application.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Text;
6 |
7 | public class Application : DosToolsApplication
8 | {
9 | protected override Int32 Execute()
10 | {
11 | if (_commandLineParser.IsOptionSet("l", "list"))
12 | {
13 | foreach (FirmwareTableType tableType in Enum.GetValues(typeof(FirmwareTableType)))
14 | {
15 | var tableIds = FirmwareTables.EnumFirmwareTables(tableType);
16 |
17 | foreach (var tableId in tableIds)
18 | {
19 | Console.WriteLine("0x{0:X8} '{1}' - 0x{2:X8} '{3}'", (UInt32)tableType, tableType.ToString().ToUpper(), tableId, FirmwareTables.UInt32ToString(tableId));
20 | }
21 | }
22 | }
23 | else if (_commandLineParser.IsOptionSet("s", "save"))
24 | {
25 | if ((_commandLineParser.FileNames.Length < 2) || (_commandLineParser.FileNames.Length > 3))
26 | {
27 | Help();
28 | }
29 |
30 | var tableType = MakeUInt32(_commandLineParser.FileNames[0]);
31 | var tableId = MakeUInt32(_commandLineParser.FileNames[1]);
32 |
33 | var data = FirmwareTables.GetFirmwareTable(tableType, tableId);
34 |
35 | var fileName = 3 == _commandLineParser.FileNames.Length ? _commandLineParser.FileNames[2] : FormatFileName(tableType, tableId);
36 |
37 | File.WriteAllBytes(fileName, data);
38 |
39 | Console.WriteLine("OK: '{0}' ({1:N0} bytes)", fileName, data.Length);
40 | }
41 | else if (_commandLineParser.IsOptionSet("a", "all"))
42 | {
43 | foreach (FirmwareTableType tableType in Enum.GetValues(typeof(FirmwareTableType)))
44 | {
45 | var tableIds = FirmwareTables.EnumFirmwareTables(tableType);
46 |
47 | foreach (var tableId in tableIds)
48 | {
49 | var data = FirmwareTables.GetFirmwareTable(tableType, tableId);
50 |
51 | var fileName = FormatFileName((UInt32)tableType, tableId);
52 |
53 | File.WriteAllBytes(fileName, data);
54 |
55 | Console.WriteLine("'{0}' ({1:N0} bytes)", fileName, data.Length);
56 | }
57 | }
58 |
59 | Console.WriteLine("All OK");
60 | }
61 | else if (_commandLineParser.IsOptionSet("d", "decode"))
62 | {
63 | if ((_commandLineParser.FileNames.Length < 1) || (_commandLineParser.FileNames.Length > 2))
64 | {
65 | Help();
66 | }
67 |
68 | var tableType = MakeUInt32(_commandLineParser.FileNames[0]);
69 |
70 | if (tableType != (UInt32)FirmwareTableType.Acpi)
71 | {
72 | throw new NotSupportedException("Only the following frimware tables can be decoded: ACPI");
73 | }
74 |
75 | if (2 == _commandLineParser.FileNames.Length)
76 | {
77 | var tableId = MakeUInt32(_commandLineParser.FileNames[1]);
78 |
79 | DecodeAcpiTable(tableId);
80 | }
81 | else
82 | {
83 | var tableIds = FirmwareTables.EnumFirmwareTables(tableType);
84 |
85 | foreach (var tableId in tableIds)
86 | {
87 | DecodeAcpiTable(tableId);
88 | Console.WriteLine();
89 | }
90 | }
91 | }
92 | #if false
93 | else if (_commandLineParser.IsOptionSet("i", "info"))
94 | {
95 | var tableIds = FirmwareTables.EnumFirmwareTables(FirmwareTableType.Acpi);
96 |
97 | foreach (var tableId in tableIds)
98 | {
99 | var acpiTable = FirmwareTables.GetAcpiTable(tableId);
100 | switch (acpiTable.Signature.ToUpper())
101 | {
102 | case "DBGP":
103 | break;
104 | }
105 | }
106 | }
107 | #endif
108 | else
109 | {
110 | Help();
111 | }
112 |
113 | return 0;
114 | }
115 |
116 | private void DecodeAcpiTable(UInt32 tableId)
117 | {
118 | var tableIdString = FirmwareTables.UInt32ToString(tableId);
119 | Console.WriteLine("=== '{0}' ACPI table 0x{1:X8} or '{2}'", tableIdString.Reverse(), tableId, tableIdString);
120 |
121 | var acpiTable = FirmwareTables.GetAcpiTable(tableId);
122 | Console.WriteLine("Table size: {0:N0} bytes", acpiTable.RawData.Length);
123 |
124 | Console.WriteLine("--- ACPI table header");
125 | Console.WriteLine("Signature: '{0}'", acpiTable.Signature);
126 | Console.WriteLine("Length: {0:N0} bytes", acpiTable.Length);
127 | Console.WriteLine("Revision: {0:N0}", acpiTable.Revision);
128 | Console.WriteLine("Checksum: 0x{0:X2} - {1}OK", acpiTable.Checksum, acpiTable.ChecksumIsValid ? "" : "NOT ");
129 | Console.WriteLine("OEM ID: '{0}'", acpiTable.OemId);
130 | Console.WriteLine("OEM Table ID: '{0}'", acpiTable.OemTableId);
131 | Console.WriteLine("OEM Revison: {0}", acpiTable.OemRevision);
132 | Console.WriteLine("Creator ID: '{0}'", acpiTable.CreatorId);
133 | Console.WriteLine("Creator Revison: {0} or 0x{0:X8}", acpiTable.CreatorRevision);
134 | Console.WriteLine("--- ACPI table payload");
135 | Console.WriteLine("Length: {0:N0} bytes", acpiTable.Payload.Length);
136 | PrintArray(acpiTable.Payload);
137 | }
138 |
139 | private UInt32 MakeUInt32(String param)
140 | {
141 | param = param.ToUpper();
142 |
143 | if (4 == param.Length)
144 | {
145 | return FirmwareTables.StringToUInt32(param);
146 | }
147 |
148 | if (param.StartsWith("0X"))
149 | {
150 | param = param.Substring(2);
151 | }
152 |
153 | return Convert.ToUInt32(param, 16);
154 | }
155 |
156 | private String FormatFileName(UInt32 tableType, UInt32 tableId)
157 | {
158 | return String.Format("{0:X8}_{1:X8}.bin", tableType, tableId);
159 | }
160 |
161 | private void PrintArray(Byte[] array)
162 | {
163 | const int rowLength = 16;
164 | var rows = (array.Length - 1) / rowLength + 1;
165 | var first = 0;
166 | var index = 0;
167 | for (var row = 1; row <= rows; row++)
168 | {
169 | Console.Write("{0:X6}: ", first);
170 |
171 | var chars = "";
172 | for (var i = 0; i < rowLength; i++)
173 | {
174 | if (index < array.Length)
175 | {
176 | var c = array[index];
177 | Console.Write("{0:X2} ", c);
178 | chars += c < 32 ? ' ' : (char)c;
179 | index++;
180 | }
181 | else
182 | {
183 | Console.Write(" ");
184 | }
185 | }
186 |
187 | Console.WriteLine(" {0}", chars);
188 |
189 | first += 16;
190 | }
191 | }
192 |
193 | protected override void Help()
194 | {
195 | Console.WriteLine("FirmwareTables {0} | https://github.com/vurdalakov/firmwaretables\n", ApplicationVersion);
196 | Console.WriteLine("Lists, extracts and decodes system firmware tables.\n");
197 | Console.WriteLine("Usage:\n\tfirmwaretables <-list | -all | -save | -decode [filename]> [-silent]\n");
198 | Console.WriteLine("Commands:\n\t-l - list available system firmware tables\n\t-a - save all system firmware tables to files\n\t-s - save specific system firmware table to file\n\t-d - decode specific system firmware table\n");
199 | Console.WriteLine("Options:\n\t-silent - no error messages are shown; check exit code\n");
200 | Console.WriteLine("Exit codes:\n\t0 - operation succeeded\n\t1 - operation failed\n\t-1 - invalid command line syntax\n");
201 |
202 | base.Help();
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/src/firmwaretables/FirmwareTables.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Runtime.InteropServices;
7 |
8 | public enum FirmwareTableType : UInt32
9 | {
10 | Acpi = 0x41435049,
11 | Firm = 0x4649524D,
12 | Rsmb = 0x52534D42
13 | }
14 |
15 | public static class FirmwareTables
16 | {
17 | public static UInt32[] EnumFirmwareTables(FirmwareTableType tableType)
18 | {
19 | return EnumFirmwareTables((UInt32)tableType);
20 | }
21 |
22 | public static UInt32[] EnumFirmwareTables(String tableType)
23 | {
24 | return EnumFirmwareTables(StringToUInt32(tableType));
25 | }
26 |
27 | public static UInt32[] EnumFirmwareTables(UInt32 tableType)
28 | {
29 | var bufferSize = EnumSystemFirmwareTables(tableType, IntPtr.Zero, 0);
30 | if (0 == bufferSize)
31 | {
32 | ThrowWin32Exception("EnumSystemFirmwareTables");
33 | }
34 |
35 | var buffer = Marshal.AllocHGlobal((Int32)bufferSize);
36 |
37 | var result = EnumSystemFirmwareTables(tableType, buffer, bufferSize);
38 | if (0 == result)
39 | {
40 | ThrowWin32Exception("EnumSystemFirmwareTables");
41 | }
42 |
43 | var byteArray = ReadByteArray(buffer, 0, (Int32)bufferSize);
44 |
45 | var firmwareTables = new List();
46 |
47 | for (int i = 0; i < byteArray.Length; i += sizeof(UInt32))
48 | {
49 | var firmwareTable = BitConverter.ToUInt32(byteArray, i);
50 | firmwareTables.Add(firmwareTable);
51 | }
52 |
53 | return firmwareTables.ToArray();
54 | }
55 |
56 | public static Byte[] GetFirmwareTable(FirmwareTableType tableType, String tableId)
57 | {
58 | return GetFirmwareTable((UInt32)tableType, StringToUInt32(tableId));
59 | }
60 |
61 | public static Byte[] GetFirmwareTable(FirmwareTableType tableType, UInt32 tableId)
62 | {
63 | return GetFirmwareTable((UInt32)tableType, tableId);
64 | }
65 |
66 | public static Byte[] GetFirmwareTable(String tableType, String tableId)
67 | {
68 | return GetFirmwareTable(StringToUInt32(tableType), StringToUInt32(tableId));
69 | }
70 |
71 | public static Byte[] GetFirmwareTable(UInt32 tableType, UInt32 tableId)
72 | {
73 |
74 | var firmwareTables = new List();
75 |
76 | var bufferSize = GetSystemFirmwareTable(tableType, tableId, IntPtr.Zero, 0);
77 | if (0 == bufferSize)
78 | {
79 | ThrowWin32Exception("GetSystemFirmwareTable");
80 | }
81 |
82 | var buffer = Marshal.AllocHGlobal((Int32)bufferSize);
83 |
84 | var result = GetSystemFirmwareTable(tableType, tableId, buffer, bufferSize);
85 | if (0 == result)
86 | {
87 | ThrowWin32Exception("GetSystemFirmwareTable");
88 | }
89 |
90 | return ReadByteArray(buffer, 0, (Int32)bufferSize);
91 | }
92 |
93 | public static AcpiTable GetAcpiTable(String tableId)
94 | {
95 | return GetAcpiTable(StringToUInt32(tableId));
96 | }
97 |
98 | public static AcpiTable GetAcpiTable(UInt32 tableId)
99 | {
100 | var data = FirmwareTables.GetFirmwareTable(FirmwareTableType.Acpi, tableId);
101 | return new AcpiTable(data);
102 | }
103 |
104 | public static UInt32 StringToUInt32(String tableType)
105 | {
106 | if (String.IsNullOrWhiteSpace(tableType) || (tableType.Length != 4))
107 | {
108 | throw new ArgumentException();
109 | }
110 |
111 | return ((UInt32)tableType[0] << 24) | ((UInt32)tableType[1] << 16) | ((UInt32)tableType[2] << 8) | (UInt32)tableType[3];
112 | }
113 |
114 | public static String UInt32ToString(UInt32 tableType)
115 | {
116 | var tableTypeString = "";
117 |
118 | tableTypeString += (char)((tableType >> 24) & 0xFF);
119 | tableTypeString += (char)((tableType >> 16) & 0xFF);
120 | tableTypeString += (char)((tableType >> 8) & 0xFF);
121 | tableTypeString += (char)((tableType >> 0) & 0xFF);
122 |
123 | return tableTypeString;
124 | }
125 |
126 | private static void ThrowWin32Exception(String functionName, String format = null, params Object[] args)
127 | {
128 | var ex = new Win32Exception();
129 | var message = String.Format("{0}() function call failed with error {1}: {2}", functionName, ex.NativeErrorCode, ex.Message);
130 | throw new Exception(message, ex);
131 | }
132 |
133 | private static Byte[] ReadByteArray(IntPtr source, Int32 startIndex, Int32 length)
134 | {
135 | var byteArray = new Byte[length];
136 | Marshal.Copy(source, byteArray, startIndex, length);
137 | return byteArray;
138 | }
139 |
140 | [DllImport("kernel32.dll", SetLastError = true)]
141 | private static extern UInt32 EnumSystemFirmwareTables(UInt32 firmwareTableProviderSignature, IntPtr firmwareTableBuffer, UInt32 bufferSize);
142 |
143 | [DllImport("kernel32.dll", SetLastError = true)]
144 | private static extern UInt32 GetSystemFirmwareTable(UInt32 firmwareTableProviderSignature, UInt32 firmwareTableID, IntPtr firmwareTableBuffer, UInt32 bufferSize);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/firmwaretables/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Vurdalakov
2 | {
3 | using System;
4 |
5 | class Program
6 | {
7 | static void Main(String[] args)
8 | {
9 | var application = new Application();
10 | application.Run();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/firmwaretables/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FirmwareTables")]
9 | [assembly: AssemblyDescription("Lists, extracts and decodes system firmware tables.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Vurdalakov")]
12 | [assembly: AssemblyProduct("FirmwareTables")]
13 | [assembly: AssemblyCopyright("Copyright © 2016 Vurdalakov")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("6a4828a3-191e-4e1b-841e-05f0dfacfbb8")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.1.*")]
36 | [assembly: AssemblyFileVersion("1.1.0.0")]
37 |
--------------------------------------------------------------------------------
/src/firmwaretables/firmwaretables.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6A4828A3-191E-4E1B-841E-05F0DFACFBB8}
8 | Exe
9 | Properties
10 | Vurdalakov
11 | firmwaretables
12 | v4.0
13 | 512
14 |
15 |
16 | $(SolutionDir)..\obj\
17 | $(SolutionDir)..\bin\
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | ..\..\bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | ..\..\bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | Common\CommandLineParser.cs
50 |
51 |
52 | Common\DosToolsApplication.cs
53 |
54 |
55 | Common\StringExtensions.cs
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
72 |
--------------------------------------------------------------------------------