Search code examples
powershellcmddllattributesget-childitem

How can I check for the presence of .DLL files using cmd.exe or PowerShell, without changing permissions?


How can I check for the presence of these https://bugzilla.mozilla.org/show_bug.cgi?id=1841751#c4 .DLL files in C:\ProgramData and child containers, using cmd.exe or PowerShell?

Preferably one-liners rather that scripts.

Without changing access permissions of any files or folders. (When using explorer I would have to change the permissions).

Have not tried anything yet as I am not sure what to do exactly, or if it will do something irreversible. Not even sure if this would show the attributes for the DLLs without the need to change permissions. Thought of using Get-Childitem, but this:- Get file version and assembly version of DLL files in the current directory and all sub directories says items stay loaded and can't be deleted "unfortunately it loads the files and never releases them". Unless using code I don't understand to spawn a new PowerShell instance.


Solution

  • Fundamentally, the subdirectories of the hidden system directory C:\ProgramData ($env:ProgramData or $env:ALLUSERSPROFILE) fall into one of 3 categories:

    • (a) Some can be read by anyone.

    • (b) Some are protected from being read by non-elevated processes (run without administrative privileges).

    • (c) Some are even protected from having their contents read by elevated processes.

    Interactively, for directories in (b) and (c), the current user can persistently gain access via a one-time action in File Explorer, which changes the file-system permissions (ACLs):

    • File Explorer offers to perform this change on accessing an affected folder, via a UAC dialog (which means that if the current user is an administrator, only confirming the dialog is sufficient; otherwise, an administrator's credentials are needed).

    Programmatically, (for directories that haven't already been "unlocked" interactively), you can only gain access to category (b) ad hoc, without changing permissions:[1]

    • That is, you must ensure that your Get-ChildItem calls are made from an elevated PowerShell session (the same requirements as discussed for the UAC dialog above apply):

    • Interactively, right-click your PowerShell taskbar / Start Menu icon, select Run as Administrator, and confirm the UAC dialog, then run your Get-ChildItem / Test-Path command.

    • Programmatically, from an existing non-elevated PowerShell session:

      • Use Start-Process -Verb RunAs (Get-Process -Id $PID).Path to start an interactive elevated session, then submit your command in that new session.

      • If you want to start an elevated session and submit a command in a single operation, do something like the following:

    Start-Process -Verb RunAs (Get-Process -Id $PID).Path @'
      -NoExit -Command
    
      Get-ChildItem -ErrorAction SilentlyContinue -ErrorVariable err -Recurse -Force -Filter *.dll -LiteralPath C:\ProgramData  |
        ForEach-Object VersionInfo |
        Where-Object FileVersion -in '1.0.0.26638', '1.0.0.26793', '1.0.0.27567', '1.0.0.29915', '1.0.0.31122'
    
      if ($err) {
        $notAuthorized, $others = $err.Where({ $_.Exception -is [System.UnauthorizedAccessException] }, 'Split')
        if ($notAuthorized) {
          Write-Warning "You are not authorized to access the following paths:`n $($notAuthorized.TargetObject -join "`n  ")"
        }
        if ($others) {
          Write-Warning "The following unexpected errors occurred:`n $($others.ForEach('ToString') -join "`n  ")"
        }
      }
    '@.Replace('"', '\"')
    

    Note:

    • The above is an example command that tries to find malware DLLs by specific version numbers only, which can yield false positives or may not find anything at all if the version numbers don't match your scenario.

    • As the linked bug report states, both the path and the specific file name of the malware DLLs can vary, so searching by path / name won't work.

    • To further narrow down matches, so you'll have two tweak the command to also look for the following, per this comment:

    combination of these four pieces of information (Timestamp, CheckSum=0, ImageSize, File version)

    • I assume that Timestamp corresponds to the .LastWriteTime property of the System.IO.FileInfo instances that Get-ChildItem emits.

    • I'm unclear on how to obtain CheckSum in PowerShell (in the bug report it was obtained with WinDbg).

    • On a general note, if you're targeting C:\ProgramData directly such as in combination with -Recurse), you must also use -Force, because PowerShell will otherwise not find the directory, because it is hidden.


    [1] Conceivably, there is a way through impersonation or ad-hoc modification of the privileges of the user token associated with the current process, but I am not sure.