├── README.md ├── parser ├── PyWMIPersistenceFinder │ ├── PyWMIPersistenceFinder.exe │ ├── PyWMIPersistenceFinder.py │ └── README.md ├── Secure2Csv64 │ ├── LICENSE.md │ ├── Secure2Csv64.exe │ ├── changelog.txt │ └── readme.txt ├── amcache.exe ├── browsinghistoryview-x64 │ ├── BrowsingHistoryView.chm │ ├── BrowsingHistoryView.exe │ └── readme.txt ├── lpslib │ ├── LPSLibrary_CDI.XML │ ├── evtx_1.sql │ ├── evtx_100,106,140,141,200.sql │ ├── evtx_104,1102.sql │ ├── evtx_12,13.sql │ ├── evtx_4624-10.sql │ ├── evtx_4624-3.sql │ ├── evtx_4648.sql │ ├── evtx_6008.sql │ └── evtx_7045.sql ├── mft.exe ├── networkusageview-x64 │ ├── NetworkUsageView.chm │ ├── NetworkUsageView.exe │ └── readme.txt ├── ntuser.txt ├── prefetch.exe ├── regruns.exe ├── shimcache.exe ├── software.txt ├── system.txt └── usnjrnl.exe └── src ├── mft ├── LICENSE ├── Makefile ├── include │ ├── attribute.h │ ├── filerecord.h │ ├── mft.h │ └── utils.h ├── lib │ ├── filerecord.cpp │ ├── filerecord_csv.cpp │ ├── mft.cpp │ └── utils.cpp └── src │ └── main.cpp ├── python ├── amcache.py ├── libMSCompression.so ├── parserutility.py ├── prefetch.py ├── requirements.txt └── usnjrnl.py ├── regruns ├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── RECmd │ ├── App.config │ ├── NLog.config │ ├── NLog.xsd │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Registry.dll │ ├── list │ │ ├── ntuser.txt │ │ ├── software.txt │ │ └── system.txt │ ├── packages.config │ └── regruns.csproj ├── ntuser.txt ├── regruns.sln ├── software.txt └── system.txt └── shimcache ├── .gitattributes ├── .gitignore ├── AppCompatCache ├── AppCompatCache.cs ├── AppCompatCache.csproj ├── AppCompatCache.v2.ncrunchproject ├── CacheEntry.cs ├── IAppCompatCache.cs ├── Properties │ └── AssemblyInfo.cs ├── VistaWin2kWin2k8.cs ├── Windows10.cs ├── Windows7.cs ├── Windows8x.cs ├── app.config └── packages.config ├── AppCompatCacheParser.v2.ncrunchsolution ├── AppCompatCacheParser ├── AppCompatCacheParser.v2.ncrunchproject ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Settings.Designer.cs │ └── Settings.settings ├── Registry.dll ├── app.config ├── packages.config └── shimcache.csproj ├── AppCompatCacheParserTest ├── AppCompatCacheTest.cs ├── AppCompatCacheTest.csproj ├── AppCompatCacheTest.v2.ncrunchproject ├── Properties │ └── AssemblyInfo.cs ├── TestFiles │ ├── ReadMe.txt │ ├── Win10.bin │ ├── Win80.bin │ ├── Win81.bin │ ├── win7x64.bin │ └── win7x86.bin ├── app.config └── packages.config ├── LICENSE.md ├── README.md └── shimcache.sln /README.md: -------------------------------------------------------------------------------- 1 | # cdir-analyzer (parser) 2 | 3 | ## 概要 4 | 5 | cdir-analyzer (parser)はcdir-collectorで収集したデータのパーサ群です。 6 | 7 | ## 内容 8 | 9 | * browsinghistoryview-x64 10 | * BrowsingHistoryView.exe - Webブラウザ履歴のパーサ 11 | * lpslib 12 | * LPSLibrary_CDI.XML - Log Parser Studio用のライブラリ 13 | * evtx_イベントID.sql - 特定のイベントIDのログを抽出するクエリ 14 | * networkusageview-x64 15 | * NetworkUsageView.exe - SRUM(SRUDB.dat)のパーサ 16 | * PyWMIPersistenceFinder 17 | * PyWMIPersistenceFinder.exe - WMI(OBJECTS.DATA)のパーサ 18 | * Secure2Csv64 19 | * Secure2Csv64.exe - $SECUREのパーサ 20 | * amcache.exe - Amcacheのパーサ 21 | * mft.exe - MFTのパーサ 22 | * ntuser.txt - regruns.exeで読み込むリストファイル 23 | * prefetch.exe - プリフェッチのパーサ 24 | * regruns.exe - Runキーなどの自動実行設定用キーのパーサ 25 | * shimcache.exe - AppCompatCacheキーのパーサ 26 | * software.txt - regruns.exeで読み込むリストファイル 27 | * system.txt - regruns.exeで読み込むリストファイル 28 | * usnjrnl.exe - UsnJrnlのパーサ 29 | 30 | ## 使い方 31 | 32 | ### BrowsingHistoryView.exe 33 | 34 | https://www.nirsoft.net/utils/browsing_history_view.html を参照してください。 35 | 36 | ### NetworkUsageView.exe 37 | 38 | https://www.nirsoft.net/utils/network_usage_view.html を参照してください。 39 | 40 | ### PyWMIPersistenceFinder.exe 41 | 42 | https://github.com/davidpany/WMI_Forensics を参照してください。 43 | 44 | ### Secure2Csv64 45 | 46 | https://github.com/jschicht/Secure2Csv を参照してください。 47 | 48 | ### その他のパーサ 49 | 50 | コマンドプロンプト上で以下の形式で実行します。 51 | 52 | `> プログラム -o 出力フォルダ 入力ファイルもしくは入力フォルダ` 53 | 54 | 入力ファイルは解析したいファイル、入力フォルダの場合はcdir-collectorで収集したデータフォルダを指定します。パース結果は、出力フォルダ配下に「プログラム名_output.csv」のファイル名規則で、タブ区切り、UTF-8で結果を出力します。 55 | -------------------------------------------------------------------------------- /parser/PyWMIPersistenceFinder/PyWMIPersistenceFinder.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/PyWMIPersistenceFinder/PyWMIPersistenceFinder.exe -------------------------------------------------------------------------------- /parser/PyWMIPersistenceFinder/README.md: -------------------------------------------------------------------------------- 1 | # WMI_Forensics 2 | This repository contains scripts used to find evidence in WMI repositories, specifically OBJECTS.DATA files located at: 3 | 4 | - C:\WINDOWS\system32\wbem\Repository\OBJECTS.DATA 5 | - C:\WINDOWS\system32\wbem\Repository\FS\OBJECTS.DATA 6 | 7 | ## CCM_RUA_Finder.py 8 | CCM_RUA_finder.py extracts SCCM software metering RecentlyUsedApplication logs from OBJECTS.DATA files. 9 | 10 | ### Usage 11 | ``` 12 | CCM_RUA_Finder.py -i path\to\OBJECTS.DATA -o path\to\output.xls 13 | ``` 14 | 15 | The output file will be TSV formatted. Excel will automatically parse TSV files with .xls extensions. 16 | 17 | ## PyWMIPersistenceFinder.py 18 | PyWMIPersistenceFinder.py is designed to find WMI persistence via FitlerToConsumerBindings 19 | solely by keyword searching the OBJECTS.DATA file without parsing the full WMI repository. 20 | 21 | In testing, this script has found the exact same data as python-cim's 22 | show_FilterToConsumerBindings.py without requiring the setup. Only further testing will 23 | indicate if this script misses any data that python-cim can find. 24 | 25 | In theory, this script will detect FilterToConsumerBindings that are deleted and remain 26 | in unallocated WMI space, but I haven't had a chance to test yet. 27 | 28 | ### Usage 29 | ```PyWMIPersistenceFinder.py ``` 30 | 31 | The output is text based in the following format for each binding: 32 | ``` 33 | - 34 | 35 | Consumer: 36 | Filter: 37 | ``` 38 | 39 | # Contact 40 | David Pany - Mandiant (FireEye) - 2017 41 | 42 | Twitter: @DavidPany 43 | 44 | Please send comments, bug reports, and questions to @DavidPany or push changes directly to GitHub 45 | 46 | -------------------------------------------------------------------------------- /parser/Secure2Csv64/Secure2Csv64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/Secure2Csv64/Secure2Csv64.exe -------------------------------------------------------------------------------- /parser/Secure2Csv64/changelog.txt: -------------------------------------------------------------------------------- 1 | 2 | v1.0.0.9 3 | Fixed a bug that caused undocumented IdentifierAuthority values to not display the correct decimal value in the SID. 4 | Removed unused variables. 5 | 6 | v1.0.0.8 7 | Moved the import sql files into the new import-sql sub directory so that compilation works with the project as is. 8 | 9 | v1.0.0.7 10 | Fixed a bug that caused commandline mode to crash when using either $SDH or $SII as input. 11 | Fixed a bug that caused the $SII and $SDH parsers to sometimes throw a warning about invalid INDX signature. 12 | Added a an output logfile for writing verbose information. 13 | Removed the output files Secure__FixedSII.bin and Secure__FixedSDH.bin that seemed useless. 14 | 15 | v1.0.0.6 16 | Added support for command line mode. 17 | Added option to specify output directory. 18 | Implemented support for importing output into MySql database. An sql with schema, and an autogenerated sql for importing of csv is added. 19 | 20 | v1.0.0.5 21 | Fixed incorrect decode of GUID's. 22 | 23 | v1.0.0.4 24 | Added support for parsing $SII and $SDH indexes from $INDEX_ROOT attribute. 25 | 26 | v1.0.0.3 27 | Renamed program from SecureParser to Secure2Csv. 28 | 29 | v1.0.0.2 30 | First official version. -------------------------------------------------------------------------------- /parser/Secure2Csv64/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/Secure2Csv64/readme.txt -------------------------------------------------------------------------------- /parser/amcache.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/amcache.exe -------------------------------------------------------------------------------- /parser/browsinghistoryview-x64/BrowsingHistoryView.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/browsinghistoryview-x64/BrowsingHistoryView.chm -------------------------------------------------------------------------------- /parser/browsinghistoryview-x64/BrowsingHistoryView.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/browsinghistoryview-x64/BrowsingHistoryView.exe -------------------------------------------------------------------------------- /parser/lpslib/evtx_1.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_1.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_100,106,140,141,200.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_100,106,140,141,200.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_104,1102.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_104,1102.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_12,13.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_12,13.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_4624-10.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_4624-10.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_4624-3.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_4624-3.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_4648.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_4648.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_6008.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_6008.sql -------------------------------------------------------------------------------- /parser/lpslib/evtx_7045.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/lpslib/evtx_7045.sql -------------------------------------------------------------------------------- /parser/mft.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/mft.exe -------------------------------------------------------------------------------- /parser/networkusageview-x64/NetworkUsageView.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/networkusageview-x64/NetworkUsageView.chm -------------------------------------------------------------------------------- /parser/networkusageview-x64/NetworkUsageView.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/networkusageview-x64/NetworkUsageView.exe -------------------------------------------------------------------------------- /parser/networkusageview-x64/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NetworkUsageView v1.20 5 | Copyright (c) 2017 - 2020 Nir Sofer 6 | Web site: http://www.nirsoft.net 7 | 8 | 9 | 10 | Description 11 | =========== 12 | 13 | NetworkUsageView extracts and displays the network usage information 14 | stored in the SRUDB.dat database of Windows 8 and Windows 10. The network 15 | usage data is collected every hour by Windows operating systems and 16 | includes the following information: The name and description of the 17 | service or application, the name and SID of the user, the network 18 | adapter, and the total number of bytes sent and received by the specified 19 | service/application. 20 | 21 | 22 | 23 | System Requirements 24 | =================== 25 | 26 | This tools works on Windows 8 and Windows 10. Previous versions of 27 | Windows are not supported because the operating system doesn't collect 28 | the network usage information. 29 | 30 | 31 | 32 | Versions History 33 | ================ 34 | 35 | 36 | * Version 1.20: 37 | o Added new columns: Network Adapter Guid, Network Adapter Luid, 38 | Connection Name. 39 | o Added support for retrieving the network adapter information from 40 | the Registry of the remote computer. 41 | o Added support for retrieving the network adapter information from 42 | the system hive of external drive. 43 | 44 | * Version 1.13: 45 | o Added 'Add Header Line To CSV/Tab-Delimited File' option (Turned 46 | on by default). 47 | 48 | * Version 1.12: 49 | o Added 'Save All Items' option (Shift+Ctrl+S). 50 | 51 | * Version 1.11: 52 | o You can now send the data to stdout by specifying empty string as 53 | filename, for example: 54 | NetworkUsageView.exe /scomma "" | more 55 | o The properties window is now resizable. You can now resize the 56 | properties window, and the last size/position of this window is saved 57 | in the .cfg file. 58 | 59 | * Version 1.10: 60 | o Added new display modes: 'Display summary by app', 'Display 61 | summary by user', 'Display summary by app And user'. You can choose 62 | them from the 'Advanced Options' window (F9). 63 | o Added 'App ID' column. 64 | o Fixed bug: On some systems, NetworkUsageView failed to access the 65 | SRUDB.dat database but didn't offer the user to run it as admin for 66 | accessing the file. 67 | 68 | * Version 1.07: 69 | o Added new options to the 'Quick Filter' feature. 70 | 71 | * Version 1.06: 72 | o Added option to choose another font (name and size) to display in 73 | the main window. 74 | 75 | * Version 1.05: 76 | o You can now use any variable inside the .cfg file as command-line 77 | parameter in order to set the configuration from command line, for 78 | example - the following command processes external SRUDB.dat database 79 | and exports the result into .csv file: 80 | NetworkUsageView.exe /LoadFrom 2 /ExternalFilename 81 | "c:\temp\SRUDB64.dat" /scomma c:\temp\nuv.csv 82 | 83 | * Version 1.00 - First release. 84 | 85 | 86 | 87 | Start Using NetworkUsageView 88 | ============================ 89 | 90 | NetworkUsageView doesn't require any installation process or additional 91 | DLL files. In order to start using it, simply run the executable file - 92 | NetworkUsageView.exe 93 | 94 | After running NetworkUsageView - if the SRUDB.dat database file is locked 95 | , NetworkUsageView will ask you whether you want to run it as 96 | administrator in order to access the locked file. If the file is not 97 | locked, NetworkUsageView will load it instantly. 98 | 99 | 100 | 101 | 'Advanced Options' Window 102 | ========================= 103 | 104 | In the 'Advanced Options' window (F9), you can choose to load the 105 | SRUDB.dat database from external drive or from a remote computer on your 106 | network. Be aware that loading the network usage information from a 107 | remote computer works only when the database file on the remote computer 108 | is not locked. 109 | 110 | You can also choose to load the network usage data from the last xx days 111 | hours or from the specified date/time range. 112 | 113 | 114 | 115 | NetworkUsageView Columns 116 | ======================== 117 | 118 | 119 | * Record ID: The ID of the record in the SRUDB.dat database. 120 | * Timestamp: The date/time that this record was created. 121 | * App Name: The name if the application or service. 122 | * App Description: The description of application or service. If the 123 | 'App Name' is .exe filename, the description is taken from the version 124 | resource of the .exe file. if the 'App Name' is a service, the 125 | description is taken from the description string of the service. 126 | * User Name: The name of the user according to the user SID specified 127 | in the SRUDB.dat database. This field is empty when reading a file from 128 | external drive. 129 | * User SID: SID of the user. 130 | * Bytes Sent: Total number of bytes that the specifies app/service sent. 131 | * Bytes Received: Total number of bytes that the specifies app/service 132 | received. 133 | * Network Adapter: The name of the network adapter that was used to 134 | send/receive data (This field is empty for remote and external drive 135 | modes). 136 | 137 | 138 | 139 | Command-Line Options 140 | ==================== 141 | 142 | 143 | 144 | /stext 145 | Save the network usage information into a simple text file. 146 | 147 | /stab 148 | Save the network usage information into a tab-delimited text file. 149 | 150 | /scomma 151 | Save the network usage information into a comma-delimited text file (csv). 152 | 153 | /stabular 154 | Save the network usage information into a tabular text file. 155 | 156 | /shtml 157 | Save the network usage information into HTML file (Horizontal). 158 | 159 | /sverhtml 160 | Save the network usage information into HTML file (Vertical). 161 | 162 | /sxml 163 | Save the network usage information into XML file. 164 | 165 | 166 | /LoadFrom [1 - 3] 167 | /ExternalFilename [External File] 168 | /RemoteComputer [Computer Name] 169 | . 170 | . 171 | . 172 | You can use any variable inside the .cfg file as command-line parameter 173 | in order to set the configuration from command line, For example: 174 | NetworkUsageView.exe /LoadFrom 2 /ExternalFilename "c:\temp\SRUDB64.dat" 175 | /scomma c:\temp\nuv.csv 176 | 177 | NetworkUsageView.exe /LoadFrom 3 /RemoteComputer "192.168.0.50" 178 | 179 | For all save command-line options, you can specify empty filename in 180 | order to send the data to stdout, for example: 181 | NetworkUsageView.exe /scomma "" | more 182 | 183 | 184 | 185 | Translating NetworkUsageView to other languages 186 | =============================================== 187 | 188 | In order to translate NetworkUsageView to other language, follow the 189 | instructions below: 190 | 1. Run NetworkUsageView with /savelangfile parameter: 191 | NetworkUsageView.exe /savelangfile 192 | A file named NetworkUsageView_lng.ini will be created in the folder of 193 | NetworkUsageView utility. 194 | 2. Open the created language file in Notepad or in any other text 195 | editor. 196 | 3. Translate all string entries to the desired language. Optionally, 197 | you can also add your name and/or a link to your Web site. 198 | (TranslatorName and TranslatorURL values) If you add this information, 199 | it'll be used in the 'About' window. 200 | 4. After you finish the translation, Run NetworkUsageView, and all 201 | translated strings will be loaded from the language file. 202 | If you want to run NetworkUsageView without the translation, simply 203 | rename the language file, or move it to another folder. 204 | 205 | 206 | 207 | License 208 | ======= 209 | 210 | This utility is released as freeware. You are allowed to freely 211 | distribute this utility via floppy disk, CD-ROM, Internet, or in any 212 | other way, as long as you don't charge anything for this and you don't 213 | sell it or distribute it as a part of commercial product. If you 214 | distribute this utility, you must include all files in the distribution 215 | package, without any modification ! 216 | 217 | 218 | 219 | Disclaimer 220 | ========== 221 | 222 | The software is provided "AS IS" without any warranty, either expressed 223 | or implied, including, but not limited to, the implied warranties of 224 | merchantability and fitness for a particular purpose. The author will not 225 | be liable for any special, incidental, consequential or indirect damages 226 | due to loss of data or any other reason. 227 | 228 | 229 | 230 | Feedback 231 | ======== 232 | 233 | If you have any problem, suggestion, comment, or you found a bug in my 234 | utility, you can send a message to nirsofer@yahoo.com 235 | -------------------------------------------------------------------------------- /parser/ntuser.txt: -------------------------------------------------------------------------------- 1 | SOFTWARE\Classes\Exefile\Shell\Open\Command\ 2 | SOFTWARE\Microsoft\Command Processor\Autorun 3 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 4 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 5 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 6 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 7 | SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 8 | SOFTWARE\Microsoft\Windows\CurrentVersion\Run 9 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce 10 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices 11 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce 12 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 13 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run 14 | Environment 15 | -------------------------------------------------------------------------------- /parser/prefetch.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/prefetch.exe -------------------------------------------------------------------------------- /parser/regruns.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/regruns.exe -------------------------------------------------------------------------------- /parser/shimcache.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/shimcache.exe -------------------------------------------------------------------------------- /parser/software.txt: -------------------------------------------------------------------------------- 1 | Classes\Exefile\Shell\Open\Command 2 | Microsoft\Active Setup\Installed Components 3 | Microsoft\SchedulingAgent 4 | Microsoft\Windows NT\CurrentVersion\Drivers32 5 | Microsoft\Windows NT\CurrentVersion\Image File Execution Options 6 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 7 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 8 | Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 9 | Microsoft\Windows NT\CurrentVersion\Winlogon\Notify 10 | Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 11 | Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList 12 | Microsoft\Windows NT\CurrentVersion\Winlogon\System 13 | Microsoft\Windows NT\CurrentVersion\Winlogon\Taskman 14 | Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 15 | Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 16 | Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 17 | Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 18 | Microsoft\Windows\CurrentVersion\Run 19 | Microsoft\Windows\CurrentVersion\RunOnce 20 | Microsoft\Windows\CurrentVersion\RunServices 21 | Microsoft\Windows\CurrentVersion\Shell Extensions\Approved 22 | Wow6432Node\Microsoft\Active Setup\Installed Components 23 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32 24 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 25 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 26 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 27 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 28 | Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 29 | Wow6432Node\Microsoft\Windows\CurrentVersion\Run 30 | Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce 31 | -------------------------------------------------------------------------------- /parser/system.txt: -------------------------------------------------------------------------------- 1 | Control\Lsa\Authentication Packages 2 | Control\Lsa\Notification Packages 3 | Control\Lsa\Security Packages 4 | Control\SecurityProviders\SecurityProviders 5 | Control\Session Manager\AppCertDlls 6 | Control\Session Manager\CWDIllegalInDllSearch 7 | -------------------------------------------------------------------------------- /parser/usnjrnl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/parser/usnjrnl.exe -------------------------------------------------------------------------------- /src/mft/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2017 Cyber Defense Institute, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/mft/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CFLAGS := -std=gnu++1z -O3 -static 3 | INCLUDE := -I./include/ 4 | LIBS := lib/*.cpp 5 | SRCS := src/*.cpp 6 | INCLUDES := include/*.h 7 | #DEBUG := -DDEBUG 8 | 9 | all: $(SRCS) $(INCLUDES) $(LIBS) 10 | # $(CC) $(DEBUG) $(CFLAGS) $(INCLUDE) $(LIBS) $(SRCS) -o mft 11 | $(CC) $(CFLAGS) $(INCLUDE) $(LIBS) $(SRCS) -o mft 12 | -------------------------------------------------------------------------------- /src/mft/include/attribute.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_ATTRIBUTE_H 2 | #define _INCLUDE_ATTRIBUTE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma pack(1) 10 | 11 | const unsigned char END_OF_ATTR[4] = {0xff, 0xff, 0xff, 0xff}; 12 | 13 | 14 | // ATTRIBUTE 15 | 16 | enum ATTRTYPEID { 17 | ATTRTYPEID_STANDARD_INFORMATION = 0x10, 18 | ATTRTYPEID_ATTRIBUTE_LIST = 0x20, 19 | ATTRTYPEID_FILE_NAME = 0x30, 20 | ATTRTYPEID_DATA = 0x80, 21 | }; 22 | 23 | 24 | 25 | // $STANDARD_INFORMATION 26 | 27 | enum FILE_FLAGS { 28 | READ_ONLY = 0x0001, 29 | HIDDEN = 0x0002, 30 | SYSTEM = 0x0004, 31 | ARCHIVE = 0x0020, 32 | DEVICE = 0x0040, 33 | NORMAL = 0x0080, 34 | TEMPORARY = 0x0100, 35 | SPARSE_FILE = 0x0200, 36 | REPARSE_POINT = 0x0400, 37 | COMPRESSED = 0x0800, 38 | OFFLINE = 0x1000, 39 | NOT_INDEXED = 0x2000, 40 | ENCRYPTED = 0x4000 41 | }; 42 | 43 | struct ATTR_STANDARD_INFORMATION { 44 | uint64_t creationtime; 45 | uint64_t file_altered_time; 46 | uint64_t mft_altered_time; 47 | uint64_t file_accessed_time; 48 | uint32_t flags; 49 | uint32_t max_version; 50 | uint32_t version; 51 | uint32_t class_id; 52 | uint32_t owner_id; 53 | uint32_t security_id; 54 | uint64_t quota_charged; 55 | uint64_t usn; 56 | }; 57 | 58 | 59 | 60 | // $FILE_NAME 61 | 62 | struct ATTR_FILE_NAME { 63 | uint64_t parent_ref_mft_entry:48; 64 | uint64_t parent_ref_mft_seq:16; 65 | uint64_t creationtime; 66 | uint64_t file_altered_time; 67 | uint64_t mft_altered_time; 68 | uint64_t file_accessed_time; 69 | uint64_t alloc_size; 70 | uint64_t real_size; 71 | uint32_t flags; 72 | uint32_t reparse_val; 73 | uint8_t fname_len; 74 | uint8_t fname_space; 75 | char16_t *fname; 76 | }; 77 | 78 | 79 | 80 | // $ATTRIBUTE_LIST 81 | 82 | struct ATTR_ATTRIBUTE_LIST { 83 | uint32_t attr_type; 84 | uint16_t entry_len; 85 | uint8_t name_len; 86 | uint8_t name_offset; 87 | uint64_t start_vcn; 88 | uint64_t attr_file_ref_record:48; 89 | uint64_t attr_file_ref_seq:16; 90 | uint8_t attr_id; 91 | }; 92 | 93 | 94 | 95 | // ATTRIBUTE structure 96 | 97 | struct ATTR_HEADER_BASE { 98 | uint32_t attr_typeid; 99 | uint32_t attr_len; 100 | uint8_t flag_nonresident; 101 | uint8_t name_len; 102 | uint16_t name_offset; 103 | uint16_t flags; 104 | uint16_t attr_id; 105 | }; 106 | 107 | struct ATTR_HEADER_RESIDENT { 108 | ATTR_HEADER_BASE base; 109 | uint32_t size; 110 | uint16_t offset; 111 | uint8_t indx_flag; 112 | uint8_t _padd; 113 | }; 114 | 115 | struct ATTR_HEADER_NONRESIDENT { 116 | ATTR_HEADER_BASE base; 117 | uint64_t vcn_start; 118 | uint64_t vcn_end; 119 | uint16_t runlist_offset; 120 | uint16_t compression_unit_size; 121 | uint32_t _unused; 122 | uint64_t alloc_attr_size; 123 | uint64_t actual_attr_size; 124 | uint64_t init_attr_size; 125 | }; 126 | 127 | union ATTR_HEADER { 128 | ATTR_HEADER_BASE base; 129 | ATTR_HEADER_RESIDENT resident; 130 | ATTR_HEADER_NONRESIDENT nonresident; 131 | }; 132 | 133 | 134 | union ATTR_CONTENT { 135 | ATTR_STANDARD_INFORMATION standard_information; 136 | ATTR_FILE_NAME file_name; 137 | ATTR_ATTRIBUTE_LIST attribute_list; 138 | }; 139 | 140 | 141 | struct ATTR { 142 | ATTR_HEADER header; 143 | ATTR_CONTENT content; 144 | }; 145 | 146 | 147 | #endif // _INCLUDE_ATTRIBUTE_H 148 | -------------------------------------------------------------------------------- /src/mft/include/filerecord.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_FILERECORD_H 2 | #define _INCLUDE_FILERECORD_H 3 | 4 | #include 5 | #include 6 | 7 | #include "mft.h" 8 | #include "attribute.h" 9 | 10 | #ifndef _WIN32 11 | #define MAX_PATH 260 12 | #endif 13 | 14 | #pragma pack(1) 15 | 16 | extern bool lt; 17 | extern char tzstr[16]; 18 | extern std::string computername; 19 | 20 | using namespace std; 21 | 22 | struct FILE_RECORD { 23 | char signature[4]; 24 | uint16_t fixup_offset; 25 | uint16_t fixup_count; 26 | uint64_t lsn; 27 | uint16_t seq_val; 28 | uint16_t link_cnt; 29 | uint16_t fattr_offset; 30 | uint16_t flags; 31 | uint32_t used_size; 32 | uint32_t alloc_size; 33 | uint64_t baserecord_ref; 34 | uint16_t next_attrid; char _padd[2]; 35 | 36 | uint32_t record_num; 37 | uint16_t fixup; 38 | }; 39 | 40 | 41 | enum FILERECORD_FLAGS { 42 | FILE_DELETED = 0b00000000, 43 | FILE_ALLOCATED = 0b00010000, 44 | DIRECTORY_DELETED = 0b00100000, 45 | DIRECTORY_ALLOCATED = 0b00110000, 46 | }; 47 | 48 | struct CSVRecord { 49 | string filename; 50 | string pathname; 51 | uint64_t fileid; 52 | uint16_t flag; 53 | uint64_t filesize; 54 | uint64_t created; 55 | uint64_t modified; 56 | uint64_t recordchanged; 57 | uint64_t accessed; 58 | uint64_t created_fn; 59 | uint64_t modified_fn; 60 | uint64_t recordchanged_fn; 61 | uint64_t accessed_fn; 62 | uint32_t owner; 63 | uint32_t security; 64 | string misc; 65 | int ns_tmp; // for calc: which FILE_NAME to take 66 | }; 67 | 68 | struct RESIDENT_DATA { 69 | char *name; 70 | unsigned int len; 71 | unsigned char *data; 72 | }; 73 | 74 | 75 | class MFT; 76 | 77 | class FileRecord { 78 | public: 79 | enum ERROR { 80 | ERROR_EOF = -1, 81 | ERROR_BADSIGNATURE = -2, 82 | }; 83 | 84 | private: 85 | uint16_t bytes_per_sector; 86 | uint32_t record_size; 87 | bool parsed; 88 | MFT *mft; 89 | FILE *fp_head; 90 | uint64_t offset; 91 | unsigned char *data; 92 | 93 | public: 94 | uint32_t record_num; 95 | FILE_RECORD record; 96 | CSVRecord csvrecord; 97 | vector attrs; 98 | string fname; 99 | vector resident_data; 100 | 101 | // info 102 | 103 | public: 104 | FileRecord(MFT*, uint64_t); 105 | int ReadRecord(); 106 | int VerifyFixup(); 107 | 108 | // for normal dump 109 | int ParseRecord(bool dump=false); 110 | int ParseAttrs(unsigned char*, bool dump=false); 111 | int ParseAttr(ATTR, unsigned char*, bool dump=false); 112 | 113 | // for CSV dump 114 | int ParseRecord_csv(); 115 | int ParseAttrs_csv(unsigned char*); 116 | int ParseAttr_csv(ATTR, unsigned char*); 117 | 118 | void printFileName(uint64_t); 119 | string getFileName(uint64_t); 120 | }; 121 | 122 | #endif // _INCLUDE_FILERECORD_H 123 | -------------------------------------------------------------------------------- /src/mft/include/mft.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_MFT_H 2 | #define _INCLUDE_MFT_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "filerecord.h" 11 | #include "attribute.h" 12 | 13 | #pragma pack(1) 14 | 15 | 16 | using namespace std; 17 | 18 | 19 | class FileRecord; 20 | 21 | class MFT { 22 | public: 23 | uint16_t bytes_per_sector; 24 | uint8_t sectors_per_clustor; 25 | uint8_t clustors_per_filerecord; 26 | uint32_t record_size; 27 | FILE *fp_head; 28 | vector record_nums; 29 | map record_table; // record_num to offset 30 | map filename; 31 | map ref_table; 32 | 33 | public: 34 | MFT(char*, int); 35 | MFT(char*, 36 | uint16_t bytes_per_sector=512, 37 | uint8_t sectors_per_clustor=2, 38 | uint8_t clustors_per_filerecord=1); 39 | int parse(uint32_t, FileRecord*, bool=true); 40 | int parse_csv(uint32_t, FileRecord*); 41 | }; 42 | 43 | #endif // _INCLUDE_MFT_H 44 | -------------------------------------------------------------------------------- /src/mft/include/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void hexdump(void*, unsigned int); 7 | void parse_time(uint64_t, bool); 8 | string UTF16toUTF8(char16_t*, int); 9 | void printUTF16(char16_t*, int); 10 | string convUTF16(char16_t*, int); 11 | void escapeDoubleQuote (std::string& str); 12 | bool isDir(const char *); 13 | bool isFile(const char *); 14 | string findFile(const char*, const char*); 15 | -------------------------------------------------------------------------------- /src/mft/lib/filerecord.cpp: -------------------------------------------------------------------------------- 1 | #include "filerecord.h" 2 | #include "utils.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | FileRecord::FileRecord(MFT* _mft, uint64_t _offset) { 14 | parsed = false; 15 | fp_head = _mft->fp_head; 16 | record_size = _mft->record_size; 17 | offset = _offset; 18 | mft = _mft; 19 | 20 | record_num = -1; 21 | } 22 | 23 | 24 | int FileRecord::ReadRecord() { 25 | FILE *fp; 26 | unsigned char *p = (unsigned char*)malloc(record_size); 27 | 28 | fp = fp_head; 29 | fseek(fp, offset, SEEK_SET); 30 | if(fread(p, 1, record_size, fp) != record_size) { 31 | #ifdef DEBUG 32 | perror("fread"); 33 | #endif 34 | free(p); 35 | return ERROR_EOF; 36 | } 37 | 38 | if(strncmp((char*)p, "FILE", 4)) { 39 | free(p); 40 | return ERROR_BADSIGNATURE; 41 | } 42 | else { 43 | record_num = ((FILE_RECORD*)p)->record_num; 44 | } 45 | 46 | free(p); 47 | 48 | return 0; 49 | } 50 | 51 | 52 | int FileRecord::ParseRecord(bool dump) { 53 | FILE *fp = fp_head; 54 | 55 | data = (unsigned char*)malloc(record_size); 56 | 57 | fseek(fp, offset, SEEK_SET); 58 | if(fread(data, 1, record_size, fp) != record_size) { 59 | #ifdef DEBUG 60 | perror("fread"); 61 | #endif 62 | return ERROR_EOF; 63 | } 64 | 65 | memcpy(&(this->record), data, sizeof(FILE_RECORD)); 66 | 67 | if(strncmp(this->record.signature, "FILE", 4)) { 68 | fprintf(stderr, "Bad Signature: %s\n", this->record.signature); 69 | return ERROR_BADSIGNATURE; 70 | } 71 | record_num = this->record.record_num; 72 | 73 | parsed = true; 74 | 75 | if(dump) { 76 | printf("\nRecord Number: %lu\n", this->record.record_num); 77 | } 78 | 79 | VerifyFixup(); 80 | ParseAttrs(data+(this->record.fattr_offset), dump); 81 | 82 | if(dump) { 83 | printf("\n"); 84 | } 85 | 86 | free(data); 87 | 88 | return 0; 89 | } 90 | 91 | 92 | int FileRecord::ParseAttrs(unsigned char *p, bool dump) { 93 | // base 94 | unsigned char *tmp; 95 | uint32_t attrid; 96 | uint32_t header_size; 97 | ATTR attr; 98 | 99 | // FILE_NAME 100 | char16_t *fname; 101 | uint8_t fname_len; 102 | 103 | if(dump) { 104 | printf("ATTRIBUTES:\n"); 105 | } 106 | 107 | for(tmp = p; ; tmp += attr.header.base.attr_len) { 108 | if(!memcmp(tmp, END_OF_ATTR, 4)) break; 109 | memcpy(&attr, tmp, sizeof(ATTR_HEADER_BASE)); 110 | 111 | if(!attr.header.base.flag_nonresident) { // resident 112 | header_size = sizeof(ATTR_HEADER_RESIDENT); 113 | memcpy(&attr, tmp, header_size); 114 | } 115 | else { 116 | header_size = sizeof(ATTR_HEADER_NONRESIDENT); 117 | memcpy(&attr, tmp, header_size); 118 | } 119 | 120 | if(attr.header.base.name_len) { 121 | if(dump) { 122 | printf("Attribute Name: "); 123 | printUTF16((char16_t*)(tmp+(attr.header.base.name_offset)), attr.header.base.name_len); 124 | printf("\n"); 125 | } 126 | } 127 | 128 | ParseAttr(attr, tmp+header_size, dump); 129 | 130 | // this->attrs.push_back(attr); 131 | } 132 | 133 | return 0; 134 | } 135 | 136 | 137 | // parse each attribute (not including header) 138 | int FileRecord::ParseAttr(ATTR attr, unsigned char *content, bool dump) { 139 | // base 140 | unsigned char *p; 141 | bool nonresident; 142 | uint32_t attrid; 143 | uint32_t header_size; 144 | uint32_t content_size; 145 | 146 | // FILE_NAME 147 | char16_t *fname; 148 | uint8_t fname_len; 149 | 150 | // for ATTRIBUTE_LIST 151 | FileRecord *fr; 152 | uint32_t ref; 153 | 154 | RESIDENT_DATA *resdata; 155 | 156 | 157 | attrid = attr.header.base.attr_typeid; 158 | 159 | if(!attr.header.base.flag_nonresident) { 160 | nonresident = false; 161 | header_size = sizeof(ATTR_HEADER_RESIDENT); 162 | content_size = attr.header.base.attr_len - sizeof(ATTR_HEADER_RESIDENT); 163 | } 164 | else { 165 | nonresident = true; 166 | header_size = sizeof(ATTR_HEADER_NONRESIDENT); 167 | content_size = attr.header.base.attr_len - sizeof(ATTR_HEADER_NONRESIDENT); 168 | } 169 | 170 | switch(attrid) { 171 | case ATTRTYPEID_STANDARD_INFORMATION: 172 | if(dump) { 173 | printf("\n $STANDARD_INFORMATION\n"); 174 | } 175 | 176 | memcpy(&(attr.content), content, sizeof(ATTR_STANDARD_INFORMATION)); 177 | 178 | if(dump) { 179 | printf(" CreationTime: "); 180 | parse_time(attr.content.standard_information.creationtime, lt); 181 | printf("\n"); 182 | } 183 | 184 | break; 185 | 186 | 187 | case ATTRTYPEID_ATTRIBUTE_LIST: 188 | if(!dump) break; 189 | 190 | printf("\n $ATTRIBUTE_LIST (%s)\n", (nonresident?"nonresident":"resident")); 191 | 192 | for(unsigned char *c = content; 193 | c < content+content_size; 194 | c += attr.content.attribute_list.entry_len) { 195 | 196 | memcpy(&(attr.content), c, sizeof(ATTR_ATTRIBUTE_LIST)); 197 | 198 | switch(attr.content.attribute_list.attr_type) { 199 | case ATTRTYPEID_STANDARD_INFORMATION: 200 | printf(" $STANDARD_INFORMATION\n"); 201 | break; 202 | 203 | case ATTRTYPEID_FILE_NAME: 204 | printf(" $FILE_NAME\n"); 205 | ref = attr.content.attribute_list.attr_file_ref_record; 206 | fr = new FileRecord(mft, mft->record_table[ref]); 207 | if(!fr->ParseRecord(false)) { 208 | mft->ref_table[record_num] = mft->ref_table[ref]; 209 | mft->filename[record_num] = mft->filename[ref]; 210 | } 211 | else { 212 | #ifdef DEBUG 213 | fprintf(stderr, "parse error @ (%lu)", ref); 214 | #endif 215 | } 216 | delete(fr); 217 | break; 218 | 219 | case ATTRTYPEID_DATA: 220 | printf(" $DATA\n"); 221 | break; 222 | 223 | default: 224 | printf(" UNKNOWN(%x)\n", attr.content.attribute_list.attr_type); 225 | } 226 | 227 | // if(attr.content.attribute_list.name_len) { 228 | // printf(" %d ", attr.content.attribute_list.name_len); 229 | // hexdump(&(attr.content)+(attr.content.attribute_list.name_offset), 16); 230 | // printf(" Name: %s\n", &(attr.content)+(attr.content.attribute_list.name_offset)); 231 | // } 232 | // printUTF16((char16_t *)&(attr.content)+attr.content.attribute_list.name_offset, 233 | // attr.content.attribute_list.name_len); 234 | if(attr.content.attribute_list.start_vcn) { 235 | printf(" VCN: %lld\n", (uint64_t)attr.content.attribute_list.start_vcn); 236 | } 237 | 238 | if(attr.content.attribute_list.attr_file_ref_record) { 239 | printf(" record ref: %ld\n", (uint32_t)attr.content.attribute_list.attr_file_ref_record); 240 | } 241 | 242 | if(attr.content.attribute_list.attr_file_ref_seq) { 243 | printf(" seq ref: %ld\n", (uint32_t)attr.content.attribute_list.attr_file_ref_seq); 244 | } 245 | } 246 | 247 | break; 248 | 249 | 250 | case ATTRTYPEID_FILE_NAME: 251 | if(dump) { 252 | printf("\n $FILE_NAME\n"); 253 | } 254 | 255 | memcpy(&(attr.content), content, sizeof(ATTR_FILE_NAME)); 256 | 257 | fname_len = attr.content.file_name.fname_len; 258 | // printf("before malloc\n"); 259 | // fname = (char16_t*)malloc(sizeof(char16_t)*fname_len); 260 | // printf("after malloc\n"); 261 | // memcpy(fname, p+header_size+sizeof(ATTR_FILE_NAME)-sizeof(char16_t*), sizeof(char16_t)*fname_len); 262 | // attr.content.file_name.fname = fname; 263 | 264 | if(dump) { 265 | printf(" CreationTime: "); 266 | parse_time(attr.content.file_name.creationtime, lt); 267 | printf("\n"); 268 | } 269 | 270 | mft->ref_table[record_num] = attr.content.file_name.parent_ref_mft_entry; 271 | mft->filename[record_num] = UTF16toUTF8((char16_t*)(content+sizeof(ATTR_FILE_NAME)-sizeof(char16_t*)), fname_len); 272 | if(dump) { 273 | printf(" File Name: "); 274 | printFileName(record_num); 275 | printf("\n"); 276 | } 277 | else { 278 | this->fname = getFileName(record_num); 279 | } 280 | // printUTF16((char16_t*)(content+sizeof(ATTR_FILE_NAME)-sizeof(char16_t*)), fname_len); 281 | 282 | break; 283 | 284 | 285 | case ATTRTYPEID_DATA: 286 | if(dump) { 287 | printf("\n $DATA(%s)\n", (nonresident?"non-resident":"resident")); 288 | } 289 | 290 | if(!nonresident) { // resident 291 | if(dump) { 292 | printf(" File Size: %u\n", attr.header.resident.size); 293 | } 294 | if (attr.header.resident.size) { 295 | if((resdata = (RESIDENT_DATA*)malloc(sizeof(RESIDENT_DATA))) == NULL) { 296 | #ifdef DEBUG 297 | perror("malloc"); 298 | return -1; 299 | #endif 300 | } 301 | resdata->name = NULL; 302 | resdata->len = attr.header.resident.size; 303 | if((resdata->data = (unsigned char*)malloc(resdata->len)) == NULL) { 304 | #ifdef DEBUG 305 | perror("malloc"); 306 | return -1; 307 | #endif 308 | } 309 | for(int i = 0; i < attr.header.resident.size; i++) { 310 | *(resdata->data+i) = *((unsigned char*)content+(attr.header.resident.offset-header_size)+i); 311 | } 312 | if(attr.header.base.name_len) { // ADS 313 | resdata->name = (char*)UTF16toUTF8((char16_t*)((char*)(content-header_size)+attr.header.base.name_offset), attr.header.base.name_len).c_str(); 314 | } 315 | this->resident_data.push_back(resdata); 316 | } 317 | } 318 | else { 319 | if(dump) { 320 | printf(" File Size: %llu\n", attr.header.nonresident.actual_attr_size); 321 | } 322 | } 323 | 324 | break; 325 | 326 | 327 | default: 328 | #ifdef DEBUG 329 | fprintf(stderr, "\nAttribute ID %d is not implemented.\n", attrid); 330 | #endif 331 | return 0; 332 | } 333 | return 0; 334 | } 335 | 336 | 337 | int FileRecord::VerifyFixup() { 338 | uint16_t *fixups; 339 | uint16_t fixup_value; 340 | uint16_t fixup_offset; 341 | uint16_t fixup_count; 342 | uint16_t offset; 343 | 344 | fixup_offset = this->record.fixup_offset; 345 | fixup_count = this->record.fixup_count; 346 | memcpy(&fixup_value, data+fixup_offset, sizeof(uint16_t)); 347 | 348 | if(fixup_count) { 349 | fixups = (uint16_t*)malloc(sizeof(uint16_t)*fixup_count); 350 | memcpy(fixups, data+fixup_offset+sizeof(uint16_t), sizeof(uint16_t)*fixup_count); 351 | for(int i = 0; i < fixup_count-1; i++) { 352 | offset = this->mft->bytes_per_sector*(i+1)-2; 353 | 354 | if(memcmp(data+offset, &fixup_value, sizeof(uint16_t))) { 355 | fprintf(stderr, "fixup error at: %d\n", offset); 356 | } 357 | 358 | memcpy(data+offset, &fixups[i], sizeof(uint16_t)); 359 | } 360 | free(fixups); 361 | } 362 | 363 | return 0; 364 | } 365 | 366 | 367 | void FileRecord::printFileName(uint64_t ref) { 368 | if(ref == 5) { // "." root 369 | printf("C:"); 370 | return; 371 | } 372 | 373 | auto &filename = mft->filename; 374 | 375 | if(filename.find(ref) == filename.end()) { 376 | FileRecord fr(mft, mft->record_table[ref]); 377 | fr.ParseRecord(false); 378 | } 379 | 380 | printFileName(mft->ref_table[ref]); 381 | printf("\\%s", filename[ref].c_str()); 382 | } 383 | 384 | 385 | string FileRecord::getFileName(uint64_t ref) { 386 | string res; 387 | if(ref == 5) { // "." root 388 | res = "C:"; 389 | return res; 390 | } 391 | 392 | auto &filename = mft->filename; 393 | 394 | if(filename.find(ref) == filename.end()) { 395 | FileRecord fr(mft, mft->record_table[ref]); 396 | fr.ParseRecord(false); 397 | } 398 | 399 | if ( mft->ref_table.find(ref) != mft->ref_table.end()) { 400 | // avoid self recursion 401 | if(ref == mft->ref_table[ref]) { 402 | return res; 403 | } 404 | 405 | res = getFileName(mft->ref_table[ref]); 406 | res += "\\" + filename[ref]; 407 | return res; 408 | } else { 409 | res = "unknown"; 410 | return res; 411 | } 412 | 413 | } 414 | -------------------------------------------------------------------------------- /src/mft/lib/filerecord_csv.cpp: -------------------------------------------------------------------------------- 1 | #include "filerecord.h" 2 | #include "utils.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | int FileRecord::ParseRecord_csv(void) { 14 | FILE *fp = fp_head; 15 | 16 | data = (unsigned char*)malloc(record_size); 17 | 18 | fseek(fp, offset, SEEK_SET); 19 | if(fread(data, 1, record_size, fp) != record_size) { 20 | #ifdef DEBUG 21 | perror("fread"); 22 | #endif 23 | return ERROR_EOF; 24 | } 25 | 26 | memcpy(&(this->record), data, sizeof(FILE_RECORD)); 27 | 28 | if(strncmp(this->record.signature, "FILE", 4)) { 29 | fprintf(stderr, "Bad Signature: %s\n", this->record.signature); 30 | return ERROR_BADSIGNATURE; 31 | } 32 | record_num = this->record.record_num; 33 | 34 | parsed = true; 35 | 36 | csvrecord.fileid = this->record.record_num; 37 | 38 | VerifyFixup(); 39 | ParseAttrs_csv(data+(this->record.fattr_offset)); 40 | csvrecord.flag = this->record.flags; 41 | 42 | // output CSV 43 | // ComputerName 44 | escapeDoubleQuote(computername); 45 | printf("\"%s\"", computername.c_str()); 46 | printf("\t"); 47 | 48 | // Filename 49 | escapeDoubleQuote(csvrecord.filename); 50 | printf("\"%s\"", csvrecord.filename.c_str()); 51 | printf("\t"); 52 | // Pathname 53 | escapeDoubleQuote(csvrecord.pathname); 54 | printf("\"%s\"", csvrecord.pathname.c_str()); 55 | printf("\t"); 56 | 57 | // FileID 58 | printf("\"%lu\"", csvrecord.fileid); 59 | printf("\t"); 60 | 61 | // Flag (2bit: isdirectory, 1bit: in use) 62 | printf((csvrecord.flag&0x2)?"\"Directory":"\"File"); 63 | printf((csvrecord.flag&0x1)?"\"":"(Deleted)\""); 64 | printf("\t"); 65 | 66 | // FileSize 67 | printf("\"%lu\"", csvrecord.filesize); 68 | printf("\t"); 69 | 70 | // TimeStamp 71 | parse_time(csvrecord.created, lt); 72 | printf("\t"); 73 | parse_time(csvrecord.modified, lt); 74 | printf("\t"); 75 | parse_time(csvrecord.recordchanged, lt); 76 | printf("\t"); 77 | parse_time(csvrecord.accessed, lt); 78 | printf("\t"); 79 | 80 | // TimeStamp ($FILE_NAME) 81 | parse_time(csvrecord.created_fn, lt); 82 | printf("\t"); 83 | parse_time(csvrecord.modified_fn, lt); 84 | printf("\t"); 85 | parse_time(csvrecord.recordchanged_fn, lt); 86 | printf("\t"); 87 | parse_time(csvrecord.accessed_fn, lt); 88 | printf("\t"); 89 | 90 | // TimeZone (always UTC+0) 91 | if(lt) 92 | printf("\"%s\"\t", tzstr); 93 | else 94 | printf("\"UTC\"\t"); 95 | 96 | printf("\"%u\"", csvrecord.owner); 97 | printf("\t"); 98 | printf("\"%u\"", csvrecord.security); 99 | printf("\t"); 100 | 101 | // Misc 102 | escapeDoubleQuote(csvrecord.misc); 103 | printf("\"%s\"", csvrecord.misc.c_str()); 104 | printf("\n"); 105 | 106 | free(data); 107 | 108 | return 0; 109 | } 110 | 111 | 112 | int FileRecord::ParseAttrs_csv(unsigned char *p) { 113 | // base 114 | unsigned char *tmp; 115 | uint32_t attrid; 116 | uint32_t header_size; 117 | ATTR attr; 118 | 119 | // FILE_NAME 120 | char16_t *fname; 121 | uint8_t fname_len; 122 | 123 | // To clean filesize parameter 124 | csvrecord.filesize = 0; 125 | 126 | for(tmp = p; ; tmp += attr.header.base.attr_len) { 127 | if(!memcmp(tmp, END_OF_ATTR, 4)) break; 128 | memcpy(&attr, tmp, sizeof(ATTR_HEADER_BASE)); 129 | 130 | if(!attr.header.base.flag_nonresident) { // resident 131 | header_size = sizeof(ATTR_HEADER_RESIDENT); 132 | memcpy(&attr, tmp, header_size); 133 | } 134 | else { 135 | header_size = sizeof(ATTR_HEADER_NONRESIDENT); 136 | memcpy(&attr, tmp, header_size); 137 | } 138 | 139 | if(attr.header.base.name_len) { 140 | if(!csvrecord.misc.empty()) { 141 | csvrecord.misc += ","; 142 | } 143 | csvrecord.misc += convUTF16((char16_t*)(tmp+(attr.header.base.name_offset)), attr.header.base.name_len); 144 | } 145 | 146 | ParseAttr_csv(attr, tmp+header_size); 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | 153 | // parse each attribute (not including header) 154 | int FileRecord::ParseAttr_csv(ATTR attr, unsigned char *content) { 155 | // base 156 | unsigned char *p; 157 | bool nonresident; 158 | uint32_t attrid; 159 | uint32_t header_size; 160 | uint32_t content_size; 161 | 162 | // FILE_NAME 163 | char16_t *fname; 164 | uint8_t fname_len; 165 | 166 | // for ATTRIBUTE_LIST 167 | FileRecord *fr; 168 | uint32_t ref; 169 | 170 | 171 | attrid = attr.header.base.attr_typeid; 172 | 173 | if(attr.header.base.flag_nonresident) { 174 | nonresident = true; 175 | header_size = sizeof(ATTR_HEADER_NONRESIDENT); 176 | content_size = attr.header.base.attr_len - sizeof(ATTR_HEADER_NONRESIDENT); 177 | } 178 | else { 179 | nonresident = false; 180 | header_size = sizeof(ATTR_HEADER_RESIDENT); 181 | content_size = attr.header.base.attr_len - sizeof(ATTR_HEADER_RESIDENT); 182 | } 183 | 184 | 185 | switch(attrid) { 186 | case ATTRTYPEID_STANDARD_INFORMATION: 187 | memcpy(&(attr.content), content, sizeof(ATTR_STANDARD_INFORMATION)); 188 | csvrecord.created = attr.content.standard_information.creationtime; 189 | csvrecord.modified = attr.content.standard_information.file_altered_time; 190 | csvrecord.recordchanged = attr.content.standard_information.mft_altered_time; 191 | csvrecord.accessed = attr.content.standard_information.file_accessed_time; 192 | csvrecord.owner = attr.content.standard_information.owner_id; 193 | csvrecord.security = attr.content.standard_information.security_id; 194 | break; 195 | 196 | case ATTRTYPEID_ATTRIBUTE_LIST: 197 | for(unsigned char *c = content; 198 | c < content+content_size; 199 | c += attr.content.attribute_list.entry_len) { 200 | 201 | memcpy(&(attr.content), c, sizeof(ATTR_ATTRIBUTE_LIST)); 202 | 203 | // avoid infinity loop 204 | if(attr.content.attribute_list.entry_len == 0) 205 | break; 206 | // TODO: validation for this process 207 | 208 | switch(attr.content.attribute_list.attr_type) { 209 | case ATTRTYPEID_FILE_NAME: 210 | ref = attr.content.attribute_list.attr_file_ref_record; 211 | fr = new FileRecord(mft, mft->record_table[ref]); 212 | if(!fr->ParseRecord(false)) { 213 | mft->ref_table[record_num] = mft->ref_table[ref]; 214 | mft->filename[record_num] = mft->filename[ref]; 215 | } 216 | delete(fr); 217 | break; 218 | } 219 | } 220 | break; 221 | 222 | 223 | case ATTRTYPEID_FILE_NAME: 224 | memcpy(&(attr.content), content, sizeof(ATTR_FILE_NAME)); 225 | fname_len = attr.content.file_name.fname_len; 226 | 227 | // POSIX(0) > WIN32&DOS(3) > other 228 | if( csvrecord.ns_tmp == -1 229 | || csvrecord.ns_tmp != 0 && attr.content.file_name.fname_space == 0 230 | || csvrecord.ns_tmp != 0 && attr.content.file_name.fname_space == 3 231 | || csvrecord.ns_tmp == 3 && attr.content.file_name.fname_space == 0) { 232 | 233 | csvrecord.created_fn = attr.content.file_name.creationtime; 234 | csvrecord.modified_fn = attr.content.file_name.file_altered_time; 235 | csvrecord.recordchanged_fn = attr.content.file_name.mft_altered_time; 236 | csvrecord.accessed_fn = attr.content.file_name.file_accessed_time; 237 | 238 | // update ns_tmp 239 | csvrecord.ns_tmp = attr.content.file_name.fname_space; 240 | } 241 | 242 | mft->ref_table[record_num] = attr.content.file_name.parent_ref_mft_entry; 243 | mft->filename[record_num] = UTF16toUTF8((char16_t*)(content+sizeof(ATTR_FILE_NAME)-sizeof(char16_t*)), fname_len); 244 | csvrecord.filename = mft->filename[record_num]; 245 | csvrecord.pathname = getFileName(mft->ref_table[record_num]); 246 | break; 247 | 248 | 249 | case ATTRTYPEID_DATA: 250 | if(attr.header.base.name_len == 0) { 251 | csvrecord.filesize = nonresident ? 252 | attr.header.nonresident.actual_attr_size : 253 | attr.header.resident.size; 254 | } 255 | break; 256 | 257 | 258 | default: 259 | #ifdef DEBUG 260 | fprintf(stderr, "\nAttribute ID %d is not implemented.\n", attrid); 261 | #endif 262 | return 0; 263 | } 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /src/mft/lib/mft.cpp: -------------------------------------------------------------------------------- 1 | #include "mft.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | 8 | MFT::MFT(char *data, int record_size) { 9 | // TODO 10 | } 11 | 12 | 13 | MFT::MFT(char *fname, uint16_t _bytes_per_sector, uint8_t _sectors_per_clustor, uint8_t _clustors_per_filerecord) { 14 | 15 | unsigned char *r; 16 | uint32_t record; 17 | uint64_t offset = 0; 18 | int readbytes; 19 | FILE *fp; 20 | 21 | if((fp_head = fopen(fname, "rb")) == NULL) { 22 | perror("fopen"); 23 | return; 24 | } 25 | fp = fp_head; 26 | 27 | bytes_per_sector = _bytes_per_sector; 28 | sectors_per_clustor = _sectors_per_clustor; 29 | clustors_per_filerecord = _clustors_per_filerecord; 30 | record_size = bytes_per_sector * sectors_per_clustor * clustors_per_filerecord; 31 | 32 | while(1) { 33 | FileRecord fr = FileRecord(this, offset); 34 | 35 | int res = fr.ReadRecord(); 36 | if(res) { 37 | if(res == FileRecord::ERROR_EOF) break; 38 | 39 | offset += record_size; 40 | continue; 41 | } 42 | 43 | record_nums.push_back(fr.record_num); 44 | record_table[fr.record_num] = offset; 45 | offset += record_size; 46 | } 47 | } 48 | 49 | 50 | int MFT::parse(uint32_t num, FileRecord* fr, bool dump) { 51 | if(record_table.find(num) == record_table.end()) { 52 | return -1; 53 | } 54 | 55 | if(fr->ParseRecord(dump)) { 56 | return -1; 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | 63 | int MFT::parse_csv(uint32_t num, FileRecord* fr) { 64 | if(record_table.find(num) == record_table.end()) { 65 | return -1; 66 | } 67 | 68 | fr = new FileRecord(this, record_table[num]); 69 | 70 | // clear calc val 71 | (fr->csvrecord).ns_tmp = -1; 72 | 73 | if(fr->ParseRecord_csv()) { 74 | return -1; 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /src/mft/lib/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "attribute.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include // opendir, readdir, closedir 12 | 13 | #ifndef HEXDUMP_COLS 14 | #define HEXDUMP_COLS 8 15 | #endif 16 | 17 | #define HEXDUMP_OUT stdout 18 | 19 | bool isDir(const char *name){ 20 | struct stat s; 21 | if(stat(name, &s) == 0) { 22 | if( s.st_mode & S_IFDIR ) 23 | return true; 24 | else if( s.st_mode & S_IFREG ) 25 | return false; 26 | else { 27 | fprintf(stderr, "error: unknown object\n"); 28 | exit(EXIT_FAILURE); 29 | } 30 | } else 31 | return false; 32 | } 33 | 34 | bool isFile(const char *name){ 35 | struct stat s; 36 | if(stat(name, &s) == 0) { 37 | if( s.st_mode & S_IFREG ) 38 | return true; 39 | else if( s.st_mode & S_IFDIR ) 40 | return false; 41 | else { 42 | fprintf(stderr, "error: unknown object\n"); 43 | exit(EXIT_FAILURE); 44 | } 45 | } else 46 | return false; 47 | } 48 | 49 | string findFile(const char *dirname, const char *filename){ 50 | DIR *dir; 51 | struct dirent *dp; 52 | string tmpname; 53 | string searchname = filename; 54 | std::string::size_type pos; 55 | 56 | dir = opendir(dirname); 57 | if (dir == NULL) 58 | return ""; 59 | 60 | dp = readdir(dir); 61 | while (dp != NULL) { 62 | tmpname = dp->d_name; 63 | if(tmpname.find(searchname, tmpname.length() - searchname.length()) != std::string::npos) { 64 | closedir(dir); 65 | return tmpname; 66 | } 67 | dp = readdir(dir); 68 | } 69 | 70 | if (dir != NULL) 71 | closedir(dir); 72 | 73 | return ""; 74 | } 75 | 76 | // Check specified directory is empty 77 | bool is_empty_dir(const char *out_dname){ 78 | DIR *pdir; 79 | 80 | if((pdir = opendir(out_dname)) == NULL) 81 | return false; 82 | 83 | struct dirent *pent; 84 | 85 | // check there is at least one file 86 | for(pent = readdir(pdir); pent != NULL; pent = readdir(pdir)) { 87 | if(strcmp(pent->d_name, ".") != 0 && strcmp(pent->d_name, "..") != 0) {// ignore "." and ".." 88 | closedir(pdir); 89 | return false; 90 | } 91 | } 92 | closedir(pdir); 93 | return true; 94 | } 95 | 96 | void hexdump(void *mem, unsigned int len) 97 | { 98 | unsigned int i, j; 99 | 100 | for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) 101 | { 102 | /* print offset */ 103 | if(i % HEXDUMP_COLS == 0) 104 | { 105 | fprintf(HEXDUMP_OUT, "0x%06x: ", i); 106 | } 107 | 108 | /* print hex data */ 109 | if(i < len) 110 | { 111 | fprintf(HEXDUMP_OUT, "%02x ", 0xFF & ((char*)mem)[i]); 112 | } 113 | else /* end of block, just aligning for ASCII dump */ 114 | { 115 | fprintf(HEXDUMP_OUT, " "); 116 | } 117 | 118 | /* print ASCII dump */ 119 | if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) 120 | { 121 | for(j = i - (HEXDUMP_COLS - 1); j <= i; j++) 122 | { 123 | if(j >= len) /* end of block, not really printing */ 124 | { 125 | putchar(' '); 126 | } 127 | else if(isprint(((char*)mem)[j])) /* printable char */ 128 | { 129 | putchar(0xFF & ((char*)mem)[j]); 130 | } 131 | else /* other char */ 132 | { 133 | putchar('.'); 134 | } 135 | } 136 | putchar('\n'); 137 | } 138 | } 139 | } 140 | 141 | 142 | void parse_time(uint64_t _time, bool lt) { 143 | /* 144 | 11644473600.0 seconds from 1601/01/01 to 1970/01/01 145 | */ 146 | 147 | time_t epoch = _time/(10*1000*1000) - 11644473600L; 148 | int miliseconds = (_time%(10*1000*1000))/(1000*10); 149 | struct tm *tm_info; 150 | 151 | // check range and print raw value if invalid 152 | if (epoch > 32503680000ULL) { // 3000/01/01 00:00:00 153 | printf("\"%llu\"", _time); 154 | return; 155 | } 156 | 157 | if(lt) 158 | tm_info = localtime(&epoch); 159 | else 160 | tm_info = gmtime(&epoch); 161 | 162 | char buf[32]; 163 | strftime(buf, 26, "\"%Y/%m/%d %H:%M:%S", tm_info); 164 | printf(buf); 165 | printf(".%03d\"", miliseconds); 166 | } 167 | 168 | 169 | void parse_flags(uint64_t flags) { 170 | /* 171 | #define READ_ONLY 0x0001 172 | #define HIDDEN 0x0002 173 | #define SYSTEM 0x0004 174 | #define ARCHIVE 0x0020 175 | #define DEVICE 0x0040 176 | #define NORMAL 0x0080 177 | #define TEMPORARY 0x0100 178 | #define SPARSE_FILE 0x0200 179 | #define REPARSE_POINT 0x0400 180 | #define COMPRESSED 0x0800 181 | #define OFFLINE 0x1000 182 | #define NOT_INDEXED 0x2000 183 | #define ENCRYPTED 0x4000 184 | */ 185 | 186 | printf("flags:"); 187 | 188 | if(flags & READ_ONLY) 189 | printf(" READ_ONLY"); 190 | if(flags & HIDDEN) 191 | printf(" HIDDEN"); 192 | if(flags & SYSTEM) 193 | printf(" SYSTEM"); 194 | if(flags & ARCHIVE) 195 | printf(" ARCHIVE"); 196 | if(flags & DEVICE) 197 | printf(" DEVICE"); 198 | if(flags & NORMAL) 199 | printf(" NORMAL"); 200 | if(flags & TEMPORARY) 201 | printf(" TEMPORARY"); 202 | if(flags & SPARSE_FILE) 203 | printf(" SPARSE_FILE"); 204 | if(flags & REPARSE_POINT) 205 | printf(" REPARSE_POINT"); 206 | if(flags & COMPRESSED) 207 | printf(" COMPRESSED"); 208 | if(flags & OFFLINE) 209 | printf(" OFFLINE"); 210 | if(flags & NOT_INDEXED) 211 | printf(" NOT_INDEXED"); 212 | if(flags & ENCRYPTED) 213 | printf(" ENCRYPTED"); 214 | 215 | printf("\n"); 216 | } 217 | 218 | 219 | string UTF16toUTF8(char16_t *s, int n) { 220 | int half = 0; 221 | char *out = (char*)malloc(6); 222 | string res; 223 | 224 | // cite from:: ntfs-3g:unistr.c 225 | for (int i = 0; i < n; ++i) { 226 | uint16_t c = s[i]; 227 | char *t = out; 228 | memset(t, 0, 6); 229 | if (half) { 230 | if ((c >= 0xdc00) && (c < 0xe000)) { 231 | *t++ = 0xf0 + (((half + 64) >> 8) & 7); 232 | *t++ = 0x80 + (((half + 64) >> 2) & 63); 233 | *t++ = 0x80 + ((c >> 6) & 15) + ((half & 3) << 4); 234 | *t++ = 0x80 + (c & 63); 235 | half = 0; 236 | } 237 | } else if (c < 0x80) { 238 | *t++ = c; 239 | } else { 240 | if (c < 0x800) { 241 | *t++ = (0xc0 | ((c >> 6) & 0x3f)); 242 | *t++ = 0x80 | (c & 0x3f); 243 | } else if (c < 0xd800) { 244 | *t++ = 0xe0 | (c >> 12); 245 | *t++ = 0x80 | ((c >> 6) & 0x3f); 246 | *t++ = 0x80 | (c & 0x3f); 247 | } else if (c < 0xdc00) 248 | half = c; 249 | else if (c >= 0xe000) { 250 | *t++ = 0xe0 | (c >> 12); 251 | *t++ = 0x80 | ((c >> 6) & 0x3f); 252 | *t++ = 0x80 | (c & 0x3f); 253 | } 254 | } 255 | res += string(out); 256 | } 257 | 258 | free(out); 259 | 260 | return res; 261 | } 262 | 263 | 264 | void printUTF16(char16_t *s, int n) { // UTF16LE 265 | int half = 0; 266 | char *out = (char*)malloc(6); 267 | 268 | // cite from:: ntfs-3g:unistr.c 269 | for (int i = 0; i < n; ++i) { 270 | uint16_t c = s[i]; 271 | char *t = out; 272 | memset(t, 0, 6); 273 | if (half) { 274 | if ((c >= 0xdc00) && (c < 0xe000)) { 275 | *t++ = 0xf0 + (((half + 64) >> 8) & 7); 276 | *t++ = 0x80 + (((half + 64) >> 2) & 63); 277 | *t++ = 0x80 + ((c >> 6) & 15) + ((half & 3) << 4); 278 | *t++ = 0x80 + (c & 63); 279 | half = 0; 280 | } 281 | } else if (c < 0x80) { 282 | *t++ = c; 283 | } else { 284 | if (c < 0x800) { 285 | *t++ = (0xc0 | ((c >> 6) & 0x3f)); 286 | *t++ = 0x80 | (c & 0x3f); 287 | } else if (c < 0xd800) { 288 | *t++ = 0xe0 | (c >> 12); 289 | *t++ = 0x80 | ((c >> 6) & 0x3f); 290 | *t++ = 0x80 | (c & 0x3f); 291 | } else if (c < 0xdc00) 292 | half = c; 293 | else if (c >= 0xe000) { 294 | *t++ = 0xe0 | (c >> 12); 295 | *t++ = 0x80 | ((c >> 6) & 0x3f); 296 | *t++ = 0x80 | (c & 0x3f); 297 | } 298 | } 299 | printf("%s", out); 300 | } 301 | 302 | free(out); 303 | 304 | return; 305 | } 306 | 307 | 308 | string convUTF16(char16_t *s, int n) { // UTF16LE 309 | string res; 310 | int half = 0; 311 | char *out = (char*)malloc(6); 312 | 313 | // cite from:: ntfs-3g:unistr.c 314 | for (int i = 0; i < n; ++i) { 315 | uint16_t c = s[i]; 316 | char *t = out; 317 | memset(t, 0, 6); 318 | if (half) { 319 | if ((c >= 0xdc00) && (c < 0xe000)) { 320 | *t++ = 0xf0 + (((half + 64) >> 8) & 7); 321 | *t++ = 0x80 + (((half + 64) >> 2) & 63); 322 | *t++ = 0x80 + ((c >> 6) & 15) + ((half & 3) << 4); 323 | *t++ = 0x80 + (c & 63); 324 | half = 0; 325 | } 326 | } else if (c < 0x80) { 327 | *t++ = c; 328 | } else { 329 | if (c < 0x800) { 330 | *t++ = (0xc0 | ((c >> 6) & 0x3f)); 331 | *t++ = 0x80 | (c & 0x3f); 332 | } else if (c < 0xd800) { 333 | *t++ = 0xe0 | (c >> 12); 334 | *t++ = 0x80 | ((c >> 6) & 0x3f); 335 | *t++ = 0x80 | (c & 0x3f); 336 | } else if (c < 0xdc00) 337 | half = c; 338 | else if (c >= 0xe000) { 339 | *t++ = 0xe0 | (c >> 12); 340 | *t++ = 0x80 | ((c >> 6) & 0x3f); 341 | *t++ = 0x80 | (c & 0x3f); 342 | } 343 | } 344 | res += string(out); 345 | } 346 | 347 | free(out); 348 | 349 | return res; 350 | } 351 | 352 | void escapeDoubleQuote (std::string& str) { 353 | std::string::size_type pos = 0; 354 | while(pos = str.find("\"", pos), pos != std::string::npos) { 355 | str.replace(pos, 1, "\"\""); 356 | pos += 2; 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /src/mft/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "mft.h" 11 | #include "attribute.h" 12 | #include "utils.h" 13 | 14 | using namespace std; 15 | 16 | #ifdef _WIN32 17 | char SEP = '\\'; 18 | #else // unix 19 | char SEP = '/'; 20 | #endif 21 | 22 | 23 | // global variables 24 | bool lt = true; // localtime 25 | char tzstr[16]; // time zone 26 | bool header = true; // output header 27 | int tz_hour, tz_min; // time zone info 28 | string computername; // extract from input full path 29 | 30 | void usage(void) { 31 | printf("Usage: mft.exe [-o output] [--utc] [-e|--export] input\n"); 32 | } 33 | 34 | void dump(char *inname) { 35 | MFT mft = MFT(inname); 36 | 37 | for(uint32_t record_num:mft.record_nums) { 38 | FileRecord *fr; 39 | if(mft.parse(record_num, fr)) { 40 | fprintf(stderr, "error\n"); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | std::string extractcomputername(char *inname) { 47 | std::string fullpath, folderpath, foldername; 48 | string ntfs = "\\NTFS"; 49 | fullpath = inname; 50 | std::string::size_type pos; 51 | 52 | // trail filename 53 | if((pos = fullpath.find_last_of(SEP)) == string::npos) 54 | return "."; 55 | folderpath = fullpath.substr(0, pos); 56 | // trail NTFS folder 57 | if(folderpath.length() <= ntfs.length() || (pos = folderpath.find(ntfs, folderpath.length() - ntfs.length())) == std::string::npos) 58 | return "."; 59 | folderpath = folderpath.substr(0, pos); 60 | // extract foldername 61 | if((pos = folderpath.find_last_of(SEP)) == string::npos) 62 | return "."; 63 | foldername = folderpath.substr(pos+1, folderpath.length()-(pos+1)); 64 | // extract computername 65 | pos = foldername.find_last_of('_'); 66 | if (pos == std::string::npos) { 67 | return "."; 68 | } 69 | return foldername.substr(0, pos); 70 | } 71 | 72 | void dumpcsv(char *inname) { 73 | MFT mft = MFT(inname); 74 | 75 | computername = extractcomputername(inname); 76 | 77 | if(header==true) { 78 | // output CSV headers 79 | printf("\"ComputerName\""); 80 | printf("\t"); 81 | printf("\"Filename\""); 82 | printf("\t"); 83 | printf("\"Path\""); 84 | printf("\t"); 85 | printf("\"FileID\""); 86 | printf("\t"); 87 | printf("\"Flag\""); 88 | printf("\t"); 89 | printf("\"FileSize\""); 90 | printf("\t"); 91 | printf("\"Created\""); 92 | printf("\t"); 93 | printf("\"Modified\""); 94 | printf("\t"); 95 | printf("\"RecordChanged\""); 96 | printf("\t"); 97 | printf("\"Accessed\""); 98 | printf("\t"); 99 | printf("\"Created($FN)\""); 100 | printf("\t"); 101 | printf("\"Modified($FN)\""); 102 | printf("\t"); 103 | printf("\"RecordChanged($FN)\""); 104 | printf("\t"); 105 | printf("\"Accessed($FN)\""); 106 | printf("\t"); 107 | printf("\"TimeZone\""); 108 | printf("\t"); 109 | printf("\"Owner\""); 110 | printf("\t"); 111 | printf("\"Security\""); 112 | printf("\t"); 113 | printf("\"Misc\""); 114 | printf("\n"); 115 | } 116 | 117 | for(uint32_t record_num:mft.record_nums) { 118 | FileRecord *fr; 119 | if(mft.parse_csv(record_num, fr)) { 120 | fprintf(stderr, "error: record_num %d\n", record_num); 121 | break; 122 | } 123 | } 124 | } 125 | 126 | char* supplyinput(char *inname) { 127 | std::string inputname; 128 | std::string::size_type pos; 129 | 130 | inputname = inname; 131 | 132 | if(inputname[inputname.length()-1] == SEP) 133 | inputname += "$MFT"; 134 | else { 135 | pos = inputname.find_last_of(SEP); 136 | if(inputname.substr(pos+1, inputname.length()-(pos+1)) != "$MFT") { 137 | inputname += SEP; 138 | inputname += "$MFT"; 139 | } 140 | } 141 | 142 | char* inputname_cstr = new char[inputname.size() + 1]; 143 | std::char_traits::copy(inputname_cstr, inputname.c_str(), inputname.size() + 1); 144 | return inputname_cstr; 145 | } 146 | 147 | int main(int argc, char **argv) { 148 | 149 | char *inname = NULL; 150 | char *outname = NULL; 151 | const char *outdir; 152 | string infilename, inntfsname, infullname, outfullname; 153 | 154 | bool dumpresident = false; // dump resident data 155 | 156 | FILE* fp_out; 157 | int opt; 158 | int longindex; 159 | 160 | struct option longopts[] = { 161 | {"help", no_argument, NULL, 'h'}, 162 | {"output", required_argument, NULL, 'o'}, 163 | {"noheader", no_argument, NULL, 30}, 164 | {"utc", no_argument, NULL, 31}, 165 | {"export", no_argument, NULL, 'e'}, 166 | {0, 0, 0, 0}, 167 | }; 168 | 169 | while((opt = getopt_long(argc, argv, "o:h:e", longopts, &longindex)) != -1) { 170 | switch(opt) { 171 | 172 | case 'o': 173 | outname = optarg; 174 | break; 175 | 176 | case 'h': 177 | usage(); 178 | exit(EXIT_FAILURE); 179 | 180 | case 30: 181 | header=false; 182 | break; 183 | 184 | case 31: 185 | lt=false; 186 | break; 187 | 188 | case 'e': 189 | dumpresident = true; 190 | break; 191 | } 192 | } 193 | for (int i = optind; i < argc; i++) 194 | inname = argv[i]; 195 | 196 | if (!inname) { 197 | usage(); 198 | exit(EXIT_FAILURE); 199 | } 200 | 201 | // input handling 202 | if(isDir(inname)) { 203 | infilename = findFile(inname, "$MFT"); 204 | if (infilename == "") { 205 | if (inname[string(inname).size()-1] == '\\') 206 | inntfsname = string(inname) + "NTFS"; 207 | else 208 | inntfsname = string(inname) + SEP + "NTFS"; 209 | const char* inntfs = inntfsname.c_str(); 210 | infilename = findFile(inntfs, "$MFT"); 211 | if (infilename == "") { 212 | fprintf(stderr, "input file not found\n"); 213 | return -1; 214 | } 215 | infullname = inntfsname + SEP + infilename; 216 | } else { 217 | if (inname[string(inname).size()-1] == '\\') 218 | infullname = string(inname) + infilename; 219 | else 220 | infullname = string(inname) + SEP + infilename; 221 | } 222 | } else if (isFile(inname)){ 223 | infullname = string(inname); 224 | std::string::size_type pos = infullname.find_last_of(SEP); 225 | infilename = infullname.substr(pos+1, infullname.length()-pos); 226 | } else { 227 | fprintf(stderr, "error: no input\n"); 228 | exit(EXIT_FAILURE); 229 | } 230 | fprintf(stdout, "input: %s\n", infullname.c_str()); 231 | 232 | // output handling 233 | if(outname != NULL) { 234 | if(isDir(outname)) { 235 | outfullname = string(outname) + SEP + infilename + "_output.csv"; 236 | outdir = outname; 237 | } 238 | else { 239 | outfullname = string(outname); 240 | std::string::size_type pos = outfullname.find_last_of(SEP); 241 | outdir = outfullname.substr(0, pos-1).c_str(); 242 | } 243 | fprintf(stdout, "output: %s\n", outfullname.c_str()); 244 | fp_out = freopen(outfullname.c_str(),"a",stdout); 245 | } else 246 | fprintf(stdout, "output: stdout\n"); 247 | 248 | char* infullname_cstr = new char[infullname.size() + 1]; 249 | std::char_traits::copy(infullname_cstr, infullname.c_str(), infullname.size() + 1); 250 | 251 | 252 | if(dumpresident) { // output resident data 253 | MFT mft = MFT(infullname_cstr); 254 | 255 | if(outname == NULL) { 256 | fprintf(stderr, "current version doesn't support dump option and stdout\n"); 257 | return -1; 258 | } 259 | 260 | string cmd = "mkdir "+string(outdir)+SEP+"mft"; 261 | if(system(cmd.c_str())) { 262 | fprintf(stderr, "failed to create directory\n"); 263 | return -1; 264 | } 265 | 266 | for(uint32_t record_num:mft.record_nums) { 267 | FileRecord *fr = new FileRecord(&mft, mft.record_table[record_num]); 268 | if(mft.parse(record_num, fr, false)) { 269 | fprintf(stderr, "mft record parse error (%u)\n", record_num); 270 | break; 271 | } 272 | string outfile = fr->fname; 273 | string::size_type pos; 274 | while((pos = outfile.find_first_of('\\')) != string::npos) { // replace all '\\' to '_' 275 | outfile = outfile.replace(pos, 1, "_"); 276 | } 277 | while((pos = outfile.find_first_of(':')) != string::npos) { // replace all ':' to '_' 278 | outfile = outfile.replace(pos, 1, "_"); 279 | } 280 | 281 | for(auto resi:fr->resident_data) { 282 | if(resi->name == NULL) { // file name 283 | ofstream ofs(string(outdir)+SEP+"mft"+SEP+outfile); 284 | ofs << resi->data; 285 | ofs.close(); 286 | } 287 | else { // ADS 288 | ofstream ofs(string(outdir)+SEP+"mft"+SEP+outfile+"_"+string(resi->name)); 289 | ofs << resi->data; 290 | ofs.close(); 291 | } 292 | } 293 | delete(fr); 294 | } 295 | 296 | return 0; 297 | } 298 | 299 | // inputname = supplyinput(inname); 300 | 301 | // calc time zone 302 | if(lt) { 303 | time_t t1, t2; 304 | time(&t1); // LocalTime UNIX epoch 305 | struct tm *tm_info; 306 | int diff_sec; 307 | 308 | tm_info = gmtime(&t1); 309 | t2 = mktime(tm_info); // UTC UNIX epoch 310 | diff_sec = t1-t2; 311 | tz_hour = diff_sec/3600; 312 | tz_min = (diff_sec/60) % 60; 313 | if(diff_sec >= 0) 314 | sprintf(tzstr, "+%02d:%02d", tz_hour, tz_min); 315 | else // -hh:mm 316 | sprintf(tzstr, "%03d:%02d", tz_hour, -tz_min); 317 | 318 | } 319 | 320 | dumpcsv(infullname_cstr); 321 | return 0; 322 | } 323 | -------------------------------------------------------------------------------- /src/python/libMSCompression.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/python/libMSCompression.so -------------------------------------------------------------------------------- /src/python/parserutility.py: -------------------------------------------------------------------------------- 1 | import time 2 | import datetime 3 | import re 4 | import binascii 5 | import os 6 | import ctypes 7 | 8 | class utility(object): 9 | def get_timezone_str(self): 10 | diff_seconds = time.timezone 11 | diff_abs = abs(diff_seconds) 12 | delta = datetime.timedelta(seconds=diff_abs) 13 | delta_array = str(delta).split(":") 14 | diff_str = delta_array[0].zfill(2) + ":" + delta_array[1] 15 | if diff_seconds <= 0: 16 | diff_str = "+" + diff_str 17 | else: 18 | diff_str = "-" + diff_str 19 | return diff_str 20 | 21 | def get_computer_name(self, path): 22 | split_path = path.split(os.sep) 23 | for dir in reversed(split_path): 24 | if not dir or dir == split_path[-1] or re.match(r'NTFS|Registry|Prefetch', dir): 25 | continue 26 | else: 27 | parent_folder_name = dir 28 | break 29 | break_line = parent_folder_name.rfind("_") 30 | return parent_folder_name[:(break_line)] 31 | 32 | def get_timestamp_str(self, ts): 33 | s = (ts / 10000000.0) - 11644473600 34 | lt = time.ctime(s) 35 | ddt = time.strftime('%Y/%m/%d %H:%M:%S', time.strptime(lt)) 36 | ms = str("%.3f"%(s)).split(".")[1] 37 | return ddt + "." + ms 38 | 39 | def hextoint(self, hex): 40 | hex_array = re.split('(..)', binascii.hexlify(hex).decode())[1::2] 41 | list.reverse(hex_array) 42 | return int(("".join(hex_array)),16) 43 | 44 | class LARGE_INTEGER ( ctypes.Structure ): 45 | LONGLONG = ctypes.c_longlong 46 | _fields_ = [ 47 | ( "QuadPart", LONGLONG ) 48 | ] 49 | 50 | class WIN32_FIND_STREAM_DATA ( ctypes.Structure ): 51 | MAX_PATH = 260 52 | WCHAR = ctypes.c_wchar * ( MAX_PATH + 1 ) 53 | _fields_ = [ 54 | ( "StreamSize", LARGE_INTEGER ), 55 | ( "cStreamName", WCHAR ) 56 | ] 57 | 58 | def findstreams( path ): 59 | 60 | HANDLE = ctypes.c_void_p 61 | LPSTR = ctypes.c_wchar_p 62 | FindStreamInfoStandard = 0 63 | INVALID_HANDLE_VALUE = -1 64 | 65 | streamData = WIN32_FIND_STREAM_DATA() 66 | FindFirstStreamW = ctypes.windll.kernel32.FindFirstStreamW 67 | FindFirstStreamW.restype = HANDLE 68 | FindNextStreamW = ctypes.windll.kernel32.FindNextStreamW 69 | hfind = FindFirstStreamW( LPSTR( path ), FindStreamInfoStandard, ctypes.byref( streamData ), 0 ) 70 | paths = list() 71 | 72 | if hfind != INVALID_HANDLE_VALUE: 73 | if streamData.cStreamName != "::$DATA": 74 | paths.append( streamData.cStreamName[0:len( streamData.cStreamName )-6] ) 75 | while FindNextStreamW( HANDLE(hfind), ctypes.byref( streamData )): 76 | if streamData.cStreamName != "::$DATA": 77 | paths.append( streamData.cStreamName[0:len(streamData.cStreamName)-6] ) 78 | 79 | if ctypes.windll.kernel32.FindClose( HANDLE(hfind) ) != True: 80 | print ("ERROR") 81 | 82 | return paths -------------------------------------------------------------------------------- /src/python/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/williballenthin/python-registry.git@1.2.0 2 | enum34 3 | unicodecsv -------------------------------------------------------------------------------- /src/python/usnjrnl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # A parser for $UsnJrnl:$J 5 | # Copyright 2017 Cyber Defense Institute, Inc. 6 | 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | # USN_RECORD_V2 structure 20 | # https://msdn.microsoft.com/en-us/library/aa365722(v=vs.85).aspx 21 | import binascii 22 | import re 23 | import os 24 | import time 25 | import sys 26 | import csv 27 | import argparse 28 | import struct 29 | from parserutility import utility 30 | 31 | parser = argparse.ArgumentParser(description="How to use usnjrnl") 32 | parser.add_argument("--output", "-o", help="-o ", required=True) 33 | parser.add_argument("input") 34 | parser.add_argument("--noheader", action="store_true", dest="noheader", help="Output without header") 35 | args = parser.parse_args() 36 | 37 | in_dir = args.input 38 | out_dir = args.output 39 | 40 | row = ["Computer Name", "Time", "Time Zone", "File Name", "Value", "Reason", "File ID", "Parent Folder ID"] 41 | 42 | flag_dict = { 43 | '32': '0x01 Data in one or more named data streams for the filee was overwritten.', 44 | '31': '0x02 The filee or directory was added to.', 45 | '30': '0x04 The filee or directory was truncated.', 46 | '28': '0x10 Data in one or more named data streams for the filee was overwritten.', 47 | '27': '0x20 One or more named data streams for the filee were added to.', 48 | '26': '0x40 One or more named data streams for the filee was truncated.', 49 | '24': '0x100 The filee or directory was created for the first time.', 50 | '23': '0x200 The filee or directory was deleted.', 51 | '22': '0x400 The user made a change to the filee\'s or directory\'s extended attributes.', 52 | '21': '0x800 A change was made in the access rights to the filee or directory.', 53 | '20': '0x1000 The filee or directory was renamed and the filee name in this structure is the previous name.', 54 | '19': '0x2000 The filee or directory was renamed and the filee name in this structure is the new name.', 55 | '18': '0x4000 A user toggled the fileE_ATTRIBUTE_NOT_CONTENT_INDEXED attribute.', 56 | '17': '0x8000 A user has either changed one or more filee or directory attributes or one or more time stamps.', 57 | '16': '0x10000 An NTFS hard link was added to or removed from the filee or directory', 58 | '15': '0x20000 The compression state of the filee or directory was changed from or to compressed.', 59 | '14': '0x40000 The filee or directory was encrypted or decrypted.', 60 | '13': '0x80000 The object identifier of the filee or directory was changed.', 61 | '12': '0x100000 The reparse point contained in the filee or directory was changed, or a reparse point was added to or deleted from the filee or directory.', 62 | '11': '0x200000 A named stream has been added to or removed from the filee or a named stream has been renamed.', 63 | '2': '0x80000000 The filee or directory was closed.' 64 | } 65 | 66 | flags = { 67 | 0x00008000: "BASIC_INFO_CHANGE", 68 | 0x80000000: "CLOSE", 69 | 0x00020000: "COMPRESSION_CHANGE", 70 | 0x00000002: "DATA_EXTEND", 71 | 0x00000001: "DATA_OVERWRITE", 72 | 0x00000004: "DATA_TRUNCATION", 73 | 0x00000400: "EA_CHANGE", 74 | 0x00040000: "ENCRYPTION_CHANGE", 75 | 0x00000100: "FILE_CREATE", 76 | 0x00000200: "FILE_DELETE", 77 | 0x00010000: "HARD_LINK_CHANGE", 78 | 0x00004000: "INDEXABLE_CHANGE", 79 | 0x00800000: "INTEGRITY_CHANGE", 80 | 0x00000020: "NAMED_DATA_EXTEND", 81 | 0x00000010: "NAMED_DATA_OVERWRITE", 82 | 0x00000040: "NAMED_DATA_TRUNCATION", 83 | 0x00080000: "OBJECT_ID_CHANGE", 84 | 0x00002000: "RENAME_NEW_NAME", 85 | 0x00001000: "RENAME_OLD_NAME", 86 | 0x00100000: "REPARSE_POINT_CHANGE", 87 | 0x00000800: "SECURITY_CHANGE", 88 | 0x00200000: "STREAM_CHANGE", 89 | 0x00400000: "TRANSACTED_CHANGE" 90 | } 91 | 92 | def check_start_point(journal_pathname): 93 | current_offset = 0 94 | filename = os.path.basename(journal_pathname) 95 | filename = filename + "_output.csv" 96 | if os.path.exists(os.path.join(out_dir,filename)): 97 | column_name_flag = False 98 | else: 99 | column_name_flag = True 100 | 101 | with open(journal_pathname, "rb") as journal_file: 102 | with open(os.path.join(out_dir, filename), "a", encoding='utf-8') as output_file: 103 | if column_name_flag and not args.noheader: 104 | csv.writer((output_file), delimiter="\t", lineterminator="\n", quoting=csv.QUOTE_ALL).writerow(row) 105 | while True: 106 | if struct.unpack(" 0 and struct.unpack("= journal_filesize: 180 | output_file.close() 181 | return 182 | journal_file.seek(next_start) 183 | while True: 184 | if binascii.hexlify(journal_file.read(4)).decode() != "00000000": 185 | start_point = journal_file.tell() - 4 186 | break 187 | 188 | if __name__ == '__main__': 189 | exists_flag = False 190 | for root, dirs, files in os.walk(in_dir): 191 | for filename in files: 192 | if not re.search(r'\$UsnJrnl-\$J', filename): 193 | continue 194 | exists_flag = True 195 | journal_pathname = os.path.join(root, filename) 196 | journal_filesize = os.path.getsize(journal_pathname) 197 | time_delta = utility().get_timezone_str() 198 | check_start_point(journal_pathname) 199 | print ("Saved: {}\\{}_output.csv".format(out_dir, filename)) 200 | if not exists_flag: 201 | print ("$UsnJrnl-$J not found") 202 | sys.exit(1) 203 | -------------------------------------------------------------------------------- /src/regruns/.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 | -------------------------------------------------------------------------------- /src/regruns/.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 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | bower_components/ 163 | 164 | # RIA/Silverlight projects 165 | Generated_Code/ 166 | 167 | # Backup & report files from converting an old project file 168 | # to a newer Visual Studio version. Backup files are not needed, 169 | # because we have git ;-) 170 | _UpgradeReport_Files/ 171 | Backup*/ 172 | UpgradeLog*.XML 173 | UpgradeLog*.htm 174 | 175 | # SQL Server files 176 | *.mdf 177 | *.ldf 178 | 179 | # Business Intelligence projects 180 | *.rdl.data 181 | *.bim.layout 182 | *.bim_*.settings 183 | 184 | # Microsoft Fakes 185 | FakesAssemblies/ 186 | 187 | # LightSwitch generated files 188 | GeneratedArtifacts/ 189 | _Pvt_Extensions/ 190 | ModelManifest.xml -------------------------------------------------------------------------------- /src/regruns/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Cyber Defense Institute, Inc. 4 | 5 | Copyright (c) 2015 Eric Zimmerman 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/regruns/README.md: -------------------------------------------------------------------------------- 1 | # regruns 2 | 3 | Extract several autorun key information from hive files. 4 | 5 | regruns uses Registry.dll as a library and uses RECmd as a reference. 6 | 7 | https://github.com/EricZimmerman/Registry 8 | 9 | https://github.com/EricZimmerman/RECmd 10 | 11 | -------------------------------------------------------------------------------- /src/regruns/RECmd/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/regruns/RECmd/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 14 | 18 | 19 | 20 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/regruns/RECmd/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("regruns")] 9 | [assembly: AssemblyDescription("AutoRuns parser")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Cyber Defense Institute")] 12 | [assembly: AssemblyProduct("regruns")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 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 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("b931c052-18f8-4be3-99f3-a974d78c46d2")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.0.6.0")] 39 | [assembly: AssemblyFileVersion("1.0.6.0")] -------------------------------------------------------------------------------- /src/regruns/RECmd/Registry.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/regruns/RECmd/Registry.dll -------------------------------------------------------------------------------- /src/regruns/RECmd/list/ntuser.txt: -------------------------------------------------------------------------------- 1 | SOFTWARE\Classes\Exefile\Shell\Open\Command\ 2 | SOFTWARE\Microsoft\Command Processor\Autorun 3 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 4 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 5 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 6 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 7 | SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 8 | SOFTWARE\Microsoft\Windows\CurrentVersion\Run 9 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce 10 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices 11 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce 12 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 13 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run 14 | Environment 15 | -------------------------------------------------------------------------------- /src/regruns/RECmd/list/software.txt: -------------------------------------------------------------------------------- 1 | Classes\Exefile\Shell\Open\Command 2 | Microsoft\Active Setup\Installed Components 3 | Microsoft\SchedulingAgent 4 | Microsoft\Windows NT\CurrentVersion\Drivers32 5 | Microsoft\Windows NT\CurrentVersion\Image File Execution Options 6 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 7 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 8 | Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 9 | Microsoft\Windows NT\CurrentVersion\Winlogon\Notify 10 | Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 11 | Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList 12 | Microsoft\Windows NT\CurrentVersion\Winlogon\System 13 | Microsoft\Windows NT\CurrentVersion\Winlogon\Taskman 14 | Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 15 | Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 16 | Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 17 | Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 18 | Microsoft\Windows\CurrentVersion\Run 19 | Microsoft\Windows\CurrentVersion\RunOnce 20 | Microsoft\Windows\CurrentVersion\RunServices 21 | Microsoft\Windows\CurrentVersion\Shell Extensions\Approved 22 | Wow6432Node\Microsoft\Active Setup\Installed Components 23 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32 24 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 25 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 26 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 27 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 28 | Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 29 | Wow6432Node\Microsoft\Windows\CurrentVersion\Run 30 | Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce 31 | -------------------------------------------------------------------------------- /src/regruns/RECmd/list/system.txt: -------------------------------------------------------------------------------- 1 | Control\Lsa\Authentication Packages 2 | Control\Lsa\Notification Packages 3 | Control\Lsa\Security Packages 4 | Control\SecurityProviders\SecurityProviders 5 | Control\Session Manager\AppCertDlls 6 | Control\Session Manager\CWDIllegalInDllSearch 7 | -------------------------------------------------------------------------------- /src/regruns/RECmd/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/regruns/RECmd/regruns.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B931C052-18F8-4BE3-99F3-A974D78C46D2} 8 | Exe 9 | Properties 10 | regruns 11 | regruns 12 | v4.6.1 13 | 512 14 | true 15 | 16 | false 17 | publish\ 18 | true 19 | Disk 20 | false 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | 0 28 | 1.0.0.%2a 29 | false 30 | true 31 | 32 | 33 | AnyCPU 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | AnyCPU 44 | pdbonly 45 | true 46 | bin\Release\ 47 | TRACE 48 | prompt 49 | 4 50 | false 51 | 52 | 53 | 54 | 55 | 56 | 57 | bin\Release%28x64%29\ 58 | TRACE 59 | true 60 | pdbonly 61 | AnyCPU 62 | prompt 63 | MinimumRecommendedRules.ruleset 64 | 65 | 66 | true 67 | bin\x64\Debug\ 68 | DEBUG;TRACE 69 | full 70 | x64 71 | prompt 72 | MinimumRecommendedRules.ruleset 73 | true 74 | 75 | 76 | bin\x64\Release\ 77 | TRACE 78 | true 79 | pdbonly 80 | x64 81 | prompt 82 | MinimumRecommendedRules.ruleset 83 | 84 | 85 | bin\x64\Release%28x64%29\ 86 | TRACE 87 | true 88 | pdbonly 89 | x64 90 | prompt 91 | MinimumRecommendedRules.ruleset 92 | 93 | 94 | false 95 | 96 | 97 | 98 | ..\packages\CsvHelper.2.16.3.0\lib\net45\CsvHelper.dll 99 | 100 | 101 | ..\packages\NFluent.2.4.0\lib\net45\NFluent.dll 102 | 103 | 104 | ..\packages\NLog.4.5.11\lib\net45\NLog.dll 105 | 106 | 107 | False 108 | .\Registry.dll 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | PreserveNewest 139 | 140 | 141 | Designer 142 | 143 | 144 | 145 | 146 | 147 | False 148 | Microsoft .NET Framework 4.6 %28x86 および x64%29 149 | true 150 | 151 | 152 | False 153 | .NET Framework 3.5 SP1 154 | false 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | copy $(ProjectDir)list\* $(TargetDir) 163 | copy $(ProjectDir)list\* $(TargetDir)..\ 164 | "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe" /v4 /out:..\regruns.exe regruns.exe NLog.dll NFluent.dll Registry.dll CSVHelper.dll System.Runtime.CompilerServices.Unsafe.dll 165 | 166 | 173 | -------------------------------------------------------------------------------- /src/regruns/ntuser.txt: -------------------------------------------------------------------------------- 1 | SOFTWARE\Classes\Exefile\Shell\Open\Command\ 2 | SOFTWARE\Microsoft\Command Processor\Autorun 3 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 4 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 5 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 6 | SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 7 | SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 8 | SOFTWARE\Microsoft\Windows\CurrentVersion\Run 9 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce 10 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices 11 | SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce 12 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 13 | SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run 14 | Environment 15 | -------------------------------------------------------------------------------- /src/regruns/regruns.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}") = "regruns", "RECmd\regruns.csproj", "{B931C052-18F8-4BE3-99F3-A974D78C46D2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Release|Any CPU = Release|Any CPU 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Debug|x64.ActiveCfg = Debug|x64 19 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Debug|x64.Build.0 = Debug|x64 20 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Release|x64.ActiveCfg = Release|x64 23 | {B931C052-18F8-4BE3-99F3-A974D78C46D2}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/regruns/software.txt: -------------------------------------------------------------------------------- 1 | Classes\Exefile\Shell\Open\Command 2 | Microsoft\Active Setup\Installed Components 3 | Microsoft\SchedulingAgent 4 | Microsoft\Windows NT\CurrentVersion\Drivers32 5 | Microsoft\Windows NT\CurrentVersion\Image File Execution Options 6 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run 7 | Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunOnce 8 | Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 9 | Microsoft\Windows NT\CurrentVersion\Winlogon\Notify 10 | Microsoft\Windows NT\CurrentVersion\Winlogon\Shell 11 | Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList 12 | Microsoft\Windows NT\CurrentVersion\Winlogon\System 13 | Microsoft\Windows NT\CurrentVersion\Winlogon\Taskman 14 | Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 15 | Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 16 | Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 17 | Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 18 | Microsoft\Windows\CurrentVersion\Run 19 | Microsoft\Windows\CurrentVersion\RunOnce 20 | Microsoft\Windows\CurrentVersion\RunServices 21 | Microsoft\Windows\CurrentVersion\Shell Extensions\Approved 22 | Wow6432Node\Microsoft\Active Setup\Installed Components 23 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32 24 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 25 | Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls 26 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects 27 | Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 28 | Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 29 | Wow6432Node\Microsoft\Windows\CurrentVersion\Run 30 | Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce 31 | -------------------------------------------------------------------------------- /src/regruns/system.txt: -------------------------------------------------------------------------------- 1 | Control\Lsa\Authentication Packages 2 | Control\Lsa\Notification Packages 3 | Control\Lsa\Security Packages 4 | Control\SecurityProviders\SecurityProviders 5 | Control\Session Manager\AppCertDlls 6 | Control\Session Manager\CWDIllegalInDllSearch 7 | -------------------------------------------------------------------------------- /src/shimcache/.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 | -------------------------------------------------------------------------------- /src/shimcache/.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 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | bower_components/ 163 | 164 | # RIA/Silverlight projects 165 | Generated_Code/ 166 | 167 | # Backup & report files from converting an old project file 168 | # to a newer Visual Studio version. Backup files are not needed, 169 | # because we have git ;-) 170 | _UpgradeReport_Files/ 171 | Backup*/ 172 | UpgradeLog*.XML 173 | UpgradeLog*.htm 174 | 175 | # SQL Server files 176 | *.mdf 177 | *.ldf 178 | 179 | # Business Intelligence projects 180 | *.rdl.data 181 | *.bim.layout 182 | *.bim_*.settings 183 | 184 | # Microsoft Fakes 185 | FakesAssemblies/ 186 | 187 | # LightSwitch generated files 188 | GeneratedArtifacts/ 189 | _Pvt_Extensions/ 190 | ModelManifest.xml 191 | /.vs/AppCompatCacheParser/v15/Server/sqlite3/ 192 | /.vs/AppCompatCacheParser/v15/sqlite3/ -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/AppCompatCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using Registry; 8 | using Registry.Abstractions; 9 | 10 | namespace AppCompatCache 11 | { 12 | public class AppCompatCache 13 | { 14 | 15 | public enum Execute 16 | { 17 | Executed, 18 | Unknown, 19 | NA 20 | } 21 | 22 | [Flags] 23 | public enum InsertFlag 24 | { 25 | Unknown1 = 0x00000001, 26 | Executed = 0x00000002, 27 | Unknown4 = 0x00000004, 28 | Unknown8 = 0x00000008, 29 | Unknown10 = 0x00000010, 30 | Unknown20 = 0x00000020, 31 | Unknown40 = 0x00000040, 32 | Unknown80 = 0x00000080, 33 | Unknown10000 = 0x00010000, 34 | Unknown20000 = 0x00020000, 35 | Unknown30000 = 0x00030000, 36 | Unknown40000 = 0x00040000, 37 | Unknown100000 = 0x00100000, 38 | Unknown200000 = 0x00200000, 39 | Unknown400000 = 0x00400000, 40 | Unknown800000 = 0x00800000 41 | } 42 | 43 | public enum OperatingSystemVersion 44 | { 45 | WindowsVistaWin2k3Win2k8, 46 | Windows7x86, 47 | Windows7x64_Windows2008R2, 48 | Windows80_Windows2012, 49 | Windows81_Windows2012R2, 50 | Windows10, 51 | Windows10Creators, 52 | Unknown 53 | } 54 | 55 | public AppCompatCache(byte[] rawBytes, int controlSet, string computerName) 56 | { 57 | Caches = new List(); 58 | var cache = Init(rawBytes, false, controlSet, computerName); 59 | Caches.Add(cache); 60 | } 61 | 62 | public AppCompatCache(string filename, int controlSet) 63 | { 64 | byte[] rawBytes = null; 65 | Caches = new List(); 66 | 67 | if (File.Exists(filename) == false) 68 | throw new FileNotFoundException($"File not found ({filename})!"); 69 | 70 | var controlSetIds = new List(); 71 | 72 | // var hive = new RegistryHiveOnDemand(filename); 73 | var hive = new RegistryHive(filename); 74 | 75 | if (hive.Header.PrimarySequenceNumber != hive.Header.SecondarySequenceNumber) 76 | { 77 | var hiveBase = Path.GetFileName(filename); 78 | var dirname = Path.GetDirectoryName(filename); 79 | if (string.IsNullOrEmpty(dirname)) 80 | dirname = "."; 81 | 82 | var logFiles = Directory.GetFiles(dirname, $"{hiveBase}.LOG?"); 83 | 84 | if (logFiles.Length == 0) 85 | Console.WriteLine("Registry hive is dirty and no transaction logs were found. Try to parse without logs."); 86 | else 87 | hive.ProcessTransactionLogs(logFiles.ToList(), true); 88 | } 89 | 90 | hive.ParseHive(); 91 | 92 | RegistryKey subKey = hive.GetKey("Select"); 93 | var ControlSet = int.Parse(subKey.Values.Single(c => c.ValueName == "Current").ValueData); 94 | // ControlSet = controlSet; 95 | 96 | if (controlSet == -1) 97 | { 98 | for (var i = 0; i < 10; i++) 99 | { 100 | subKey = hive.GetKey($@"ControlSet00{i}\Control\Session Manager\AppCompatCache"); 101 | 102 | if (subKey == null) 103 | subKey = hive.GetKey($@"ControlSet00{i}\Control\Session Manager\AppCompatibility"); 104 | 105 | if (subKey != null) 106 | controlSetIds.Add(i); 107 | } 108 | 109 | if (controlSetIds.Count > 1) 110 | Console.WriteLine($"***The following ControlSet00x keys will be exported: {string.Join(",", controlSetIds)}.\r\n"); 111 | } 112 | else 113 | { 114 | //a control set was passed in 115 | subKey = hive.GetKey($@"ControlSet00{ControlSet}\Control\Session Manager\AppCompatCache"); 116 | 117 | if (subKey == null) 118 | subKey = hive.GetKey($@"ControlSet00{ControlSet}\Control\Session Manager\AppCompatibility"); 119 | 120 | if (subKey == null) 121 | throw new Exception($"Could not find ControlSet00{ControlSet}. Exiting"); 122 | 123 | controlSetIds.Add(ControlSet); 124 | } 125 | 126 | var is32 = Is32Bit(filename); 127 | string computerName = ComputerName(filename); 128 | 129 | foreach (var id in controlSetIds) 130 | { 131 | var hive2 = new RegistryHiveOnDemand(filename); 132 | subKey = hive2.GetKey($@"ControlSet00{id}\Control\Session Manager\AppCompatCache"); 133 | 134 | if (subKey == null) 135 | subKey = hive2.GetKey($@"ControlSet00{id}\Control\Session Manager\AppCompatibility"); 136 | 137 | var val = subKey?.Values.SingleOrDefault(c => c.ValueName == "AppCompatCache"); 138 | 139 | if (val != null) 140 | rawBytes = val.ValueDataRaw; 141 | 142 | if (rawBytes == null) 143 | throw new Exception($@"'AppCompatCache' value not found for 'ControlSet00{id}'! Exiting"); 144 | 145 | var cache = Init(rawBytes, is32, id, computerName); 146 | 147 | Caches.Add(cache); 148 | } 149 | } 150 | 151 | public int ControlSet { get; } 152 | 153 | public List Caches { get; } 154 | public OperatingSystemVersion OperatingSystem { get; private set; } 155 | 156 | // added computerName argument 157 | private IAppCompatCache Init(byte[] rawBytes, bool is32, int controlSet, string computerName) 158 | { 159 | IAppCompatCache appCache = null; 160 | OperatingSystem = OperatingSystemVersion.Unknown; 161 | 162 | string signature; 163 | 164 | var sigNum = BitConverter.ToUInt32(rawBytes, 0); 165 | 166 | //TODO check minimum length of rawBytes and throw exception if not enough data 167 | 168 | signature = Encoding.ASCII.GetString(rawBytes, 128, 4); 169 | 170 | if (sigNum == 0xbadc0ffe) // Vista 171 | { 172 | OperatingSystem = OperatingSystemVersion.WindowsVistaWin2k3Win2k8; 173 | appCache = new VistaWin2k3Win2k8(rawBytes, is32, controlSet, computerName); 174 | } 175 | else if (sigNum == 0xbadc0fee) // Win7 176 | { 177 | if (is32) 178 | OperatingSystem = OperatingSystemVersion.Windows7x86; 179 | else 180 | OperatingSystem = OperatingSystemVersion.Windows7x64_Windows2008R2; 181 | 182 | appCache = new Windows7(rawBytes, is32, controlSet, computerName); 183 | 184 | } 185 | else if ((signature == "00ts")) 186 | { 187 | OperatingSystem = OperatingSystemVersion.Windows80_Windows2012; 188 | appCache = new Windows8x(rawBytes, OperatingSystem, controlSet, computerName); 189 | } 190 | else if (signature == "10ts") 191 | { 192 | OperatingSystem = OperatingSystemVersion.Windows81_Windows2012R2; 193 | appCache = new Windows8x(rawBytes, OperatingSystem, controlSet, computerName); 194 | } 195 | else 196 | { 197 | //is it windows 10? 198 | 199 | var offsetToEntries = BitConverter.ToInt32(rawBytes, 0); 200 | 201 | OperatingSystem = OperatingSystemVersion.Windows10; 202 | 203 | if (offsetToEntries == 0x34) 204 | OperatingSystem = OperatingSystemVersion.Windows10Creators; 205 | 206 | signature = Encoding.ASCII.GetString(rawBytes, offsetToEntries, 4); 207 | if ((signature == "10ts")) 208 | appCache = new Windows10(rawBytes, controlSet, computerName); 209 | } 210 | 211 | if (appCache == null) 212 | throw new Exception("Unable to determine operating system..."); 213 | 214 | return appCache; 215 | } 216 | 217 | // added to retrieve ComputerName in SYSTEM hive 218 | public static string ComputerName(string fileName) 219 | { 220 | var hive = new RegistryHiveOnDemand(fileName); 221 | var subKey = hive.GetKey("Select"); 222 | var currentCtlSet = int.Parse(subKey.Values.Single(c => c.ValueName == "Current").ValueData); 223 | subKey = hive.GetKey($"ControlSet00{currentCtlSet}\\Control\\ComputerName\\ComputerName"); 224 | string computerName = subKey.Values.Single(c => c.ValueName == "ComputerName").ValueData; 225 | 226 | return computerName; 227 | } 228 | 229 | public static bool Is32Bit(string fileName) 230 | { 231 | var hive = new RegistryHiveOnDemand(fileName); 232 | var subKey = hive.GetKey("Select"); 233 | var currentCtlSet = int.Parse(subKey.Values.Single(c => c.ValueName == "Current").ValueData); 234 | 235 | subKey = hive.GetKey($"ControlSet00{currentCtlSet}\\Control\\Session Manager\\Environment"); 236 | 237 | var val = subKey?.Values.SingleOrDefault(c => c.ValueName == "PROCESSOR_ARCHITECTURE"); 238 | 239 | if (val != null) 240 | return val.ValueData.Equals("x86"); 241 | 242 | throw new NullReferenceException("Unable to determine CPU architecture..."); 243 | } 244 | } 245 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/AppCompatCache.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A} 8 | Library 9 | Properties 10 | AppCompatCache 11 | AppCompatCache 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | true 36 | bin\x64\Debug\ 37 | DEBUG;TRACE 38 | full 39 | x64 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | 43 | 44 | bin\x64\Release\ 45 | TRACE 46 | true 47 | pdbonly 48 | x64 49 | prompt 50 | MinimumRecommendedRules.ruleset 51 | 52 | 53 | 54 | ..\packages\NFluent.2.4.0\lib\net45\NFluent.dll 55 | 56 | 57 | ..\packages\NLog.4.5.11\lib\net45\NLog.dll 58 | 59 | 60 | ..\AppCompatCacheParser\Registry.dll 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Designer 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 104 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/AppCompatCache.v2.ncrunchproject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCache/AppCompatCache.v2.ncrunchproject -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/CacheEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AppCompatCache 4 | { 5 | public class CacheEntry 6 | { 7 | public string ComputerName { get; set; } 8 | public int EntryPosition { get; set; } 9 | public byte[] Data { get; set; } 10 | public AppCompatCache.InsertFlag InsertFlags { get; set; } 11 | public AppCompatCache.Execute Flag { get; set; } 12 | public int DataSize { get; set; } 13 | public DateTimeOffset LastModified { get; set; } 14 | public string TimeZone { get; set; } 15 | public string Path { get; set; } 16 | public int PathSize { get; set; } 17 | public string Signature { get; set; } 18 | public int ControlSet { get; set; } 19 | 20 | public override string ToString() 21 | { 22 | return $"#{EntryPosition} (Path size: {PathSize}), Path: {Path}, Last modified (Local):{LastModified}"; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/IAppCompatCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AppCompatCache 4 | { 5 | public interface IAppCompatCache 6 | { 7 | List Entries { get; } 8 | /// 9 | /// The total number of entries to expect 10 | /// 11 | /// When not available (Windows 8.x/10), will return -1 12 | int EntryCount { get; } 13 | int ControlSet { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("AppCompatCache")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AppCompatCache")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 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 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("ef07492c-2992-4bfd-b93a-78c6cc8fde7a")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.0.3.0")] 39 | [assembly: AssemblyFileVersion("1.0.3.0")] -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/VistaWin2kWin2k8.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | 6 | namespace AppCompatCache 7 | { 8 | public class VistaWin2k3Win2k8 : IAppCompatCache 9 | { 10 | public VistaWin2k3Win2k8(byte[] rawBytes, bool is32Bit, int controlSet, string computerName) 11 | { 12 | Entries = new List(); 13 | 14 | var index = 4; 15 | ControlSet = controlSet; 16 | 17 | EntryCount = BitConverter.ToInt32(rawBytes, index); 18 | 19 | index = 8; 20 | 21 | var position = 0; 22 | 23 | if (EntryCount == 0) 24 | { 25 | return; ; 26 | } 27 | 28 | if (is32Bit) 29 | { 30 | while (index < rawBytes.Length) 31 | { 32 | try 33 | { 34 | var ce = new CacheEntry(); 35 | 36 | ce.ComputerName = computerName; 37 | 38 | ce.PathSize = BitConverter.ToUInt16(rawBytes, index); 39 | index += 2; 40 | 41 | var maxPathSize = BitConverter.ToUInt16(rawBytes, index); 42 | index += 2; 43 | 44 | 45 | var pathOffset = BitConverter.ToInt32(rawBytes, index); 46 | index += 4; 47 | 48 | ce.LastModified = DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 49 | 50 | ce.TimeZone = ce.LastModified.ToString("zzz"); 51 | 52 | index += 8; 53 | 54 | // skip 4 unknown (insertion flags?) 55 | ce.InsertFlags = (AppCompatCache.InsertFlag)BitConverter.ToInt32(rawBytes, index); 56 | index += 4; 57 | 58 | // skip 4 unknown (shim flags?) 59 | index += 4; 60 | 61 | ce.Path = Encoding.Unicode.GetString(rawBytes, pathOffset, ce.PathSize).Replace(@"\??\", ""); 62 | 63 | // if ((ce.InsertFlags & AppCompatCache.InsertFlag.Executed) == AppCompatCache.InsertFlag.Executed) 64 | // { 65 | // ce.Executed = AppCompatCache.Execute.Executed; 66 | // } 67 | // else 68 | // { 69 | // ce.Executed = AppCompatCache.Execute.Unknown; 70 | // } 71 | ce.Flag = AppCompatCache.Execute.NA; 72 | 73 | ce.EntryPosition = position; 74 | ce.ControlSet = controlSet; 75 | Entries.Add(ce); 76 | position += 1; 77 | 78 | if (Entries.Count == EntryCount) 79 | { 80 | break; 81 | } 82 | } 83 | catch (Exception ex) 84 | { 85 | Debug.WriteLine(ex.Message); 86 | //take what we can get 87 | break; 88 | } 89 | } 90 | } 91 | else 92 | { 93 | while (index < rawBytes.Length) 94 | { 95 | try 96 | { 97 | var ce1 = new CacheEntry(); 98 | 99 | ce1.ComputerName = computerName; 100 | 101 | ce1.PathSize = BitConverter.ToUInt16(rawBytes, index); 102 | index += 2; 103 | 104 | var maxPathSize = BitConverter.ToUInt16(rawBytes, index); 105 | index += 2; 106 | 107 | // skip 4 unknown (padding) 108 | index += 4; 109 | 110 | var pathOffset = BitConverter.ToInt64(rawBytes, index); 111 | index += 8; 112 | 113 | ce1.LastModified = DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 114 | 115 | ce1.TimeZone = ce1.LastModified.ToString("zzz"); 116 | index += 8; 117 | 118 | // skip 4 unknown (insertion flags?) 119 | ce1.InsertFlags = (AppCompatCache.InsertFlag)BitConverter.ToInt32(rawBytes, index); 120 | index += 4; 121 | 122 | // skip 4 unknown (shim flags?) 123 | index += 4; 124 | 125 | ce1.Path = Encoding.Unicode.GetString(rawBytes, (int)pathOffset, ce1.PathSize).Replace(@"\??\", ""); 126 | 127 | if ((ce1.InsertFlags & AppCompatCache.InsertFlag.Executed) == AppCompatCache.InsertFlag.Executed) 128 | ce1.Flag = AppCompatCache.Execute.Executed; 129 | else 130 | ce1.Flag = AppCompatCache.Execute.Unknown; 131 | 132 | ce1.EntryPosition = position; 133 | Entries.Add(ce1); 134 | position += 1; 135 | 136 | if (Entries.Count == EntryCount) 137 | break; 138 | } 139 | catch (Exception ex) 140 | { 141 | if (Entries.Count < EntryCount) 142 | throw; 143 | //take what we can get 144 | break; 145 | } 146 | } 147 | } 148 | } 149 | 150 | public List Entries { get; } 151 | public int EntryCount { get; } 152 | public int ControlSet { get; } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/Windows10.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace AppCompatCache 7 | { 8 | public class Windows10 : IAppCompatCache 9 | { 10 | public int ExpectedEntries { get; } 11 | 12 | public Windows10(byte[] rawBytes, int controlSet, string computerName) 13 | { 14 | Entries = new List(); 15 | 16 | ExpectedEntries = 0; 17 | 18 | var offsetToRecords = BitConverter.ToInt32(rawBytes, 0); 19 | 20 | ExpectedEntries = BitConverter.ToInt32(rawBytes, 0x24); 21 | 22 | if (offsetToRecords == 0x34) 23 | ExpectedEntries = BitConverter.ToInt32(rawBytes, 0x28); 24 | 25 | var index = offsetToRecords; 26 | ControlSet = controlSet; 27 | EntryCount = -1; 28 | 29 | var position = 0; 30 | 31 | while (index < rawBytes.Length) 32 | { 33 | try 34 | { 35 | var ce = new CacheEntry 36 | { 37 | Signature = Encoding.ASCII.GetString(rawBytes, index, 4) 38 | }; 39 | 40 | if (ce.Signature != "10ts") 41 | break; 42 | 43 | ce.ComputerName = computerName; 44 | 45 | index += 4; 46 | 47 | // skip 4 unknown 48 | index += 4; 49 | 50 | var ceDataSize = BitConverter.ToUInt32(rawBytes, index); 51 | index += 4; 52 | 53 | ce.PathSize = BitConverter.ToUInt16(rawBytes, index); 54 | index += 2; 55 | ce.Path = Encoding.Unicode.GetString(rawBytes, index, ce.PathSize).Replace(@"\??\", ""); 56 | index += ce.PathSize; 57 | 58 | ce.LastModified = 59 | DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 60 | 61 | ce.TimeZone = ce.LastModified.ToString("zzz"); 62 | 63 | index += 8; 64 | 65 | ce.DataSize = BitConverter.ToInt32(rawBytes, index); 66 | index += 4; 67 | 68 | ce.Data = rawBytes.Skip(index).Take(ce.DataSize).ToArray(); 69 | index += ce.DataSize; 70 | ce.Flag = AppCompatCache.Execute.NA; 71 | ce.ControlSet = controlSet; 72 | ce.EntryPosition = position; 73 | Entries.Add(ce); 74 | position += 1; 75 | 76 | } 77 | catch (Exception ex) 78 | { 79 | //TODO Report this 80 | //take what we can get 81 | Console.Error.WriteLine($"Error parsing cache entry. Position: {position} Index: {index}, Error: {ex.Message} "); 82 | break; 83 | } 84 | } 85 | } 86 | 87 | public List Entries { get; } 88 | public int EntryCount { get; } 89 | public int ControlSet { get; } 90 | } 91 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/Windows7.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | 6 | namespace AppCompatCache 7 | { 8 | public class Windows7 : IAppCompatCache 9 | { 10 | public Windows7(byte[] rawBytes, bool is32Bit, int controlSet, string computerName) 11 | { 12 | Entries = new List(); 13 | 14 | var index = 4; 15 | ControlSet = controlSet; 16 | 17 | EntryCount = BitConverter.ToInt32(rawBytes, index); 18 | 19 | index = 128; 20 | 21 | var position = 0; 22 | 23 | if (EntryCount == 0) 24 | { 25 | return;; 26 | } 27 | 28 | if ((is32Bit)) 29 | { 30 | while (index < rawBytes.Length) 31 | { 32 | try 33 | { 34 | var ce = new CacheEntry(); 35 | 36 | ce.ComputerName = computerName; 37 | 38 | ce.PathSize = BitConverter.ToUInt16(rawBytes, index); 39 | index += 2; 40 | 41 | var maxPathSize = BitConverter.ToUInt16(rawBytes, index); 42 | index += 2; 43 | 44 | var pathOffset = BitConverter.ToInt32(rawBytes, index); 45 | index += 4; 46 | 47 | ce.LastModified = 48 | DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 49 | 50 | ce.TimeZone = ce.LastModified.ToString("zzz"); 51 | 52 | index += 8; 53 | 54 | // skip 4 unknown (insertion flags?) 55 | ce.InsertFlags = (AppCompatCache.InsertFlag)BitConverter.ToInt32(rawBytes, index); 56 | index += 4; 57 | 58 | // skip 4 unknown (shim flags?) 59 | index += 4; 60 | 61 | var ceDataSize = BitConverter.ToUInt32(rawBytes, index); 62 | index += 4; 63 | 64 | var dataOffset = BitConverter.ToUInt32(rawBytes, index); 65 | index += 4; 66 | 67 | ce.Path = Encoding.Unicode.GetString(rawBytes, pathOffset, ce.PathSize).Replace(@"\??\",""); 68 | 69 | if ((ce.InsertFlags & AppCompatCache.InsertFlag.Executed) == AppCompatCache.InsertFlag.Executed) 70 | ce.Flag = AppCompatCache.Execute.Executed; 71 | else 72 | ce.Flag = AppCompatCache.Execute.Unknown; 73 | 74 | ce.EntryPosition = position; 75 | ce.ControlSet = controlSet; 76 | Entries.Add(ce); 77 | position += 1; 78 | 79 | if (Entries.Count == EntryCount) 80 | break; 81 | } 82 | catch (Exception ex) 83 | { 84 | if (Entries.Count < EntryCount) 85 | throw; 86 | //TODO Report this 87 | Debug.WriteLine(ex.Message); 88 | //take what we can get 89 | break; 90 | } 91 | } 92 | } 93 | else 94 | { 95 | while (index <= rawBytes.Length) 96 | { 97 | try 98 | { 99 | var ce1 = new CacheEntry(); 100 | 101 | ce1.ComputerName = computerName; 102 | 103 | ce1.PathSize = BitConverter.ToUInt16(rawBytes, index); 104 | index += 2; 105 | 106 | var maxPathSize = BitConverter.ToUInt16(rawBytes, index); 107 | index += 2; 108 | 109 | // skip 4 unknown (padding) 110 | index += 4; 111 | 112 | var pathOffset = BitConverter.ToInt64(rawBytes, index); 113 | index += 8; 114 | 115 | ce1.LastModified = 116 | DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 117 | 118 | ce1.TimeZone = ce1.LastModified.ToString("zzz"); 119 | 120 | index += 8; 121 | 122 | // skip 4 unknown (insertion flags?) 123 | ce1.InsertFlags = (AppCompatCache.InsertFlag)BitConverter.ToInt32(rawBytes, index); 124 | index += 4; 125 | 126 | // skip 4 unknown (shim flags?) 127 | index += 4; 128 | 129 | var ceDataSize = BitConverter.ToUInt64(rawBytes, index); 130 | index += 8; 131 | 132 | var dataOffset = BitConverter.ToUInt64(rawBytes, index); 133 | index += 8; 134 | 135 | ce1.Path = Encoding.Unicode.GetString(rawBytes, (int) pathOffset, ce1.PathSize).Replace(@"\??\", ""); 136 | 137 | if ((ce1.InsertFlags & AppCompatCache.InsertFlag.Executed) == AppCompatCache.InsertFlag.Executed) 138 | ce1.Flag = AppCompatCache.Execute.Executed; 139 | else 140 | ce1.Flag = AppCompatCache.Execute.Unknown; 141 | 142 | ce1.EntryPosition = position; 143 | ce1.ControlSet = controlSet; 144 | Entries.Add(ce1); 145 | position += 1; 146 | 147 | if (Entries.Count == EntryCount) 148 | break; 149 | } 150 | catch (Exception ex) 151 | { 152 | //TODO Report this 153 | //take what we can get 154 | Console.Error.WriteLine($"Error parsing cache entry. Position: {position} Index: {index}, Error: {ex.Message} "); 155 | if (Entries.Count < EntryCount) 156 | throw; 157 | break; 158 | } 159 | } 160 | } 161 | } 162 | 163 | public List Entries { get; } 164 | public int EntryCount { get; } 165 | public int ControlSet { get; } 166 | } 167 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/Windows8x.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace AppCompatCache 7 | { 8 | public class Windows8x : IAppCompatCache 9 | { 10 | public Windows8x(byte[] rawBytes, AppCompatCache.OperatingSystemVersion os, int controlSet, string computerName) 11 | { 12 | Entries = new List(); 13 | 14 | var index = 128; 15 | 16 | var signature = "00ts"; 17 | 18 | ControlSet = controlSet; 19 | 20 | EntryCount = -1; 21 | 22 | if (os == AppCompatCache.OperatingSystemVersion.Windows81_Windows2012R2) 23 | signature = "10ts"; 24 | 25 | var position = 0; 26 | 27 | while (index < rawBytes.Length) 28 | { 29 | try 30 | { 31 | var ce = new CacheEntry 32 | { 33 | Signature = Encoding.ASCII.GetString(rawBytes, index, 4) 34 | }; 35 | 36 | if (ce.Signature != signature) 37 | break; 38 | 39 | ce.ComputerName = computerName; 40 | 41 | index += 4; 42 | 43 | // skip 4 unknown 44 | index += 4; 45 | 46 | var ceDataSize = BitConverter.ToUInt32(rawBytes, index); 47 | index += 4; 48 | 49 | ce.PathSize = BitConverter.ToUInt16(rawBytes, index); 50 | index += 2; 51 | 52 | ce.Path = Encoding.Unicode.GetString(rawBytes, index, ce.PathSize).Replace(@"\??\", ""); 53 | index += ce.PathSize; 54 | 55 | var packageLen = BitConverter.ToUInt16(rawBytes, index); 56 | index += 2; 57 | //skip package data 58 | index += packageLen; 59 | 60 | // skip 4 unknown (insertion flags?) 61 | ce.InsertFlags = (AppCompatCache.InsertFlag)BitConverter.ToInt32(rawBytes, index); 62 | index += 4; 63 | 64 | // skip 4 unknown (shim flags?) 65 | index += 4; 66 | 67 | ce.LastModified = 68 | DateTimeOffset.FromFileTime(BitConverter.ToInt64(rawBytes, index)); 69 | 70 | ce.TimeZone = ce.LastModified.ToString("zzz"); 71 | 72 | index += 8; 73 | 74 | ce.DataSize = BitConverter.ToInt32(rawBytes, index); 75 | index += 4; 76 | 77 | ce.Data = rawBytes.Skip(index).Take(ce.DataSize).ToArray(); 78 | index += ce.DataSize; 79 | 80 | if ((ce.InsertFlags & AppCompatCache.InsertFlag.Executed) == AppCompatCache.InsertFlag.Executed) 81 | ce.Flag = AppCompatCache.Execute.Executed; 82 | else 83 | ce.Flag = AppCompatCache.Execute.Unknown; 84 | 85 | ce.ControlSet = controlSet; 86 | ce.EntryPosition = position; 87 | Entries.Add(ce); 88 | position += 1; 89 | 90 | } 91 | catch (Exception ex) 92 | { 93 | //TODO report this 94 | //take what we can get 95 | Console.Error.WriteLine($"Error parsing cache entry. Position: {position} Index: {index}, Error: {ex.Message} "); 96 | break; 97 | } 98 | } 99 | } 100 | 101 | public List Entries { get; } 102 | public int EntryCount { get; } 103 | public int ControlSet { get; } 104 | } 105 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCache/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser.v2.ncrunchsolution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParser.v2.ncrunchsolution -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/AppCompatCacheParser.v2.ncrunchproject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParser/AppCompatCacheParser.v2.ncrunchproject -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Reflection; 5 | using AppCompatCache; 6 | using Microsoft.Win32; 7 | using CsvHelper; 8 | using CsvHelper.Configuration; 9 | 10 | namespace AppCompatCacheParser 11 | { 12 | internal class Program 13 | { 14 | 15 | private static bool CheckForDotnet46() 16 | { 17 | using ( 18 | var ndpKey = 19 | Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry32) 20 | .OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) 21 | { 22 | var releaseKey = Convert.ToInt32(ndpKey.GetValue("Release")); 23 | 24 | return (releaseKey >= 393295); 25 | } 26 | } 27 | private static void Help() 28 | { 29 | Console.WriteLine(@"shimcache.exe version " + Assembly.GetExecutingAssembly().GetName().Version + "\r\n" 30 | + "Cyber Defense Institute, Inc. A modified version of AppCompatCacheParser\r\n" 31 | + "Usage: shimcache.exe -o|--output OUTPUTFOLDER INPUTFOLDER"); 32 | Environment.Exit(0); 33 | } 34 | 35 | private static void Main(string[] args) 36 | { 37 | 38 | if (!CheckForDotnet46()) 39 | { 40 | Console.Error.WriteLine("Please install .NET Framework 4.6."); 41 | return; 42 | } 43 | 44 | string inDir = "", outDir = ""; 45 | string outFileBase = $"shimcache_output.csv"; 46 | 47 | // option handling 48 | string[] cmds = Environment.GetCommandLineArgs(); 49 | if (args.Length == 3 || args.Length == 4) // -o output input [--noheader] 50 | { 51 | if (args[0] == "-o" || args[0] == "--output") 52 | { 53 | outDir = args[1]; 54 | inDir = args[2]; 55 | } 56 | else 57 | Help(); 58 | } 59 | // TODO: implement standard output 60 | // else if (args.Length == 1) // only input 61 | // inDir = args[0]; 62 | else 63 | Help(); 64 | 65 | if (Directory.Exists(outDir) == false) 66 | Directory.CreateDirectory(outDir); 67 | 68 | var outFilename = Path.Combine(outDir, outFileBase); 69 | var sw = new StreamWriter(outFilename, true, new System.Text.UTF8Encoding(false)); 70 | sw.AutoFlush = true; 71 | var csv = new CsvWriter(sw); 72 | csv.Configuration.RegisterClassMap(); 73 | csv.Configuration.Delimiter = "\t"; 74 | // csv.Configuration.IgnoreQuotes = false; 75 | csv.Configuration.Quote = '"'; 76 | csv.Configuration.QuoteAllFields = true; 77 | 78 | if (args.Length == 4) 79 | if (args[3] == "--noheader") 80 | csv.Configuration.HasHeaderRecord = false; 81 | else 82 | csv.Configuration.HasHeaderRecord = true; 83 | else 84 | csv.Configuration.HasHeaderRecord = true; 85 | 86 | bool entryFlag = false; 87 | foreach (string fileName in Directory.GetFiles(inDir, "*", SearchOption.AllDirectories)) 88 | { 89 | if (fileName.EndsWith(".LOG") || fileName.EndsWith(".LOG1") || fileName.EndsWith(".LOG2")) 90 | continue; 91 | DirectoryInfo parentFolder = Directory.GetParent(fileName); 92 | if (outDir.Contains(parentFolder.ToString())) 93 | continue; 94 | Stream st = File.OpenRead(fileName); 95 | if (st.Length < 4) 96 | continue; 97 | 98 | BinaryReader br = new BinaryReader(st); 99 | if (br.ReadInt32() != 1718052210) // means not "regf" 100 | continue; 101 | 102 | br.BaseStream.Seek(48, SeekOrigin.Begin); 103 | if (br.ReadUInt16() != 'S') // means not SYSTEM hive 104 | continue; 105 | 106 | br.Close(); 107 | st.Close(); 108 | var appCompat = new AppCompatCache.AppCompatCache(fileName, 0); // 0: current, -1: all control sets 109 | 110 | if (appCompat.Caches.Any()) 111 | { 112 | foreach (var appCompatCach in appCompat.Caches) 113 | { 114 | 115 | try 116 | { 117 | Console.WriteLine( 118 | $"Found {appCompatCach.Entries.Count:N0} entries for {appCompat.OperatingSystem} in ControlSet00{appCompatCach.ControlSet}"); 119 | 120 | csv.WriteRecords(appCompatCach.Entries); 121 | entryFlag = true; 122 | } 123 | catch (Exception ex) 124 | { 125 | Console.Error.WriteLine($"Skip: " + fileName); 126 | } 127 | } 128 | } 129 | } 130 | 131 | sw.Close(); 132 | if (entryFlag == true) 133 | Console.WriteLine($"Saved: '{outFilename}'"); 134 | else 135 | Console.WriteLine($"Found 0 entries.."); 136 | 137 | return; 138 | } 139 | } 140 | 141 | public sealed class CacheOutputMap : ClassMap 142 | { 143 | public CacheOutputMap() 144 | { 145 | Map(m => m.ComputerName); 146 | Map(m => m.Path); 147 | Map(m => m.LastModified).TypeConverterOption.Format("yyyy/MM/dd HH:mm:ss.fff"); 148 | Map(m => m.TimeZone); 149 | Map(m => m.Flag); 150 | Map(m => m.EntryPosition); 151 | } 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("shimcache")] 9 | [assembly: AssemblyDescription("Shimcache parser")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Cyber Defense Institute")] 12 | [assembly: AssemblyProduct("shimcache")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 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 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("9f0f6b88-7d27-43b9-a729-da94d2358bfd")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.0.4.0")] 39 | [assembly: AssemblyFileVersion("1.0.4.0")] -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace shimcache.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/Registry.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParser/Registry.dll -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParser/shimcache.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD} 8 | Exe 9 | Properties 10 | shimcache 11 | shimcache 12 | v4.6.1 13 | 512 14 | true 15 | 16 | false 17 | publish\ 18 | true 19 | Disk 20 | false 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | 0 28 | 1.0.0.%2a 29 | false 30 | true 31 | 32 | 33 | AnyCPU 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | AnyCPU 44 | pdbonly 45 | true 46 | bin\Release\ 47 | TRACE 48 | prompt 49 | 4 50 | 51 | 52 | 53 | 54 | 55 | 56 | true 57 | bin\x64\Debug\ 58 | DEBUG;TRACE 59 | full 60 | x64 61 | prompt 62 | MinimumRecommendedRules.ruleset 63 | true 64 | 65 | 66 | bin\x64\Release\ 67 | TRACE 68 | true 69 | pdbonly 70 | x64 71 | prompt 72 | MinimumRecommendedRules.ruleset 73 | true 74 | 75 | 76 | 77 | ..\packages\CsvHelper.6.1.1\lib\net45\CsvHelper.dll 78 | 79 | 80 | ..\packages\NFluent.2.4.0\lib\net45\NFluent.dll 81 | 82 | 83 | ..\packages\NLog.4.5.11\lib\net45\NLog.dll 84 | 85 | 86 | .\Registry.dll 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | True 110 | True 111 | Settings.settings 112 | 113 | 114 | 115 | 116 | 117 | Designer 118 | 119 | 120 | SettingsSingleFileGenerator 121 | Settings.Designer.cs 122 | 123 | 124 | 125 | 126 | {ef07492c-2992-4bfd-b93a-78c6cc8fde7a} 127 | AppCompatCache 128 | 129 | 130 | 131 | 132 | False 133 | Microsoft .NET Framework 4.5.2 %28x86 および x64%29 134 | true 135 | 136 | 137 | False 138 | .NET Framework 3.5 SP1 139 | false 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe" /v4 /out:..\shimcache.exe shimcache.exe AppCompatCache.dll CsvHelper.dll NFluent.dll NLog.dll Registry.dll System.Runtime.CompilerServices.Unsafe.dll 151 | 152 | 153 | 160 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/AppCompatCacheTest.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using AppCompatCache; 3 | using NFluent; 4 | using NUnit.Framework; 5 | 6 | namespace AppCompatCacheTest 7 | { 8 | [TestFixture] 9 | public class AppCompatCacheTest 10 | { 11 | [SetUp] 12 | public void PreTestSetup() 13 | { 14 | Win7X86 = File.ReadAllBytes(@"..\..\TestFiles\Win7x86.bin"); 15 | Win7X64 = File.ReadAllBytes(@"..\..\TestFiles\Win7x64.bin"); 16 | Win80 = File.ReadAllBytes(@"..\..\TestFiles\Win80.bin"); 17 | Win81 = File.ReadAllBytes(@"..\..\TestFiles\Win81.bin"); 18 | Win10 = File.ReadAllBytes(@"..\..\TestFiles\Win10.bin"); 19 | Win10Creators = File.ReadAllBytes(@"..\..\TestFiles\Win10Creators.bin"); 20 | WinXp = File.ReadAllBytes(@"..\..\TestFiles\WinXPx86.bin"); 21 | Win2k8Std = File.ReadAllBytes(@"..\..\TestFiles\Win2k8Standard.bin"); 22 | } 23 | 24 | public byte[] Win7X86; 25 | public byte[] Win7X64; 26 | public byte[] Win80; 27 | public byte[] Win81; 28 | public byte[] Win10; 29 | public byte[] Win10Creators; 30 | public byte[] WinXp; 31 | public byte[] Win2k8Std; 32 | 33 | // [Test] 34 | // public void OneOff() 35 | // { 36 | // var foo = File.ReadAllBytes(@"D:\Temp\Win2003SP2.bin"); 37 | // var a = new VistaWin2k3Win2k8(foo, true, -1); 38 | // } 39 | 40 | [Test] 41 | public void Win2k8Std_ShouldFindEntries() 42 | { 43 | var a = new VistaWin2k3Win2k8(Win2k8Std, false, -1, null); 44 | Check.That(a.Entries.Count).Equals(873); 45 | // Check.That(a.ExpectedEntries).Equals(a.Entries.Count); 46 | Check.That(a.EntryCount).Equals(873); 47 | 48 | Check.That(a.Entries[0].PathSize).IsEqualTo(164); 49 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 50 | Check.That(a.Entries[0].Path).Contains("raw_agent_svc.exe"); 51 | 52 | Check.That(a.Entries[2].PathSize).IsEqualTo(62); 53 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 54 | Check.That(a.Entries[2].Path).Contains("mmc.exe"); 55 | 56 | Check.That(a.Entries[5].PathSize).IsEqualTo(62); 57 | Check.That(a.Entries[5].Flag).IsEqualTo(""); 58 | Check.That(a.Entries[5].Path).Contains("SCW.exe"); 59 | 60 | Check.That(a.Entries[337].PathSize).IsEqualTo(148); 61 | Check.That(a.Entries[337].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 62 | Check.That(a.Entries[337].Path).Contains("MSExchangeTransport.exe"); 63 | 64 | Check.That(a.Entries[349].PathSize).IsEqualTo(136); 65 | Check.That(a.Entries[349].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 66 | Check.That(a.Entries[349].Path).Contains("MSExchangeFDS.exe"); 67 | } 68 | 69 | [Test] 70 | public void Win10_CreatorsShouldFindEntries() 71 | { 72 | var a = new Windows10(Win10Creators, -1, null); 73 | Check.That(a.Entries.Count).Equals(506); 74 | Check.That(a.ExpectedEntries).Equals(a.Entries.Count); 75 | Check.That(a.EntryCount).Equals(-1); 76 | 77 | Check.That(a.Entries[0].PathSize).IsEqualTo(126); 78 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 79 | Check.That(a.Entries[0].Path).Contains("nvstreg.exe"); 80 | 81 | Check.That(a.Entries[2].PathSize).IsEqualTo(62); 82 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 83 | Check.That(a.Entries[2].Path).Contains("grpconv.exe"); 84 | 85 | Check.That(a.Entries[7].PathSize).IsEqualTo(166); 86 | Check.That(a.Entries[7].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 87 | Check.That(a.Entries[7].Path).Contains("ISBEW64.exe"); 88 | 89 | Check.That(a.Entries[337].PathSize).IsEqualTo(64); 90 | Check.That(a.Entries[337].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 91 | Check.That(a.Entries[337].Path).Contains("wsqmcons.exe"); 92 | 93 | Check.That(a.Entries[349].PathSize).IsEqualTo(56); 94 | Check.That(a.Entries[349].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 95 | Check.That(a.Entries[349].Path).Contains("SLUI.exe"); 96 | } 97 | 98 | [Test] 99 | public void Win10ShouldFindEntries() 100 | { 101 | var a = new Windows10(Win10, -1, null); 102 | Check.That(a.Entries.Count).Equals(350); 103 | Check.That(a.ExpectedEntries).Equals(a.Entries.Count); 104 | Check.That(a.EntryCount).Equals(-1); 105 | 106 | Check.That(a.Entries[0].PathSize).IsEqualTo(54); 107 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 108 | Check.That(a.Entries[0].Path).Contains("vds.exe"); 109 | 110 | Check.That(a.Entries[2].PathSize).IsEqualTo(140); 111 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 112 | Check.That(a.Entries[2].Path).Contains("DismHost.exe"); 113 | 114 | Check.That(a.Entries[7].PathSize).IsEqualTo(58); 115 | Check.That(a.Entries[7].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 116 | Check.That(a.Entries[7].Path).Contains("mstsc.exe"); 117 | 118 | Check.That(a.Entries[337].PathSize).IsEqualTo(112); 119 | Check.That(a.Entries[337].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 120 | Check.That(a.Entries[337].Path).Contains("Ngen.exe"); 121 | 122 | Check.That(a.Entries[349].PathSize).IsEqualTo(64); 123 | Check.That(a.Entries[349].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.NA); 124 | Check.That(a.Entries[349].Path).Contains("services.exe"); 125 | } 126 | 127 | [Test] 128 | public void Win7x64ShouldFindEntries() 129 | { 130 | var a = new Windows7(Win7X64, false, -1, null); 131 | Check.That(a.Entries.Count).Equals(304); 132 | Check.That(a.EntryCount).Equals(304); 133 | 134 | Check.That(a.Entries[0].PathSize).IsEqualTo(70); 135 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 136 | Check.That(a.Entries[0].Path).Contains("wuauclt.exe"); 137 | 138 | Check.That(a.Entries[2].PathSize).IsEqualTo(88); 139 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 140 | Check.That(a.Entries[2].Path).Contains("SearchFilterHost.exe"); 141 | 142 | Check.That(a.Entries[7].PathSize).IsEqualTo(126); 143 | Check.That(a.Entries[7].Flag).IsEqualTo(""); 144 | Check.That(a.Entries[7].Path).Contains("chrome.exe"); 145 | 146 | Check.That(a.Entries[300].PathSize).IsEqualTo(176); 147 | Check.That(a.Entries[300].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 148 | Check.That(a.Entries[300].Path).Contains("chrmstp.exe"); 149 | 150 | Check.That(a.Entries[301].PathSize).IsEqualTo(62); 151 | Check.That(a.Entries[301].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 152 | Check.That(a.Entries[301].Path).Contains("reg.exe"); 153 | } 154 | 155 | [Test] 156 | public void Win7x86ShouldFindEntries() 157 | { 158 | var a = new Windows7(Win7X86, true, -1, null); 159 | Check.That(a.Entries.Count).Equals(91); 160 | Check.That(a.EntryCount).Equals(91); 161 | 162 | Check.That(a.Entries[0].PathSize).IsEqualTo(70); 163 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 164 | Check.That(a.Entries[0].Path).Contains("LogonUI.exe"); 165 | 166 | Check.That(a.Entries[2].PathSize).IsEqualTo(92); 167 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 168 | Check.That(a.Entries[2].Path).Contains("SearchProtocolHost.exe"); 169 | 170 | Check.That(a.Entries[8].PathSize).IsEqualTo(108); 171 | Check.That(a.Entries[8].Flag).IsEqualTo(""); 172 | Check.That(a.Entries[8].Path).Contains("wmplayer.exe"); 173 | 174 | Check.That(a.Entries[89].PathSize).IsEqualTo(62); 175 | Check.That(a.Entries[89].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 176 | Check.That(a.Entries[89].Path).Contains("reg.exe"); 177 | 178 | Check.That(a.Entries[90].PathSize).IsEqualTo(72); 179 | Check.That(a.Entries[90].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 180 | Check.That(a.Entries[90].Path).Contains("SETUPUGC.EXE"); 181 | } 182 | 183 | [Test] 184 | public void Win80ShouldFindEntries() 185 | { 186 | var a = new Windows8x(Win80, AppCompatCache.AppCompatCache.OperatingSystemVersion.Windows80_Windows2012, -1, null); 187 | Check.That(a.Entries.Count).Equals(104); 188 | Check.That(a.EntryCount).Equals(-1); 189 | 190 | 191 | Check.That(a.Entries[0].PathSize).IsEqualTo(70); 192 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 193 | Check.That(a.Entries[0].Path).Contains("LogonUI.exe"); 194 | 195 | Check.That(a.Entries[2].PathSize).IsEqualTo(144); 196 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 197 | Check.That(a.Entries[2].Path).Contains("EditPadLite7.exe"); 198 | 199 | Check.That(a.Entries[8].PathSize).IsEqualTo(70); 200 | Check.That(a.Entries[8].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 201 | Check.That(a.Entries[8].Path).Contains("svchost.exe"); 202 | 203 | Check.That(a.Entries[100].PathSize).IsEqualTo(76); 204 | Check.That(a.Entries[100].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 205 | Check.That(a.Entries[100].Path).Contains("Setup.exe"); 206 | 207 | Check.That(a.Entries[101].PathSize).IsEqualTo(70); 208 | Check.That(a.Entries[101].Flag).IsEqualTo(""); 209 | Check.That(a.Entries[101].Path).Contains("WWAHost.exe"); 210 | } 211 | 212 | [Test] 213 | public void Win81ShouldFindEntries() 214 | { 215 | var a = new Windows8x(Win81, AppCompatCache.AppCompatCache.OperatingSystemVersion.Windows81_Windows2012R2, 216 | -1, null); 217 | Check.That(a.Entries.Count).Equals(1024); 218 | Check.That(a.EntryCount).Equals(-1); 219 | 220 | 221 | Check.That(a.Entries[0].PathSize).IsEqualTo(94); 222 | Check.That(a.Entries[0].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 223 | Check.That(a.Entries[0].Path).Contains("java.exe"); 224 | 225 | Check.That(a.Entries[2].PathSize).IsEqualTo(128); 226 | Check.That(a.Entries[2].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 227 | Check.That(a.Entries[2].Path).Contains("SpotifyHelper.exe"); 228 | 229 | Check.That(a.Entries[8].PathSize).IsEqualTo(70); 230 | Check.That(a.Entries[8].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 231 | Check.That(a.Entries[8].Path).Contains("dllhost.exe"); 232 | 233 | Check.That(a.Entries[1011].PathSize).IsEqualTo(98); 234 | Check.That(a.Entries[1011].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 235 | Check.That(a.Entries[1011].Path).Contains("osTriage2.exe"); 236 | 237 | Check.That(a.Entries[1023].PathSize).IsEqualTo(170); 238 | Check.That(a.Entries[1023].Flag).IsEqualTo(AppCompatCache.AppCompatCache.Execute.Executed); 239 | Check.That(a.Entries[1023].Path).Contains("setup.exe"); 240 | } 241 | } 242 | } -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/AppCompatCacheTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {46FD0FC6-4166-434D-A415-456122E87009} 9 | Library 10 | Properties 11 | AppCompatCacheTest 12 | AppCompatCacheTest 13 | v4.6.1 14 | 512 15 | 16 | 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | true 38 | bin\x64\Debug\ 39 | DEBUG;TRACE 40 | full 41 | x64 42 | prompt 43 | MinimumRecommendedRules.ruleset 44 | 45 | 46 | bin\x64\Release\ 47 | TRACE 48 | true 49 | pdbonly 50 | x64 51 | prompt 52 | MinimumRecommendedRules.ruleset 53 | 54 | 55 | 56 | ..\packages\NFluent.2.4.0\lib\net45\NFluent.dll 57 | 58 | 59 | ..\packages\NLog.4.5.11\lib\net45\NLog.dll 60 | 61 | 62 | ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | {ef07492c-2992-4bfd-b93a-78c6cc8fde7a} 85 | AppCompatCache 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 104 | 105 | 106 | 107 | 114 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/AppCompatCacheTest.v2.ncrunchproject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/AppCompatCacheTest.v2.ncrunchproject -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("AppCompatCacheTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AppCompatCacheTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 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 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("46fd0fc6-4166-434d-a415-456122e87009")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.0.0.0")] 39 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/ReadMe.txt: -------------------------------------------------------------------------------- 1 | These are the raw, binary contents of the SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache key's AppCompatCache value -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/Win10.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/TestFiles/Win10.bin -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/Win80.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/TestFiles/Win80.bin -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/Win81.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/TestFiles/Win81.bin -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/win7x64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/TestFiles/win7x64.bin -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/TestFiles/win7x86.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyberDefenseInstitute/CDIR-A/a93a82dfdb8f4e816a58cc9fdbd98339cc064a2e/src/shimcache/AppCompatCacheParserTest/TestFiles/win7x86.bin -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/shimcache/AppCompatCacheParserTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/shimcache/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Cyber Defense Institute, Inc. 4 | 5 | Copyright (c) 2015 Eric Zimmerman 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/shimcache/README.md: -------------------------------------------------------------------------------- 1 | # shimcache 2 | A modified version of AppCompatCache (shimcache) parser. 3 | 4 | https://github.com/EricZimmerman/AppCompatCacheParser 5 | 6 | This parser also reads specified directory including SYSTEM hive and writes to TSV format. -------------------------------------------------------------------------------- /src/shimcache/shimcache.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2018 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shimcache", "AppCompatCacheParser\shimcache.csproj", "{9F0F6B88-7D27-43B9-A729-DA94D2358BFD}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCompatCache", "AppCompatCache\AppCompatCache.csproj", "{EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCompatCacheTest", "AppCompatCacheParserTest\AppCompatCacheTest.csproj", "{46FD0FC6-4166-434D-A415-456122E87009}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Release|Any CPU = Release|Any CPU 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Debug|x64.ActiveCfg = Debug|x64 23 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Debug|x64.Build.0 = Debug|x64 24 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Release|x64.ActiveCfg = Release|x64 27 | {9F0F6B88-7D27-43B9-A729-DA94D2358BFD}.Release|x64.Build.0 = Release|x64 28 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Debug|x64.ActiveCfg = Debug|x64 31 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Debug|x64.Build.0 = Debug|x64 32 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Release|x64.ActiveCfg = Release|x64 35 | {EF07492C-2992-4BFD-B93A-78C6CC8FDE7A}.Release|x64.Build.0 = Release|x64 36 | {46FD0FC6-4166-434D-A415-456122E87009}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {46FD0FC6-4166-434D-A415-456122E87009}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {46FD0FC6-4166-434D-A415-456122E87009}.Debug|x64.ActiveCfg = Debug|x64 39 | {46FD0FC6-4166-434D-A415-456122E87009}.Debug|x64.Build.0 = Debug|x64 40 | {46FD0FC6-4166-434D-A415-456122E87009}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {46FD0FC6-4166-434D-A415-456122E87009}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {46FD0FC6-4166-434D-A415-456122E87009}.Release|x64.ActiveCfg = Release|x64 43 | {46FD0FC6-4166-434D-A415-456122E87009}.Release|x64.Build.0 = Release|x64 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {3F25ED98-6DA9-4E1A-ACC7-8B7F6BBEC2BA} 50 | EndGlobalSection 51 | EndGlobal 52 | --------------------------------------------------------------------------------