secana / PeNet

Portable Executable (PE) library written in .Net
Apache License 2.0
593 stars 113 forks source link

signed files reporting as unsigned #83

Closed dgrif closed 5 years ago

dgrif commented 5 years ago

It appears that signed file checks may have an issue, have only tested with a few known signed x64 binaries, no other info at the moment.


> PeNet.Utilities.SignatureInformation.IsSigned("C:\Windows\System32\kernel32.dll");; 
val it : bool = false 
> PeNet.Utilities.SignatureInformation.IsSigned("C:\Users\me\Downloads\SysinternalsSuite\ADExplorer.exe");; 
val it : bool = false 
> PeNet.Utilities.SignatureInformation.IsSigned("C:\Windows\explorer.exe");;                               
val it : bool = false```
secana commented 5 years ago

Hi @dgrif,

that is some strange behavior. I ran the unit test and added your test cases and all of them work as expected. I know from past issues that there is a difference between .NET Framework, Core and Windows/Linux in the signature check. See https://github.com/dotnet/corefx/issues/34202

Can you provide more information about your setup?

dgrif commented 5 years ago

My dev environments have been a mess, I've been working in VS Code on Win/Mac/Linux and VS on Windows. I noticed it in VS 2015 on my Win10 box.

To replicate it in a more isolated way, I snagged one of the Edge Win10 dev VMs from MS and installed VS 2015 Community. I then created a F# Library project, installed PeNet latest with NuGet and in the fsx I put this test code which evaluates false:

#r "../packages/PeNet.1.0.7/lib/net461/PeNet.dll"
open PeNet

PeNet.Utilities.SignatureInformation.IsSigned("C:\\Windows\\System32\\Kernel32.dll")
val it : bool = false
dgrif commented 5 years ago

Another test I get the expected result of True @secana

Same Edge VM setup as described above, this time I created a console application project, compiled and debugged and using the following code, this time getting results as expected.

open PeNet

let APeFile (aFile:string)= 
    let ape = PeNet.PeFile(aFile)
    ape

[<EntryPoint>]
let main argv = 
    printfn "%A" argv
    let ape = APeFile "C:\\Windows\\System32\\Kernel32.dll"
    if ape.IsSigned then
        printfn "The file was signed."
    else
        printfn "The file is NOT signed."
    0 // return an integer exit code

I was debugging/testing my functions in scripts via fsi before putting them into my library, so the issue likely lies with that workflow.

secana commented 5 years ago

@dgrif do you use .NET Core or the old Framework to run the fsx scripts?

SteveGilham commented 5 years ago

Following your tweet, I've tried this on my Windows 10 Home dev box and running

open System
Environment.CommandLine;;
#r "[path to]/packages/PeNet.1.0.8/lib/net461/PeNet.dll"
open PeNet

PeNet.Utilities.SignatureInformation.IsSigned("C:\\Windows\\System32\\Kernel32.dll");;

let ape = PeFile "C:\\Windows\\System32\\Kernel32.dll"   
ape.IsSigned;;

with both commands fsi and dotnet fsi

val it : string =
""C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\FSharp\fsi.exe""
val it : bool = false
[file dump omitted]
val it : bool = false

and

val it : string =
  ""C:\Program Files\dotnet\sdk\3.0.100-preview5-011568\FSharp\fsi.exe""
val it : bool = false
[file dump omitted]
val it : bool = false

i.e. both routes to the answer on either interactive platform go adrift.

With essentially the same code

open System
open PeNet

[<EntryPoint>]
let main argv =
    printfn "%A" Environment.CommandLine
    printfn "%A" <| PeNet.Utilities.SignatureInformation.IsSigned("C:\\Windows\\System32\\Kernel32.dll")
    let ape = PeFile "C:\\Windows\\System32\\Kernel32.dll"
    printfn "%A" ape.IsSigned
    0 // return an integer exit code

as a .net core 2.1 executable

"C:\Users\steve\source\repos\ClassLibrary1\ConsoleApp4\bin\Debug\netcoreapp2.1\ConsoleApp4.dll"
true
true

and as a framework 4.7.2 executable

""C:\Users\steve\source\repos\ClassLibrary1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe" "
true
true

So it looks like something in the interactive environment is invalidating an assumption at some point.


> ape.PKCS7;;
val it : Security.Cryptography.X509Certificates.X509Certificate2 = null
> ape.Authenticode;;
val it : Authenticode.AuthenticodeInfo = null

Logging from here might shed some light on the mystery.


Hypothesis- the script needs another #r or two to pull in the dependencies in other nuget packages used for authenticode processing.

SteveGilham commented 5 years ago

Hypothesis confirmed.

PS: C:\Users\steve
07/22/2019 08:00:10>fsi
Microsoft (R) F# Interactive version 10.2.3 for F# 4.5
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> #r "C:/Users/steve/source/repos/ClassLibrary1/packages/PeNet.Asn1.1.3.3/lib/net461/PeNet.Asn1.dll";;

--> Referenced 'C:/Users/steve/source/repos/ClassLibrary1/packages/PeNet.Asn1.1.3.3/lib/net461/PeNet.Asn1.dll' (file may be locked by F# Interactive process)

> #r "C:/Users/steve/source/repos/ClassLibrary1/packages/Newtonsoft.Json.12.0.1/lib/net45/NewtonSoft.Json.dll";;

--> Referenced 'C:/Users/steve/source/repos/ClassLibrary1/packages/Newtonsoft.Json.12.0.1/lib/net45/NewtonSoft.Json.dll' (file may be locked by F# Interactive process)

> #r "C:/Users/steve/source/repos/ClassLibrary1/packages/PeNet.1.0.8/lib/net461/PeNet.dll";;

--> Referenced 'C:/Users/steve/source/repos/ClassLibrary1/packages/PeNet.1.0.8/lib/net461/PeNet.dll' (file may be locked by F# Interactive process)

> open PeNet;;
> PeNet.Utilities.SignatureInformation.IsSigned("C:\\Windows\\System32\\Kernel32.dll");;
Binding session to 'C:/Users/steve/source/repos/ClassLibrary1/packages/PeNet.Asn1.1.3.3/lib/net461/PeNet.Asn1.dll'...
val it : bool = true

So while the original report is actually one of an insufficient script, the swallowing of all potentially diagnostic error information in the Authenticode handler obscured the problem.

secana commented 5 years ago

@SteveGilham thx alot for helping. So an F# interactive user needs to reference the assembly manually which are referenced by PeNet itself. @dgrif this should solve your problem.

F# community is great!

SteveGilham commented 5 years ago

That's a general .net thing; because the assemblies are not co-located (being in various places under the packages folder) as they would be with a deployed executable, their locations have to be specified manually.

dgrif commented 5 years ago

Hi all, sorry for the delayed reply but this definitely sorted me out. I really appreciate the clarification, thanks!