├── .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 | --------------------------------------------------------------------------------