Scottzxor
Scottzxor

Reputation: 11

How to return all applications with dependencies on .NET Framework, specific to versions?

I'm trying to find all applications that rely on outdated.NET Framework versions. For instance, on a client environment, they have .NET Framework version 1.0 enabled in their registry. This is from 2002 and is horribly vulnerable with multiple CVEs of 9.3, security-wise. Same for .NET Framework 2.0., possibly 3.0.

.NET is one of the most vulnerable applications via CISA, and this issue consistently pops up across multiple clients. I want to remove these outdated Framework versions, but I've read that applications built using those older versions may not be able to switch to newer versions, so it could break very important applications that are needed to save lives and require 100% uptime.

I've tried tasklist /m "mscore*" as a cmd command to return applications currently being executed via the .dll engine. So it only returns running applications, and it also doesn't tell me which versions of .NET Framework are used on the running applications. There is also no mscorlib.dll version in either the 3.0 or 3.5 directories.

I can also do this simply with ProcMon, but I face the same issue: this will only tell me the active and running processes

I've tried using a C# script using ICorPublish interface, but this also just returns PIDs, so it also relies on the application running.

ICorPublishProcess process;

process = publish.GetProcess(PidToCheck);

if (process == null || !process.IsManaged)
{
    return "Process managed by .NET"
}
else
{
    return "Process not managed by .NET."
}

I can find all installed versions of .NET Framework easily enough via: https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed

However, I can't find anything regarding how to find all applications--with running processes or not running--that have dependencies on specific .NET Framework versions.

Is there a way to find applications that aren't currently running that are reliant on older .NET Framework versions to function?

Upvotes: 1

Views: 701

Answers (1)

mklement0
mklement0

Reputation: 437688

You can try the following brute-force approach - which will run for a long time, however:

  • Open an elevated PowerShell instance (run as admin), so as to get access to as many directories as possible.

  • Starting from the root of all drives of interest, search for all *.exe files across the entire disk (depending on your needs you may have to examine *.dll files too) and determine their target .NET CLR version using [System.Reflection.Assembly]::LoadFile($filePath).ImageRuntimeVersion

The following code demonstrates this:

# You can pass multiple root directories, if needed.
# If you need to include DLLs too, replace -Filter *.exe
# with -Include *.exe, *.dll
Get-ChildItem C:\ -Filter *.exe -Recurse -ErrorAction SilentlyContinue -ErrorVariable errs | 
  ForEach-Object { 
    try {
      [pscustomobject] @{ 
        Path = $_.FullName
        CLRVersion = [System.Reflection.Assembly]::LoadFile($_.FullName).ImageRuntimeVersion 
      }
    } 
    catch {} 
  } | 
  Format-List

Note:

  • The Format-List command is solely for display formatting.

    • If instead you want to save the results in CSV format, for instance, pipe to Export-Csv instead.

    • If you want to save the results to a variable ($results = ...), simply omit | Format-List.

  • If you want to limit output to specific versions, insert the following before | Format-List:

    • To find those below a threshold, such as all CLR version lower than 4.0

      | Where-Object { [version] $_.CLRVersion.Substring(1) -lt [version] '4.0' }
      
    • To find those for a specific version, such as v1.1:

      | Where-Object { $_.CLRVersion -like 'v1.1.*' }
      
  • Variable $errs will contain any errors that occurred during file enumeration.

Caveats:

  • The Assembly.ImageRuntimeVersion is only supported in .NET Framework v1.1 and above - if you really still have applications for 1.0, you'll need a different approach (perhaps the answers to this question provide pointers).

  • The version number reported - e.g. v4.0.30319 - is that of the CLR (the runtime engine), not that of the framework (the class library; e.g., the 3.0 framework builds on the 2.0 CLR).

  • Assemblies created for the cross-platform .NET Core / .NET 5+ editions, apparently for backward compatibility, present as if they target .NET Framework's version 4.0 CLR (v4.0.30319)

    • In these .NET editions, there is no longer a distinction between the CLR and frameworks, so you can presumably inspect the TargetFramework attribute, as shown in this answer; said answer is written for .NET Framework, where it works for assemblies written for .NET Framework version 4.0 and above; to make it work with the cross-platform editions, method ReflectionOnlyLoadFrom must be replaced with method LoadFile.

Upvotes: 1

Related Questions