├── .github ├── FUNDING.yml └── workflows │ └── auto-update.yml ├── BulkBindex.sln ├── BulkBindex ├── BulkBindex.csproj ├── Helper.cs ├── Program.cs ├── Worker.cs └── obj │ └── Debug │ └── net6.0 │ ├── .NETCoreApp,Version=v6.0.AssemblyAttributes.cs │ ├── BulkBindex.AssemblyInfo.cs │ ├── BulkBindex.AssemblyInfoInputs.cache │ ├── BulkBindex.GeneratedMSBuildEditorConfig.editorconfig │ ├── BulkBindex.GlobalUsings.g.cs │ └── BulkBindex.csproj.AssemblyReference.cache └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: FuzzySecurity 4 | -------------------------------------------------------------------------------- /.github/workflows/auto-update.yml: -------------------------------------------------------------------------------- 1 | name: Build, Run and Publish Results 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build_and_upload_artifacts: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | input: 14 | - { value: ' -b 11-22H2 -d 2023-08', prefix: '11-22H2' } 15 | - { value: ' -b 22H2 -d 2023-08', prefix: '10-22H2' } 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v2 20 | 21 | - name: Setup .NET 22 | uses: actions/setup-dotnet@v1 23 | with: 24 | dotnet-version: 6.0.x 25 | 26 | - name: Build the .NET 6 application 27 | run: dotnet build --configuration Release 28 | 29 | - name: Extract date from input 30 | id: extract_date 31 | run: | 32 | date=$(echo '${{ matrix.input.value }}' | grep -oP '(?<=-d\s)[\d-]+') 33 | echo "::set-output name=date::$date" 34 | 35 | - name: Run the binary with matrix input 36 | run: dotnet ./BulkBindex/bin/Release/net6.0/BulkBindex.dll ${{ matrix.input.value }} 37 | 38 | - name: Archive x86 result 39 | run: zip -j ./BulkBindex/bin/Release/net6.0/x86-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }}.zip ./BulkBindex/bin/Release/net6.0/Worker-Output/Download/x86/* 40 | env: 41 | OUTPUT_DIR: Worker-Output/Download 42 | PROJECT_DIR: BulkBindex/bin/Release/net6.0 43 | 44 | - name: Archive x64 result 45 | run: zip -j ./BulkBindex/bin/Release/net6.0/x64-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }}.zip ./BulkBindex/bin/Release/net6.0/Worker-Output/Download/x64/* 46 | env: 47 | OUTPUT_DIR: Worker-Output/Download 48 | PROJECT_DIR: BulkBindex/bin/Release/net6.0 49 | 50 | - name: Upload x86 result 51 | uses: actions/upload-artifact@v2 52 | with: 53 | name: x86-result-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }} 54 | path: ./BulkBindex/bin/Release/net6.0/x86-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }}.zip 55 | 56 | - name: Upload x64 result 57 | uses: actions/upload-artifact@v2 58 | with: 59 | name: x64-result-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }} 60 | path: ./BulkBindex/bin/Release/net6.0/x64-${{ matrix.input.prefix }}-${{ steps.extract_date.outputs.date }}.zip 61 | 62 | create_release: 63 | needs: build_and_upload_artifacts 64 | runs-on: ubuntu-latest 65 | permissions: 66 | contents: write 67 | steps: 68 | - name: Checkout code 69 | uses: actions/checkout@v2 70 | 71 | - name: Create release tag 72 | id: create_tag 73 | run: | 74 | TAG_NAME="release-$(date +'%Y-%m-%d')-$(git rev-parse --short HEAD)" 75 | git config user.name "github-actions" 76 | git config user.email "github-actions@users.noreply.github.com" 77 | git tag $TAG_NAME 78 | echo "::set-output name=tag::$TAG_NAME" 79 | 80 | - name: Download all artifacts 81 | uses: actions/download-artifact@v2 82 | 83 | - name: Publish release 84 | if: github.ref == 'refs/heads/main' 85 | uses: softprops/action-gh-release@v1 86 | with: 87 | tag_name: ${{ steps.create_tag.outputs.tag }} 88 | draft: false 89 | prerelease: false 90 | files: | 91 | x86-result-*/*.zip 92 | x64-result-*/*.zip 93 | env: 94 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /BulkBindex.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BulkBindex", "BulkBindex\BulkBindex.csproj", "{907D3586-BD02-4BD5-AA04-8422FDBDF215}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {907D3586-BD02-4BD5-AA04-8422FDBDF215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {907D3586-BD02-4BD5-AA04-8422FDBDF215}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {907D3586-BD02-4BD5-AA04-8422FDBDF215}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {907D3586-BD02-4BD5-AA04-8422FDBDF215}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /BulkBindex/BulkBindex.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /BulkBindex/Helper.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | 3 | namespace BulkBindex; 4 | using System.IO.Compression; 5 | 6 | public class Helper 7 | { 8 | internal struct FileData 9 | { 10 | public String OSVersion; 11 | public String? ReleaseDate; 12 | public String FileName; 13 | public String? FileVersion; 14 | public String? md5; 15 | public Int64 Timestamp; 16 | public Int64 VirtualSize; 17 | public String DownloadURL; 18 | public String MachineType; 19 | } 20 | 21 | internal static List ProcessGZJSON(String sFullPath, String sDate, String sBuildName) 22 | { 23 | // Result object 24 | List oResult = new List(); 25 | 26 | // gz decompress the file 27 | String sJSON = String.Empty; 28 | using (FileStream fs = new FileStream(sFullPath, FileMode.Open)) 29 | { 30 | using (GZipStream gz = new GZipStream(fs, CompressionMode.Decompress)) 31 | { 32 | using (StreamReader sr = new StreamReader(gz)) 33 | { 34 | sJSON = sr.ReadToEnd(); 35 | } 36 | } 37 | } 38 | 39 | // Load the JSON into a JObject 40 | JObject oJSON = JObject.Parse(sJSON); 41 | 42 | // Loop through the json object 43 | foreach (JProperty oProperty in oJSON.Properties()) 44 | { 45 | //Console.WriteLine(oProperty.Name); 46 | JObject? fileInfo = null; 47 | try 48 | { 49 | fileInfo = (JObject)oProperty.Value["fileInfo"]!; 50 | } catch {continue;} 51 | 52 | Int64 timestamp = 0; 53 | Int64 virtualSize = 0; 54 | Int64 machineType = 0; 55 | try 56 | { 57 | // Get the timestamp / virtualSize / machineType values from the fileInfo object 58 | timestamp = (Int64) (fileInfo["timestamp"] ?? 0); 59 | virtualSize = (Int64) (fileInfo["virtualSize"] ?? 0); 60 | machineType = (Int64) (fileInfo["machineType"] ?? 0); 61 | if (timestamp == 0 || virtualSize == 0 || machineType == 0) 62 | { 63 | continue; 64 | } 65 | } catch {continue;} 66 | 67 | // We only want x86 and x64 files 68 | String sMachineType = String.Empty; 69 | if (machineType != 332 && machineType != 34404) 70 | { 71 | continue; 72 | } 73 | 74 | // Set the machine type in the result object 75 | if (machineType == 332) 76 | { 77 | sMachineType = "x86"; 78 | } 79 | else 80 | { 81 | sMachineType = "x64"; 82 | } 83 | 84 | String? sVersion = String.Empty; 85 | String? sMD5 = String.Empty; 86 | JObject? windowsVersions = null; 87 | try 88 | { 89 | sVersion = (String) fileInfo["version"]!; 90 | sMD5 = (String) fileInfo["md5"]!; 91 | windowsVersions = (JObject) oProperty.Value["windowsVersions"]!; 92 | } catch {continue;} 93 | 94 | // Loop through each version in the windowsVersions object 95 | foreach (JProperty versionProperty in windowsVersions.Properties()) 96 | { 97 | // Get the version object from the current version property 98 | JObject version = (JObject) versionProperty.Value; 99 | 100 | // Loop through the version object 101 | foreach (JProperty versionProperty2 in version.Properties()) 102 | { 103 | JObject? windowsVersionInfo = null; 104 | try 105 | { 106 | windowsVersionInfo = (JObject) versionProperty2.Value["windowsVersionInfo"]!; 107 | } 108 | catch {} 109 | 110 | JArray? otherWindowsVersions = null; 111 | if (windowsVersionInfo == null) 112 | { 113 | try 114 | { 115 | windowsVersionInfo = (JObject) versionProperty2.Value["updateInfo"]!; 116 | } catch {continue;} 117 | 118 | try 119 | { 120 | // If we have updateInfo, there can be an array of otherWindowsVersions 121 | // Stop it ok, just make a sane format MSFT ffs.. 122 | otherWindowsVersions = (JArray)windowsVersionInfo["otherWindowsVersions"]!; 123 | } catch {} 124 | } 125 | 126 | String? releaseDate = String.Empty; 127 | try 128 | { 129 | releaseDate = (String) windowsVersionInfo["releaseDate"]!; 130 | } catch {continue;} 131 | 132 | // Do we want this file? 133 | if (otherWindowsVersions != null) 134 | { 135 | try 136 | { 137 | if ((!otherWindowsVersions.Contains(sDate) && !versionProperty.Name.Contains(sBuildName)) || !releaseDate.Contains(sDate)) 138 | { 139 | continue; 140 | } 141 | } catch {continue;} 142 | 143 | } 144 | else 145 | { 146 | try 147 | { 148 | if (!releaseDate.Contains(sDate) || !versionProperty.Name.Contains(sBuildName)) 149 | { 150 | continue; 151 | } 152 | } catch {continue;} 153 | } 154 | 155 | // Get name (Win) 156 | String sFile = sFullPath.Split('\\').Last(); 157 | // Get name (Lin) 158 | sFile = sFile.Split('/').Last(); 159 | sFile = sFile.Remove(sFile.Length - 8); 160 | 161 | // We only want the first part of the version if there are spaces 162 | if (!String.IsNullOrEmpty(sVersion)) 163 | { 164 | if (sVersion.Contains(' ')) 165 | { 166 | sVersion = sVersion.Split(' ').First(); 167 | } 168 | } 169 | 170 | // Add the result to the list 171 | oResult.Add(new FileData 172 | { 173 | OSVersion = versionProperty.Name, 174 | ReleaseDate = releaseDate, 175 | FileName = sFile, 176 | md5 = sMD5, 177 | FileVersion = sVersion, 178 | Timestamp = timestamp, 179 | VirtualSize = virtualSize, 180 | DownloadURL = MakeMSFTSymbolDownloadLink(sFile, timestamp, virtualSize), 181 | MachineType = sMachineType 182 | }); 183 | } 184 | } 185 | } 186 | 187 | // Return the result 188 | return oResult; 189 | } 190 | 191 | public static String MakeMSFTSymbolDownloadLink(String peName, Int64 timeStamp, Int64 imageSize) 192 | { 193 | // "%s/%s/%08X%x/%s" % (serverName, peName, timeStamp, imageSize, peName) 194 | // https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/ 195 | 196 | String timeStampHex = timeStamp.ToString("X").ToUpper(); 197 | String paddedTimeStampHex = "0000000".Substring(0, 8 - timeStampHex.Length) + timeStampHex; 198 | String imageSizeHex = imageSize.ToString("x").ToLower(); 199 | 200 | String fileId = $"{paddedTimeStampHex}{imageSizeHex}"; 201 | return $"https://msdl.microsoft.com/download/symbols/{peName}/{fileId}/{peName}"; 202 | } 203 | 204 | internal static void DisplayProgress(Int64 index, Int64 count) 205 | { 206 | Double progress = (Double) index / count; 207 | Int32 progressInChars = (Int32)Math.Floor(progress * 50); 208 | 209 | Console.SetCursorPosition(0, Console.CursorTop); 210 | Console.Write('['); 211 | 212 | for (Int32 i = 0; i < 50; i++) 213 | { 214 | if (i < progressInChars) 215 | { 216 | Console.Write('='); 217 | } 218 | else if (i == progressInChars) 219 | { 220 | Console.Write('>'); 221 | } 222 | else 223 | { 224 | Console.Write(' '); 225 | } 226 | } 227 | 228 | Int32 progressPercentage = (Int32)Math.Floor(progress * 100); 229 | Console.Write($"] {progressPercentage}% ({index}/{count})"); 230 | Console.SetCursorPosition(0, Console.CursorTop); 231 | } 232 | } -------------------------------------------------------------------------------- /BulkBindex/Program.cs: -------------------------------------------------------------------------------- 1 | using BulkBindex; 2 | using System.Text.RegularExpressions; 3 | 4 | Int32 iBuildName = Array.FindIndex(args, s => new Regex(@"(?i)(-|--|/)(b|Build)$").Match(s).Success); 5 | Int32 iYearMonth = Array.FindIndex(args, s => new Regex(@"(?i)(-|--|/)(d|Date)$").Match(s).Success); 6 | 7 | if (iBuildName != -1 && iYearMonth != -1) 8 | { 9 | try 10 | { 11 | String BuildName = args[iBuildName + 1]; 12 | String YearMonth = args[iYearMonth + 1]; 13 | 14 | // Run the worker 15 | Worker.Run(BuildName, YearMonth); 16 | 17 | // DEBUG CODE 18 | //-------------- 19 | 20 | //List lFiles = Helper.ProcessGZJSON(@"C:\Users\b33f\tools\Dev\BulkBindex\BulkBindex\BulkBindex\bin\Debug\net6.0\Worker-Output\Compressed\ntdll.dll.json.gz", YearMonth, BuildName); 21 | // 22 | //// Print the results 23 | //foreach (Helper.FileData file in lFiles) 24 | //{ 25 | // Console.WriteLine("\n[+] File: " + file.FileName); 26 | // Console.WriteLine(" OS Version: " + file.OSVersion); 27 | // Console.WriteLine(" Release Date: " + file.ReleaseDate); 28 | // Console.WriteLine(" File Version: " + file.FileVersion); 29 | // Console.WriteLine(" MD5: " + file.md5); 30 | // Console.WriteLine(" Timestamp: " + file.Timestamp); 31 | // Console.WriteLine(" Virtual Size: " + file.VirtualSize); 32 | // Console.WriteLine(" Download URL: " + file.DownloadURL); 33 | //} 34 | } catch (Exception ex) 35 | { 36 | Console.WriteLine($"[!] Error: {ex.Message}"); 37 | } 38 | } 39 | else 40 | { 41 | Console.WriteLine("[!] Missing required arguments. Please use the following format:"); 42 | Console.WriteLine(" BulkBindex.exe -b -d "); 43 | Console.WriteLine(" Example: BulkBindex.exe -b 11-22H2 -d 2023-04"); 44 | } -------------------------------------------------------------------------------- /BulkBindex/Worker.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Reflection; 3 | using System.IO.Compression; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace BulkBindex; 7 | 8 | public class Worker 9 | { 10 | internal static void Run(String BuildName, String YearMonth) 11 | { 12 | // Get the current directory of the executable 13 | String CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; 14 | 15 | // Create the output directory 16 | String OutputDirectory = Path.Combine(CurrentDirectory, "Worker-Output"); 17 | 18 | // If directory exists, delete it and all of its contents 19 | if (Directory.Exists(OutputDirectory)) 20 | { 21 | Directory.Delete(OutputDirectory, true); 22 | } 23 | Directory.CreateDirectory(OutputDirectory); 24 | 25 | // Download zip to output directory 26 | // https://github.com/m417z/winbindex/archive/refs/heads/gh-pages.zip 27 | String zFile = Path.Combine(OutputDirectory, "winbindex.zip"); 28 | String ZipURL = "https://github.com/m417z/winbindex/archive/refs/heads/gh-pages.zip"; 29 | Console.WriteLine($"[+] Downloading winbindex from GitHub to {zFile}"); 30 | using (WebClient Client = new WebClient()) 31 | { 32 | Client.DownloadFile(ZipURL, zFile); 33 | } 34 | 35 | // Get file size of zip file 36 | FileInfo ZipFileInfo = new FileInfo(zFile); 37 | Console.WriteLine($"[>] Downloaded {ZipFileInfo.Length} bytes"); 38 | String sCompressedPath = Path.Combine(OutputDirectory, "Compressed"); 39 | Directory.CreateDirectory(sCompressedPath); 40 | 41 | // Extract zip file to output directory 42 | Console.WriteLine($"[+] Extracting compressed files to {sCompressedPath}"); 43 | 44 | using (ZipArchive archive = ZipFile.OpenRead(zFile)) 45 | { 46 | foreach (ZipArchiveEntry entry in archive.Entries) 47 | { 48 | if (entry.FullName.StartsWith("winbindex-gh-pages/data/by_filename_compressed/")) 49 | { 50 | String sPattern = @"\.exe|\.dll|\.sys|\.winmd|\.cpl|\.ax|\.node|\.ocx|\.efi|\.acm|\.scr|\.tsp|\.drv"; 51 | if (Regex.IsMatch(entry.FullName, sPattern)) 52 | { 53 | // Extract the file 54 | entry.ExtractToFile(Path.Combine(sCompressedPath, entry.Name)); 55 | } 56 | } 57 | } 58 | } 59 | Console.WriteLine("[>] Extraction complete."); 60 | 61 | // Delete the zip file 62 | File.Delete(zFile); 63 | 64 | // Make output directory for downloaded files 65 | String sDownloadedPath = Path.Combine(OutputDirectory, "Download"); 66 | String sDownloadedPathx86 = Path.Combine(sDownloadedPath, "x86"); 67 | String sDownloadedPathx64 = Path.Combine(sDownloadedPath, "x64"); 68 | Directory.CreateDirectory(sDownloadedPath); 69 | Directory.CreateDirectory(sDownloadedPathx86); 70 | Directory.CreateDirectory(sDownloadedPathx64); 71 | Console.WriteLine($"[DEBUG] Downloaded files will be saved to {sDownloadedPath}"); 72 | Console.WriteLine($"[+] Downloading all binaries for {BuildName} {YearMonth}.."); 73 | 74 | // Process the files 75 | // 1. Decompress 76 | // 2. Read as JSON 77 | // 3. Loop through each file 78 | 79 | // Get count of files 80 | Int64 iFileCount = Directory.GetFiles(sCompressedPath).Length; 81 | Int64 iCurrentFile = 0; 82 | List lFailedDownloads = new List(); 83 | foreach (String sGZInstance in Directory.GetFiles(sCompressedPath)) 84 | { 85 | // Pass the full path to the helper 86 | List fileList = Helper.ProcessGZJSON(sGZInstance, YearMonth, BuildName); 87 | 88 | // Print the results 89 | foreach (Helper.FileData file in fileList) 90 | { 91 | // Create the file name 92 | String sFileName = String.Empty; 93 | if (!String.IsNullOrEmpty(file.FileVersion)) 94 | { 95 | sFileName = file.FileName + "-" + file.FileVersion + "-" + file.md5 + ".blob"; 96 | } 97 | else 98 | { 99 | sFileName = file.FileName + "-" + file.md5 + ".blob"; 100 | } 101 | 102 | // Download the file 103 | String sDownloadPath = String.Empty; 104 | if (file.MachineType == "x86") 105 | { 106 | sDownloadPath = Path.Combine(sDownloadedPathx86, sFileName); 107 | } 108 | else 109 | { 110 | sDownloadPath = Path.Combine(sDownloadedPathx64, sFileName); 111 | } 112 | //Console.WriteLine("[DEBUG] " + sDownloadPath); 113 | 114 | try 115 | { 116 | using (WebClient Client = new WebClient()) 117 | { 118 | Client.DownloadFile(file.DownloadURL, sDownloadPath); 119 | } 120 | } 121 | catch (Exception ex) 122 | { 123 | String sError = " - " + file.DownloadURL + "\n |_ " + ex.Message; 124 | lFailedDownloads.Add(sError); 125 | } 126 | } 127 | 128 | // Delete the compressed file 129 | File.Delete(sGZInstance); 130 | 131 | // Increment and print progress 132 | iCurrentFile++; 133 | Helper.DisplayProgress(iCurrentFile, iFileCount); 134 | } 135 | 136 | Console.WriteLine("\n[>] Download complete."); 137 | // Print failed downloads 138 | if (lFailedDownloads.Count > 0) 139 | { 140 | Console.WriteLine("\n[!] Failed file downloads.."); 141 | foreach (String sError in lFailedDownloads) 142 | { 143 | Console.WriteLine(sError); 144 | } 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] 5 | -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/BulkBindex.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | using System; 11 | using System.Reflection; 12 | 13 | [assembly: System.Reflection.AssemblyCompanyAttribute("BulkBindex")] 14 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 15 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 16 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 17 | [assembly: System.Reflection.AssemblyProductAttribute("BulkBindex")] 18 | [assembly: System.Reflection.AssemblyTitleAttribute("BulkBindex")] 19 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 20 | 21 | // Generated by the MSBuild WriteCodeFragment class. 22 | 23 | -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/BulkBindex.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | b1481bc9685728b3b79cbbd34ffbf784f5d3b7ae 2 | -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/BulkBindex.GeneratedMSBuildEditorConfig.editorconfig: -------------------------------------------------------------------------------- 1 | is_global = true 2 | build_property.TargetFramework = net6.0 3 | build_property.TargetPlatformMinVersion = 4 | build_property.UsingMicrosoftNETSdkWeb = 5 | build_property.ProjectTypeGuids = 6 | build_property.InvariantGlobalization = 7 | build_property.PlatformNeutralAssembly = 8 | build_property._SupportedPlatformList = Linux,macOS,Windows 9 | build_property.RootNamespace = BulkBindex 10 | build_property.ProjectDir = c:\Users\b33f\tools\GitHub\BulkBindex\BulkBindex\ 11 | -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/BulkBindex.GlobalUsings.g.cs: -------------------------------------------------------------------------------- 1 | // 2 | global using global::System; 3 | global using global::System.Collections.Generic; 4 | global using global::System.IO; 5 | global using global::System.Linq; 6 | global using global::System.Net.Http; 7 | global using global::System.Threading; 8 | global using global::System.Threading.Tasks; 9 | -------------------------------------------------------------------------------- /BulkBindex/obj/Debug/net6.0/BulkBindex.csproj.AssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzySecurity/BulkBindex/cd155782916fca08e602ff24f3e7a848bb437355/BulkBindex/obj/Debug/net6.0/BulkBindex.csproj.AssemblyReference.cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CI](https://github.com/FuzzySecurity/BulkBindex/actions/workflows/auto-update.yml/badge.svg) 2 | 3 | # BulkBindex 4 | 5 | `BulkBindex` is a **very** DIY extension for [`Winbindex`](https://winbindex.m417z.com/) by [@m417z](https://twitter.com/m417z). All the great work is done there really! 6 | 7 | `BulkBindex` fetches compressed JSON files from the `Winbindex` repository and processes those to download all binaries related to a specific Windows build and month. It can just be really useful to have everything collected after `patch tuesday` for example. 8 | 9 | ## Usage 10 | 11 | `BulkBindex` is built on .NET6 so you can compile and run it anywhere. Command line usage is shown below. 12 | 13 | ``` 14 | // Windows 15 | BulkBindex.exe -b 11-22H2 -d 2023-04 16 | 17 | // Nix 18 | dotnet BulkBindex.dll -b 11-22H2 -d 2023-04 19 | ``` 20 | 21 | #### Where do I get build names? 22 | 23 | `BulkBindex` uses the same build identifiers as on `Winbindex`. For example, in the listing for `ntdll` below you can see the version is `11-22H2`. Note however that sometimes, other applicable versions are specified in `otherWindowsVersions` (e.g., `21H2` etc.). 24 | 25 | ```json 26 | { 27 | "fileInfo": { 28 | "description": "NT Layer DLL", 29 | "machineType": 34404, 30 | "md5": "c9b7eb6b6320deb5a9dc6ab23be3029d", 31 | "sha1": "ac9d441181e3b35d4d321002ca5b4d26aa59615d", 32 | "sha256": "abb30adf05bd71ae8283d8a44e55268de3c408421ec059c626b92b9168adc0f9", 33 | "signatureType": "Overlay", 34 | "signingDate": [ 35 | "2023-03-18T02:15:00" 36 | ], 37 | "signingStatus": "Signed", 38 | "size": 2174872, 39 | "timestamp": 3085964618, 40 | "version": "10.0.22621.1485 (WinBuild.160101.0800)", 41 | "virtualSize": 2179072 42 | }, 43 | "windowsVersions": { 44 | "11-22H2": { 45 | "KB5023778": { 46 | "assemblies": { 47 | "amd64_microsoft-windows-ntdll_31bf3856ad364e35_10.0.22621.1485_none_38c42af777bdcc16": { 48 | "assemblyIdentity": { 49 | "buildType": "release", 50 | "language": "neutral", 51 | "name": "Microsoft-Windows-Ntdll", 52 | "processorArchitecture": "amd64", 53 | "publicKeyToken": "31bf3856ad364e35", 54 | "version": "10.0.22621.1485", 55 | "versionScope": "nonSxS" 56 | }, 57 | "attributes": [ 58 | { 59 | "destinationPath": "$(runtime.system32)\\", 60 | "importPath": "$(build.nttree)\\", 61 | "name": "ntdll.dll", 62 | "sourceName": "ntdll.dll", 63 | "sourcePath": ".\\" 64 | } 65 | ] 66 | } 67 | }, 68 | "updateInfo": { 69 | "heading": "March 28, 2023—KB5023778 (OS Build 22621.1485) Preview", 70 | "releaseDate": "2023-03-28", 71 | "releaseVersion": "22621.1485", 72 | "updateUrl": "https://support.microsoft.com/help/5023778" 73 | } 74 | }, 75 | "KB5025239": { 76 | "assemblies": { 77 | "amd64_microsoft-windows-ntdll_31bf3856ad364e35_10.0.22621.1485_none_38c42af777bdcc16": { 78 | "assemblyIdentity": { 79 | "buildType": "release", 80 | "language": "neutral", 81 | "name": "Microsoft-Windows-Ntdll", 82 | "processorArchitecture": "amd64", 83 | "publicKeyToken": "31bf3856ad364e35", 84 | "version": "10.0.22621.1485", 85 | "versionScope": "nonSxS" 86 | }, 87 | "attributes": [ 88 | { 89 | "destinationPath": "$(runtime.system32)\\", 90 | "importPath": "$(build.nttree)\\", 91 | "name": "ntdll.dll", 92 | "sourceName": "ntdll.dll", 93 | "sourcePath": ".\\" 94 | } 95 | ] 96 | } 97 | }, 98 | "updateInfo": { 99 | "heading": "April 11, 2023—KB5025239 (OS Build 22621.1555)", 100 | "releaseDate": "2023-04-11", 101 | "releaseVersion": "22621.1555", 102 | "updateUrl": "https://support.microsoft.com/help/5025239" 103 | } 104 | } 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | ## Downloads & Automation 111 | 112 | When you run `BulkBindex` you should expect about a 20 minute runtime to fetch all binaries for a single build (depending on bandwidth). In this repository I have also added `GitHub Workflow` automation which allows workers to fetch builds for various versions and add them to the same release. 113 | 114 | Further testing is needed but a release has already been uploaded for `April 2023 -> 11 22H2 & 10 22H2`. The intention is to add a schedule to the workflow so these releases are created right after `patch tuesday` starting from the next cycle. 115 | 116 | ## Halp?! 117 | 118 | The code is still quite DIY. I am more than happy to receive PR's both on `BulkBindex` and the `GitHub Workflow` automation! Additions which also fetch `PDB's` welcome! --------------------------------------------------------------------------------