├── .gitignore ├── ConsoleApp1 ├── App.config ├── AssemblyLoader.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── DemoAssembly ├── DemoAssembly.csproj ├── DemoClass.cs └── Properties │ └── AssemblyInfo.cs ├── DotNetGargoyle.sln ├── EnumerateDotNetTimers ├── App.config ├── EnumerateDotNetTimers.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Timers.cs └── packages.config ├── NativeDll ├── NativeDll.vcxproj ├── NativeDll.vcxproj.filters └── dll.cpp ├── NativeMainApp ├── NativeMainApp.cpp ├── NativeMainApp.vcxproj ├── NativeMainApp.vcxproj.filters ├── stdafx.cpp ├── stdafx.h └── targetver.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 235 | **/wwwroot/lib/ 236 | 237 | # RIA/Silverlight projects 238 | Generated_Code/ 239 | 240 | # Backup & report files from converting an old project file 241 | # to a newer Visual Studio version. Backup files are not needed, 242 | # because we have git ;-) 243 | _UpgradeReport_Files/ 244 | Backup*/ 245 | UpgradeLog*.XML 246 | UpgradeLog*.htm 247 | ServiceFabricBackup/ 248 | *.rptproj.bak 249 | 250 | # SQL Server files 251 | *.mdf 252 | *.ldf 253 | *.ndf 254 | 255 | # Business Intelligence projects 256 | *.rdl.data 257 | *.bim.layout 258 | *.bim_*.settings 259 | *.rptproj.rsuser 260 | 261 | # Microsoft Fakes 262 | FakesAssemblies/ 263 | 264 | # GhostDoc plugin setting file 265 | *.GhostDoc.xml 266 | 267 | # Node.js Tools for Visual Studio 268 | .ntvs_analysis.dat 269 | node_modules/ 270 | 271 | # Visual Studio 6 build log 272 | *.plg 273 | 274 | # Visual Studio 6 workspace options file 275 | *.opt 276 | 277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 278 | *.vbw 279 | 280 | # Visual Studio LightSwitch build output 281 | **/*.HTMLClient/GeneratedArtifacts 282 | **/*.DesktopClient/GeneratedArtifacts 283 | **/*.DesktopClient/ModelManifest.xml 284 | **/*.Server/GeneratedArtifacts 285 | **/*.Server/ModelManifest.xml 286 | _Pvt_Extensions 287 | 288 | # Paket dependency manager 289 | .paket/paket.exe 290 | paket-files/ 291 | 292 | # FAKE - F# Make 293 | .fake/ 294 | 295 | # JetBrains Rider 296 | .idea/ 297 | *.sln.iml 298 | 299 | # CodeRush personal settings 300 | .cr/personal 301 | 302 | # Python Tools for Visual Studio (PTVS) 303 | __pycache__/ 304 | *.pyc 305 | 306 | # Cake - Uncomment if you are using it 307 | # tools/** 308 | # !tools/packages.config 309 | 310 | # Tabs Studio 311 | *.tss 312 | 313 | # Telerik's JustMock configuration file 314 | *.jmconfig 315 | 316 | # BizTalk build output 317 | *.btp.cs 318 | *.btm.cs 319 | *.odx.cs 320 | *.xsd.cs 321 | 322 | # OpenCover UI analysis results 323 | OpenCover/ 324 | 325 | # Azure Stream Analytics local run output 326 | ASALocalRun/ 327 | 328 | # MSBuild Binary and Structured Log 329 | *.binlog 330 | 331 | # NVidia Nsight GPU debugger configuration file 332 | *.nvuser 333 | 334 | # MFractors (Xamarin productivity tool) working folder 335 | .mfractor/ 336 | 337 | # Local History for Visual Studio 338 | .localhistory/ -------------------------------------------------------------------------------- /ConsoleApp1/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ConsoleApp1/AssemblyLoader.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {76435F79-F8AF-4D74-8DF5-D598A551B895} 8 | Library 9 | AssemblyLoader 10 | AssemblyLoader 11 | v4.6.1 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | full 42 | x64 43 | prompt 44 | MinimumRecommendedRules.ruleset 45 | 46 | 47 | bin\x64\Release\ 48 | TRACE 49 | true 50 | pdbonly 51 | x64 52 | prompt 53 | MinimumRecommendedRules.ruleset 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /ConsoleApp1/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.IO; 4 | using System.Reflection; 5 | 6 | public class AssemblyLoader 7 | { 8 | public interface IAssemblyLoader 9 | { 10 | void Load(byte[] bytes); 11 | } 12 | 13 | public class AssemblyLoaderProxy : MarshalByRefObject, IAssemblyLoader 14 | { 15 | public void Load(byte[] bytes) 16 | { 17 | var assembly = AppDomain.CurrentDomain.Load(bytes); 18 | var type = assembly.GetType("DemoAssembly.DemoClass"); 19 | var method = type.GetMethod("HelloWorld"); 20 | var instance = Activator.CreateInstance(type, null); 21 | Console.WriteLine("--- Executed from {0}: {1}", AppDomain.CurrentDomain.FriendlyName, method.Invoke(instance, null)); 22 | } 23 | } 24 | 25 | public static int StartTimer(string gargoyleDllContentsInBase64) 26 | { 27 | Console.WriteLine("Start timer function called"); 28 | byte[] dllByteArray = Convert.FromBase64String(gargoyleDllContentsInBase64); 29 | Timer t = new Timer(new TimerCallback(TimerProcAssemblyLoad), dllByteArray, 0, 0); 30 | return 0; 31 | } 32 | 33 | private static void TimerProcAssemblyLoad(object state) 34 | { 35 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 36 | Console.WriteLine("Hello from timer!"); 37 | 38 | String appDomainName = "TemporaryApplicationDomain"; 39 | AppDomain applicationDomain = System.AppDomain.CreateDomain(appDomainName); 40 | var assmblyLoaderType = typeof(AssemblyLoaderProxy); 41 | var assemblyLoader = (IAssemblyLoader)applicationDomain.CreateInstanceFromAndUnwrap(assmblyLoaderType.Assembly.Location, assmblyLoaderType.FullName); 42 | assemblyLoader.Load((byte[])state); 43 | Console.WriteLine("Dynamic assembly has been loaded in new AppDomain " + appDomainName); 44 | 45 | AppDomain.Unload(applicationDomain); 46 | Console.WriteLine("New AppDomain has been unloaded"); 47 | 48 | Timer t = new Timer(new TimerCallback(TimerProcAssemblyLoad), state, 1000, 0); 49 | } 50 | 51 | private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 52 | { 53 | try 54 | { 55 | Assembly assembly = System.Reflection.Assembly.Load(args.Name); 56 | if (assembly != null) 57 | return assembly; 58 | } 59 | catch 60 | { // ignore load error } 61 | 62 | // *** Try to load by filename - split out the filename of the full assembly name 63 | // *** and append the base path of the original assembly (ie. look in the same dir) 64 | // *** NOTE: this doesn't account for special search paths but then that never 65 | // worked before either. 66 | string[] Parts = args.Name.Split(','); 67 | string File = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + Parts[0].Trim() + ".dll"; 68 | 69 | return System.Reflection.Assembly.LoadFrom(File); 70 | } 71 | return null; 72 | } 73 | } -------------------------------------------------------------------------------- /ConsoleApp1/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("ConsoleApp1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ConsoleApp1")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 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("76435f79-f8af-4d74-8df5-d598a551b895")] 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 | -------------------------------------------------------------------------------- /DemoAssembly/DemoAssembly.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220} 8 | Library 9 | Properties 10 | DemoAssembly 11 | DemoAssembly 12 | v4.6.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | bin\x64\Debug\ 35 | DEBUG;TRACE 36 | full 37 | x64 38 | prompt 39 | MinimumRecommendedRules.ruleset 40 | 41 | 42 | bin\x64\Release\ 43 | TRACE 44 | true 45 | pdbonly 46 | x64 47 | prompt 48 | MinimumRecommendedRules.ruleset 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /DemoAssembly/DemoClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DemoAssembly 8 | { 9 | public class DemoClass 10 | { 11 | public static string HelloWorld() 12 | { 13 | return "Hello World from DemoAssembly!"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DemoAssembly/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("DemoAssembly")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DemoAssembly")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 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("6f0bbb2a-e200-4d76-b8fa-f93c801ac220")] 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 | -------------------------------------------------------------------------------- /DotNetGargoyle.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLoader", "ConsoleApp1\AssemblyLoader.csproj", "{76435F79-F8AF-4D74-8DF5-D598A551B895}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NativeMainApp", "NativeMainApp\NativeMainApp.vcxproj", "{4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NativeDll", "NativeDll\NativeDll.vcxproj", "{C08A1ED9-4989-423A-A356-28A24DFAC703}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoAssembly", "DemoAssembly\DemoAssembly.csproj", "{6F0BBB2A-E200-4D76-B8FA-F93C801AC220}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumerateDotNetTimers", "EnumerateDotNetTimers\EnumerateDotNetTimers.csproj", "{5A3FC840-5432-4925-B5BC-ABC536429CB5}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|Any CPU = Release|Any CPU 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|x64.ActiveCfg = Debug|x64 29 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|x64.Build.0 = Debug|x64 30 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|x86.ActiveCfg = Debug|Any CPU 31 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Debug|x86.Build.0 = Debug|Any CPU 32 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|x64.ActiveCfg = Release|Any CPU 35 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|x64.Build.0 = Release|Any CPU 36 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|x86.ActiveCfg = Release|Any CPU 37 | {76435F79-F8AF-4D74-8DF5-D598A551B895}.Release|x86.Build.0 = Release|Any CPU 38 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|Any CPU.ActiveCfg = Debug|Win32 39 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|Any CPU.Build.0 = Debug|Win32 40 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|x64.ActiveCfg = Debug|x64 41 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|x64.Build.0 = Debug|x64 42 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|x86.ActiveCfg = Debug|Win32 43 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Debug|x86.Build.0 = Debug|Win32 44 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Release|Any CPU.ActiveCfg = Release|Win32 45 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Release|x64.ActiveCfg = Release|x64 46 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Release|x64.Build.0 = Release|x64 47 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Release|x86.ActiveCfg = Release|Win32 48 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B}.Release|x86.Build.0 = Release|Win32 49 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|Any CPU.ActiveCfg = Debug|Win32 50 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|Any CPU.Build.0 = Debug|Win32 51 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|x64.ActiveCfg = Debug|x64 52 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|x64.Build.0 = Debug|x64 53 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|x86.ActiveCfg = Debug|Win32 54 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Debug|x86.Build.0 = Debug|Win32 55 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Release|Any CPU.ActiveCfg = Release|Win32 56 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Release|x64.ActiveCfg = Release|x64 57 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Release|x64.Build.0 = Release|x64 58 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Release|x86.ActiveCfg = Release|Win32 59 | {C08A1ED9-4989-423A-A356-28A24DFAC703}.Release|x86.Build.0 = Release|Win32 60 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|x64.ActiveCfg = Debug|x64 63 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|x64.Build.0 = Debug|x64 64 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|x86.ActiveCfg = Debug|Any CPU 65 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Debug|x86.Build.0 = Debug|Any CPU 66 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|x64.ActiveCfg = Release|Any CPU 69 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|x64.Build.0 = Release|Any CPU 70 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|x86.ActiveCfg = Release|Any CPU 71 | {6F0BBB2A-E200-4D76-B8FA-F93C801AC220}.Release|x86.Build.0 = Release|Any CPU 72 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|x64.ActiveCfg = Debug|x64 75 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|x64.Build.0 = Debug|x64 76 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|x86.ActiveCfg = Debug|Any CPU 77 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Debug|x86.Build.0 = Debug|Any CPU 78 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|x64.ActiveCfg = Release|Any CPU 81 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|x64.Build.0 = Release|Any CPU 82 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|x86.ActiveCfg = Release|Any CPU 83 | {5A3FC840-5432-4925-B5BC-ABC536429CB5}.Release|x86.Build.0 = Release|Any CPU 84 | EndGlobalSection 85 | GlobalSection(SolutionProperties) = preSolution 86 | HideSolutionNode = FALSE 87 | EndGlobalSection 88 | GlobalSection(ExtensibilityGlobals) = postSolution 89 | SolutionGuid = {1D5A20DE-3455-44EF-9350-13B4B3E946FB} 90 | EndGlobalSection 91 | EndGlobal 92 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/EnumerateDotNetTimers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5A3FC840-5432-4925-B5BC-ABC536429CB5} 8 | Exe 9 | EnumerateDotNetTimers 10 | EnumerateDotNetTimers 11 | v4.6.1 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | true 36 | bin\x64\Debug\ 37 | DEBUG;TRACE 38 | full 39 | x64 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | true 43 | 44 | 45 | bin\x64\Release\ 46 | TRACE 47 | true 48 | pdbonly 49 | x64 50 | prompt 51 | MinimumRecommendedRules.ruleset 52 | true 53 | 54 | 55 | 56 | ..\packages\Microsoft.Diagnostics.Runtime.0.9.180305.01\lib\net40\Microsoft.Diagnostics.Runtime.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Diagnostics.Runtime; 7 | using System.Diagnostics; 8 | 9 | 10 | namespace ClrMdHarness 11 | { 12 | class Program 13 | { 14 | static void Usage() 15 | { 16 | Console.WriteLine("ERROR - Invalid args"); 17 | Console.WriteLine(); 18 | Console.WriteLine("EnumerateDotNetTimers.exe --all | --non-microsoft-only"); 19 | Console.WriteLine(); 20 | Console.WriteLine("--all\t\t\tEnumerate all timers"); 21 | Console.WriteLine("--non-microsoft-only\tEnumerate only timers with non-System and non-Microsoft namespaces"); 22 | } 23 | static void Main(string[] args) 24 | { 25 | bool enumerateAll = true; 26 | 27 | if (args.Length < 1) 28 | { 29 | Usage(); 30 | return; 31 | } 32 | else if (args[0] == "--all") 33 | { 34 | enumerateAll = true; 35 | } 36 | else if (args[0] == "--non-microsoft-only") 37 | { 38 | enumerateAll = false; 39 | } 40 | else 41 | { 42 | Usage(); 43 | return; 44 | } 45 | 46 | Console.WriteLine("Timers\n============"); 47 | 48 | foreach (var process in Process.GetProcesses()) 49 | { 50 | try 51 | { 52 | using (DataTarget target = DataTarget.AttachToProcess(process.Id, 1000, AttachFlag.Passive)) 53 | { 54 | // First, loop through each Clr in the process (there may be multiple in the side-by-side scenario). 55 | foreach (ClrInfo clrVersion in target.ClrVersions) 56 | { 57 | ClrRuntime runtime = clrVersion.CreateRuntime(); 58 | Timers t = new Timers(); 59 | var timers = t.EnumerateTimers(runtime); 60 | foreach (var timer in timers) 61 | { 62 | if (!timer.MethodName.StartsWith("System") && !timer.MethodName.StartsWith("Microsoft")) 63 | { 64 | Console.WriteLine("[NON-MICROSOFT] - {0}:{1} - {2}, {3}, {4:X}, {5:X}, {6}", process.ProcessName, process.Id, timer.DueTime.ToString(), timer.StateTypeName, timer.ThisAddress, timer.MethodAddress, timer.MethodName); 65 | } 66 | else if (enumerateAll) 67 | { 68 | Console.WriteLine("[MICROSOFT] - {0}:{1} - {2}, {3}, {4:X}, {5:X}, {6}", process.ProcessName, process.Id, timer.DueTime.ToString(), timer.StateTypeName, timer.ThisAddress, timer.MethodAddress, timer.MethodName); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | catch (Exception e) 75 | { 76 | // Console.WriteLine(e); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/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("EnumerateDotNetTimers")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("EnumerateDotNetTimers")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 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("5a3fc840-5432-4925-b5bc-abc536429cb5")] 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 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/Timers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Diagnostics.Runtime; 7 | 8 | 9 | namespace ClrMdHarness 10 | { 11 | class Timers 12 | { 13 | public class TimerInfo 14 | { 15 | public ulong TimerQueueTimerAddress { get; set; } 16 | public uint DueTime { get; set; } 17 | public uint Period { get; set; } 18 | public bool Cancelled { get; set; } 19 | public ulong StateAddress { get; set; } 20 | public string StateTypeName { get; set; } 21 | public ulong ThisAddress { get; set; } 22 | public string MethodName { get; set; } 23 | public ulong MethodAddress { get; set; } 24 | } 25 | 26 | // from threadpool.cs in https://github.com/Microsoft/clrmd/tree/master/src/Microsoft.Diagnostics.Runtime/Desktop 27 | public ClrModule GetMscorlib(ClrRuntime runtime) 28 | { 29 | foreach (ClrModule module in runtime.Modules) 30 | if (module.AssemblyName.Contains("mscorlib.dll")) 31 | return module; 32 | 33 | // Uh oh, this shouldn't have happened. Let's look more carefully (slowly). 34 | foreach (ClrModule module in runtime.Modules) 35 | if (module.AssemblyName.ToLower().Contains("mscorlib")) 36 | return module; 37 | 38 | // Ok...not sure why we couldn't find it. 39 | return null; 40 | } 41 | 42 | private object GetFieldValue(ClrHeap heap, ulong address, string fieldName) 43 | { 44 | var type = heap.GetObjectType(address); 45 | ClrInstanceField field = type.GetFieldByName(fieldName); 46 | if (field == null) 47 | return null; 48 | 49 | return field.GetValue(address); 50 | } 51 | 52 | private string BuildTimerCallbackMethodName(ClrRuntime runtime, ulong timerCallbackRef, string methodPtrString) 53 | { 54 | var heap = runtime.Heap; 55 | var methodPtr = GetFieldValue(heap, timerCallbackRef, methodPtrString); 56 | if (methodPtr != null) 57 | { 58 | ClrMethod method = runtime.GetMethodByAddress((ulong)(long)methodPtr); 59 | if (method != null) 60 | { 61 | // look for "this" to figure out the real callback implementor type 62 | string thisTypeName = "?"; 63 | var thisPtr = GetFieldValue(heap, timerCallbackRef, "_target"); 64 | if ((thisPtr != null) && ((ulong)thisPtr) != 0) 65 | { 66 | ulong thisRef = (ulong)thisPtr; 67 | var thisType = heap.GetObjectType(thisRef); 68 | if (thisType != null) 69 | { 70 | thisTypeName = thisType.Name; 71 | } 72 | } 73 | else 74 | { 75 | thisTypeName = (method.Type != null) ? method.Type.Name : "?"; 76 | } 77 | return method.GetFullSignature(); 78 | return string.Format("{0}.{1}", thisTypeName, method.Name); 79 | } 80 | else 81 | { 82 | return ""; 83 | } 84 | } 85 | else 86 | { 87 | return ""; 88 | } 89 | } 90 | 91 | public IEnumerable EnumerateTimers(ClrRuntime runtime) 92 | { 93 | ClrHeap heap = runtime.Heap; 94 | if (!heap.CanWalkHeap) 95 | yield break; 96 | 97 | var timerQueueType = GetMscorlib(runtime).GetTypeByName("System.Threading.TimerQueue"); 98 | if (timerQueueType == null) 99 | yield break; 100 | 101 | ClrStaticField staticField = timerQueueType.GetStaticFieldByName("s_queue"); 102 | if (staticField == null) 103 | yield break; 104 | 105 | foreach (ClrAppDomain domain in runtime.AppDomains) 106 | { 107 | ulong? timerQueue = (ulong?)staticField.GetValue(domain); 108 | if (!timerQueue.HasValue || timerQueue.Value == 0) 109 | continue; 110 | 111 | // m_timers is the start of the list of TimerQueueTimer 112 | var currentPointer = GetFieldValue(heap, timerQueue.Value, "m_timers"); 113 | 114 | while ((currentPointer != null) && (((ulong)currentPointer) != 0)) 115 | { 116 | // currentPointer points to a TimerQueueTimer instance 117 | ulong currentTimerQueueTimerRef = (ulong)currentPointer; 118 | 119 | TimerInfo ti = new TimerInfo() 120 | { 121 | TimerQueueTimerAddress = currentTimerQueueTimerRef 122 | }; 123 | 124 | var val = GetFieldValue(heap, currentTimerQueueTimerRef, "m_dueTime"); 125 | ti.DueTime = (uint)val; 126 | val = GetFieldValue(heap, currentTimerQueueTimerRef, "m_period"); 127 | ti.Period = (uint)val; 128 | val = GetFieldValue(heap, currentTimerQueueTimerRef, "m_canceled"); 129 | ti.Cancelled = (bool)val; 130 | val = GetFieldValue(heap, currentTimerQueueTimerRef, "m_state"); 131 | ti.StateTypeName = ""; 132 | if (val == null) 133 | { 134 | ti.StateAddress = 0; 135 | } 136 | else 137 | { 138 | ti.StateAddress = (ulong)val; 139 | var stateType = heap.GetObjectType(ti.StateAddress); 140 | if (stateType != null) 141 | { 142 | ti.StateTypeName = stateType.Name; 143 | } 144 | } 145 | 146 | // decypher the callback details 147 | val = GetFieldValue(heap, currentTimerQueueTimerRef, "m_timerCallback"); 148 | if (val != null) 149 | { 150 | ulong elementAddress = (ulong)val; 151 | if (elementAddress == 0) 152 | continue; 153 | 154 | var elementType = heap.GetObjectType(elementAddress); 155 | if (elementType != null) 156 | { 157 | if (elementType.Name == "System.Threading.TimerCallback") 158 | { 159 | ti.MethodAddress = (ulong)(long)GetFieldValue(heap, elementAddress, "_methodPtr"); 160 | ti.MethodName = BuildTimerCallbackMethodName(runtime, elementAddress, "_methodPtr"); 161 | if (ti.MethodName == "") 162 | { 163 | ti.MethodAddress = (ulong)(long)GetFieldValue(heap, elementAddress, "_methodPtrAux"); 164 | ti.MethodName = BuildTimerCallbackMethodName(runtime, elementAddress, "_methodPtrAux"); 165 | } 166 | } 167 | else 168 | { 169 | ti.MethodName = "<" + elementType.Name + ">"; 170 | } 171 | } 172 | else 173 | { 174 | ti.MethodName = "{no callback type?}"; 175 | } 176 | } 177 | else 178 | { 179 | ti.MethodName = "???"; 180 | } 181 | 182 | yield return ti; 183 | 184 | currentPointer = GetFieldValue(heap, currentTimerQueueTimerRef, "m_next"); 185 | } 186 | } 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /EnumerateDotNetTimers/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /NativeDll/NativeDll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {C08A1ED9-4989-423A-A356-28A24DFAC703} 24 | NativeDll 25 | 10.0.17134.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | Level3 84 | Disabled 85 | true 86 | true 87 | 88 | 89 | 90 | 91 | Level3 92 | MaxSpeed 93 | true 94 | true 95 | true 96 | true 97 | 98 | 99 | true 100 | true 101 | 102 | 103 | 104 | 105 | Level3 106 | MaxSpeed 107 | true 108 | true 109 | true 110 | true 111 | 112 | 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | {76435f79-f8af-4d74-8df5-d598a551b895} 123 | 124 | 125 | {6f0bbb2a-e200-4d76-b8fa-f93c801ac220} 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /NativeDll/NativeDll.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /NativeDll/dll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #pragma comment(lib, "mscoree.lib") 8 | 9 | 10 | static char encoding_table[] = { 11 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 12 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 13 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 14 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 15 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 16 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 17 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', 18 | '4', '5', '6', '7', '8', '9', '+', '/' }; 19 | static char *decoding_table = NULL; 20 | static int mod_table[] = { 0, 2, 1 }; 21 | 22 | 23 | char *base64_encode(const unsigned char *data, 24 | size_t input_length, 25 | size_t *output_length) { 26 | 27 | *output_length = 4 * ((input_length + 2) / 3); 28 | 29 | char *encoded_data = (char*)calloc(*output_length, sizeof(char)); 30 | if (encoded_data == NULL) return NULL; 31 | 32 | for (unsigned int i = 0, j = 0; i < input_length;) { 33 | 34 | uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; 35 | uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; 36 | uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; 37 | 38 | uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; 39 | 40 | encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; 41 | encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; 42 | encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; 43 | encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; 44 | } 45 | 46 | for (int i = 0; i < mod_table[input_length % 3]; i++) 47 | encoded_data[*output_length - 1 - i] = '='; 48 | 49 | encoded_data[*output_length] = '\0'; 50 | 51 | return encoded_data; 52 | } 53 | 54 | 55 | DWORD WINAPI RunDotNet(LPVOID lpvParam) 56 | { 57 | HRESULT hr; 58 | ICLRMetaHost *pMetaHost = NULL; 59 | ICLRRuntimeInfo *pRuntimeInfo = NULL; 60 | ICLRRuntimeHost *pClrRuntimeHost = NULL; 61 | 62 | // build runtime 63 | hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); 64 | hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); 65 | hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, 66 | IID_PPV_ARGS(&pClrRuntimeHost)); 67 | 68 | // start runtime 69 | hr = pClrRuntimeHost->Start(); 70 | 71 | // convert malicious assembly to base64-encoded byte stream 72 | FILE *fileptr; 73 | char *buffer; 74 | long filelen; 75 | size_t outputlen; 76 | 77 | _wfopen_s(&fileptr, L"DemoAssembly.dll", L"rb"); // Open the file in binary mode 78 | fseek(fileptr, 0, SEEK_END); // Jump to the end of the file 79 | filelen = ftell(fileptr); // Get the current byte offset in the file 80 | rewind(fileptr); // Jump back to the beginning of the file 81 | 82 | buffer = (char *)calloc((filelen + 1), sizeof(char)); // Enough memory for file + \0 83 | fread(buffer, filelen, 1, fileptr); // Read in the entire file 84 | fclose(fileptr); // Close the file 85 | char *char_base64contents = base64_encode((unsigned char*)buffer, filelen, &outputlen); 86 | LPCWSTR lpcwstr_base64_contents = (LPCWSTR)calloc(outputlen + 1, sizeof(wchar_t)); 87 | mbstowcs_s(&outputlen, (wchar_t*)lpcwstr_base64_contents, outputlen + 1, char_base64contents, outputlen); 88 | 89 | // execute managed assembly 90 | DWORD pReturnValue; 91 | hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( 92 | L"AssemblyLoader.dll", 93 | L"AssemblyLoader", 94 | L"StartTimer", 95 | lpcwstr_base64_contents, 96 | &pReturnValue); 97 | 98 | return 0; 99 | } 100 | 101 | BOOL WINAPI DllMain( 102 | __in HINSTANCE hinstDLL, 103 | __in DWORD fdwReason, 104 | __in LPVOID lpvReserved 105 | ) { 106 | switch (fdwReason) { 107 | case DLL_PROCESS_ATTACH: 108 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunDotNet, NULL, 0, NULL); 109 | break; 110 | case DLL_PROCESS_DETACH: 111 | break; 112 | case DLL_THREAD_ATTACH: 113 | break; 114 | case DLL_THREAD_DETACH: 115 | break; 116 | } 117 | return TRUE; 118 | } 119 | 120 | int wmain(int argc, wchar_t *argv[]) 121 | { 122 | RunDotNet(NULL); 123 | _getch(); 124 | } -------------------------------------------------------------------------------- /NativeMainApp/NativeMainApp.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WithSecureLabs/dotnet-gargoyle/ee5d0878e4ff7ac485172ca78b3cf522fce0da97/NativeMainApp/NativeMainApp.cpp -------------------------------------------------------------------------------- /NativeMainApp/NativeMainApp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {4BBB15A7-F6E7-492F-92CA-10CA66F0EE1B} 24 | Win32Proj 25 | NativeMainApp 26 | 10.0.17134.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Use 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Use 102 | Level3 103 | Disabled 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Use 116 | Level3 117 | MaxSpeed 118 | true 119 | true 120 | true 121 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | 124 | 125 | Console 126 | true 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | Use 134 | Level3 135 | MaxSpeed 136 | true 137 | true 138 | true 139 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | true 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Create 157 | Create 158 | Create 159 | Create 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /NativeMainApp/NativeMainApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /NativeMainApp/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WithSecureLabs/dotnet-gargoyle/ee5d0878e4ff7ac485172ca78b3cf522fce0da97/NativeMainApp/stdafx.cpp -------------------------------------------------------------------------------- /NativeMainApp/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WithSecureLabs/dotnet-gargoyle/ee5d0878e4ff7ac485172ca78b3cf522fce0da97/NativeMainApp/stdafx.h -------------------------------------------------------------------------------- /NativeMainApp/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WithSecureLabs/dotnet-gargoyle/ee5d0878e4ff7ac485172ca78b3cf522fce0da97/NativeMainApp/targetver.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotnet-gargoyle 2 | A spiritual .NET equivalent to the Gargoyle memory scanning evasion technique 3 | 4 | https://www.countercept.com/blog/gargoyle-memory-scanning-evasion-for-net/ 5 | --------------------------------------------------------------------------------