GetFileVersionInfo() returns wrong file's version information - winapi

I have an application that is required to check the versions of various system EXEs and DLLs to determine if they are vulnerable or not. This is a native C++ application which does not provide any specific WinSxS linkages in its manifest. On Windows 7, when I invoke GetFileVersionInfo on an absolute path, for example "c:\windows\system32\taskeng.exe", I receive the version information for "C:\Windows\winsxs\x86_microsoft-windows-taskscheduler-engine_31bf3856ad364e35_6.1.7600.16385_none_e582a352202e02c8\taskeng.exe"
So, to clarify, the version c:\windows\system32\taskeng.exe reported by Windows Explorer is 6.1.7600.16699.
The version of c:\windows\system32\taskeng.exe reported by GetFileVersionInfo() is 6.1.7600.16385.
How do I force my app to not have its file redirected via WinSxS?

Here's a PowerShell script to show the difference. FileVersion is a string that is different than the composition of [FileMajorPart].[FileMinorPart].[FileBuildPart].[FilePrivatePart].
PS C:\> [System.Diagnostics.FileVersionInfo]::GetVersionInfo("c:\windows\system32\taskeng.exe") | Format-List -property *
Comments :
CompanyName : Microsoft Corporation
FileBuildPart : 7601
FileDescription : Task Scheduler Engine
FileMajorPart : 6
FileMinorPart : 1
FileName : c:\windows\system32\taskeng.exe
FilePrivatePart : 17514
FileVersion : 6.1.7600.16385 (win7_rtm.090713-1255)
InternalName : TaskEng
IsDebug : False
IsPatched : False
IsPrivateBuild : False
IsPreRelease : False
IsSpecialBuild : False
Language : English (United States)
LegalCopyright : © Microsoft Corporation. All rights reserved.
LegalTrademarks :
OriginalFilename : taskeng.exe.mui
PrivateBuild :
ProductBuildPart : 7601
ProductMajorPart : 6
ProductMinorPart : 1
ProductName : Microsoft® Windows® Operating System
ProductPrivatePart : 17514
ProductVersion : 6.1.7600.16385
SpecialBuild :

Are you sure you are looking at the correct fields? GetFileVersionInfo() gives me the same thing as Explorer with one caveat: the FileVersion in the StringFileInfo is 6.1.7600.16385 whereas the FileVersion in the VS_FIXEDFILEINFO is 6.1.7600.16699. Explorer is showing the FileVersion from the VS_FIXEDFILEINFO. I guess Microsoft just didn't update the StringFileInfo for some reason.

Related

Get-Help shows `-AllUser` parameter for Remove-AppxPackage, so why won't the cmdlet won't accept it?

I need a way to reliably remove all Appx Package from a system that start with a given string. On most systems the following works:
Get-AppxPackage -all MyApp* | Remove-AppxPackage -AllUsers
However for two systems I get the following:
PS C:\Users\Administrator> Get-AppxPackage -all CDI* | Remove-AppxPackage -AllUsers
Remove-AppxPackage : A parameter cannot be found that matches parameter name 'AllUsers'.
At line:1 char:48
+ Get-AppxPackage -all CDI* | Remove-AppxPackage -AllUsers
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-AppxPackage], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.Windows.Appx.PackageManager.Commands.RemoveAppxPackageCommand
This basically says AllUSers is invalid, but this contradicts the Get-Help output:
Get-Help Remove-AppxPackage -Parameter AllUsers
-AllUsers [<SwitchParameter>]
{{Fill AllUsers Description}}
Required? false
Position? named
Default value False
Accept pipeline input? False
Accept wildcard characters? false
Is there a Path issue or another way to remove the Appx package for everyone?
Update #1: Version info
Here is the version info for the command:
PS C:\Users\Administrator> Get-Command Remove-AppxPackage
CommandType Name Version Source
----------- ---- ------- ------
Function Remove-AppxPackage 1.0 Appx
And the OS
> [System.Environment]::OSVersion.Version
Major Minor Build Revision
----- ----- ----- --------
10 0 14393 0
Update #2
Module version output
PS > Get-Module -ListAvailable Appx
Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 2.0.0.0 Appx {Add-AppxPackage, Get-AppxPackage, Get-AppxPackageManifest...
Is there any way to produce the same effect as the AllUsers Switch when i don't have it (even though the documentation says i should)
Remove-AppxPackage has an -AllUsers switch only in recent versions of Windows (both desktop and server editions).
On the linked page, browsing the version-specific doc pages (via the dropdown list of versions above the list of topics on the left) shows that Windows Server 2016 PowerShell and Windows 10 and Windows Sever 2019 PowerShell are the earliest versions that document -AllUsers.
As you've stated later, you're using Windows Server 2016, and the version number indicates a recent release, so -AllUsers should work. For instance, on my recent Windows 10 release (release ID 21H2, build 19044; Windows 10 has the same foundation as Windows Server 2016), -AllUsers is present. A notable difference is that the AppX module version is 2.0.1.0 on my machine, compared to 1.0 on yours, which may explain the difference:
Your error message indeed implies that the cmdlet itself lacks an -AllUsers parameter - despite what the Get-Help cmdlet may report (the information isn't guaranteed to be in sync).
If you want to know whether a given command truly supports a given parameter, use Get-Command -Syntax, which directly consults the command's definition; in this case: (Get-Command -Syntax Remove-AppxPackage) -match '-AllUsers'
A simpler alternative is to try to tab-complete the parameter name: if nothing happens, the parameter doesn't exist.
Potential solutions:
Use Get-Module -ListAvailable AppX to see if you accidentally have multiple versions of the AppX module installed (with an obsolete one shadowing the platform-appropriate one), and if so, remove all but the most recent one (highest version number).
Otherwise, you can try to manually copy the module from a recent Windows 10 / Windows Server 2019 or a Windows Server 2022 machine - but you'll have to see if that actually works.
Unfortunately, the Appx module is not available in the PowerShell Gallery, so you cannot simply install the latest version with Install-Module.
The need for doing this would imply that the docs for Windows Server 2016 are incorrect.
The cmdlet, like many others also, would require you to elevate the PowerShell to have admin permissions if you want to affect other users.

How to get .NET 5 symbols to show up in the call stack in Process Hacker or Process Explorer?

I created a simple console application in both .NET Framework 4.8 and .NET 5 (same code in both), but symbols resolve differently across various debugging tools.
If I run both applications, launch Process Hacker, open the process's properties, click on the Threads tab, and open the Stack for the primary managed thread, the .NET 4.8 Stack shows resolved symbols for my classes and methods, but the .NET 5 Stack does not -- it shows hex strings like 0x7ffbac6087a3.
In both cases, calls to System.Console.dll!System.Console.ReadKey() resolve correctly, so I know I have my symbol loading configured correctly (_NT_SYMBOL_PATH = "srv*C:\Source\symbols*https://msdl.microsoft.com/download/symbols"). In both cases, the projects are configured for full debug type and to include debug symbols. In both cases, there is a .pdb to go along with the .exe.
Sysinternals Process Explorer won't display any of that - the bottom of the call stack is 0x0.
If I take a dump of the applications, I can load them into WinDbg Preview and am able to see all of my code as expected. For the .NET 5 application, the normal Stack shows the same thing as Process Hacker (e.g. 0x7ffbac6087a3), but if I run the command !CLRStack -a, those hex values get properly resolved (e.g. 000000BD4F17E840 00007ffbac6087a3 SymbolsCoreConsoleApp.Program.Run() [C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\Program.cs # 18]).
So, there's the background. Here are the questions:
1.) Why doesn't the Process Hacker Stack resolve symbols for my classes in a .NET 5 application, but it does for the exact same code in a .NET Framework 4.8 application?
2.) Why doesn't Sysinternals Process Explorer display any of my code (just 0x0) for either application? In case it matters, I run procexp64.exe and my machine is x64 Windows 10 Enterprise. If I run 'procexp.exe`, it ultimately launches the x64 version anyhow. Mentioning this in case there is an issue with 32 vs. 64 bit.
3.) Both Process Hacker and Process Explorer have process tabs specifically for .NET (e.g. .NET assemblies and .NET performance), and those tabs only show up for the .NET Framework 4.8 application, but not for the .NET 5 application. Is this by-design or do I have something configured wrong?
4.) In WinDbg Preview, is this behavior by-design? If so, why?
5.) Are there other special things to consider when debugging/analyzing .NET 5/Core applications outside of Visual Studio?
That's a lot of questions, but they're all closely related, and I suspect there may be some fundamental thing(s) that I'm missing here.
Thanks in advance!
EDIT: 20210803 10:55 AM CDT
Per magicandre1981's comment, I installed the nightly of Process Hacker (v3.0.4234).
It still doesn't resolve those symbols.
It does show .NET assemblies and .NET performance tabs for the .NET 5 application now, but there are no values on the .NET performance tab.
EDIT: 20210803 05:05 PM CDT
I ran symchk and dumpbin against both of the applications in case this will help anyone diagnose the problem.
.NET 5
net5.0> $> pwd
C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0
net5.0> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsCoreConsoleApp.exe /r
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1
net5.0> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsCoreConsoleApp.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsCoreConsoleApp.exe
File Type: EXECUTABLE IMAGE
PDB file 'C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0\apphost.pdb' checked. (File not found)
PDB file 'D:\workspace\_work\1\s\artifacts\obj\win-x64.Release\corehost\cli\apphost\standalone\Release\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\symbols\exe\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\exe\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\apphost.pdb' checked. (File not found)
Summary
2000 .data
2000 .pdata
9000 .rdata
1000 .reloc
1000 .rsrc
14000 .text
1000 _RDATA
net5.0> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsCoreConsoleApp.dll /r
SYMCHK: SymbolsCoreConsoleApp.dll FAILED - SymbolsCoreConsoleApp.pdb mismatched or not found
SYMCHK: SymbolsCoreConsoleApp.dll FAILED - No CodeView information found.
SYMCHK: FAILED files = 2
SYMCHK: PASSED + IGNORED files = 0
net5.0> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsCoreConsoleApp.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsCoreConsoleApp.dll
File Type: EXECUTABLE IMAGE
PDB file found at 'C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0\SymbolsCoreConsoleApp.pdb'
Summary
2000 .reloc
2000 .rsrc
2000 .text
.NET 4.8
Debug> $> pwd
C:\Source\research\SymbolsFramework\SymbolsFrameworkConsoleApp\bin\Debug
Debug> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsFrameworkConsoleApp.exe /r
SYMCHK: SymbolsFrameworkConsoleApp.exe FAILED - SymbolsFrameworkConsoleApp.pdb mismatched or not found
SYMCHK: FAILED files = 1
SYMCHK: PASSED + IGNORED files = 0
Debug> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsFrameworkConsoleApp.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsFrameworkConsoleApp.exe
File Type: EXECUTABLE IMAGE
PDB file found at 'C:\Source\research\SymbolsFramework\SymbolsFrameworkConsoleApp\bin\Debug\SymbolsFrameworkConsoleApp.pdb'
Summary
2000 .reloc
2000 .rsrc
2000 .text
EDIT: 20210803 07:54 PM CDT
Per hanpassant's comment, here is the project file (it already had the DebugType set to full).
SymbolsCoreConsoleApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
</Project>
EDIT: 20210803 08:40 PM CDT
Here are a few screenshots in case it wasn't clear from my explanation.
Notice the 0x7xfbb03a8 addresses instead of resolved symbols.
Notice the resolved symbols for SymbolsFramework.ConsoleApp.Program instead of the unresolved 0x7xfbb03a8 addresses.
Notice the 0x0 address instead of any resolved symbols.
The .NET Assemblies tab shows up for .NET 5 and appears to populate correctly.
The .NET Performance tab shows up for .NET 5, but it has no values.
I opened an issue with Process Hacker on GitHub and it was closed a few days back with a fix in the nightly build. I confirmed that it now works as expected.

Sysprep failure on windows.miracastview

When trying to sysprep and windows 10 (1709) build I get the following error:
Package Windows.MiracastView_6.3.0.0_neutral_cw5n1h2txyewy was installed for a
user but not provisioned for all users. This package will not function
properly in the sysprep image.
I tried using powershell to remove it but the error message says it is part of windows and cannot be removed.
I checked the user accounts and I only have one user account (other accounts are built-in windows accounts).
How can I get sysprep to work?
After further investigation I found that miracast view is the only app where Get-AppxPackage -allusers has the pending status:
Name : Windows.MiracastView
Publisher : CN=Microsoft Windows, O=Microsoft Corporation,
L=Redmond, S=Washington, C=US
Architecture : Neutral
ResourceId : neutral
Version : 6.3.0.0
PackageFullName :Windows.MiracastView_6.3.0.0_neutral_neutral_cw5n1h2txyewy
InstallLocation :
IsFramework : False
PackageFamilyName : Windows.MiracastView_cw5n1h2txyewy
PublisherId : cw5n1h2txyewy
PackageUserInformation : {S-1-5-21-4120236872-3763413694-1479318824-1000
[Operator]: Installed(pending removal)}
IsResourcePackage : False
IsBundle : False
IsDevelopmentMode : False
IsPartiallyStaged : False
SignatureKind : System
Status : Ok
Okay, here is what I found and it was probably due to a lack of understanding how imaging works that caused the issue in the first place although it was only after the 1709 october release did we see the issue.
So we have VMs where we create the images. When we did the 1709 update we had left the reference image on network which downloaded some additional updates for some windows store apps.
Each time we sysprep'd we kept getting failures. Removing the apps with powershell only highlighted other apps that needed to be removed. These were staged app entries and can be found as:
Get-AppXPackage -AllUser | % {if ($_.PackageUserInformation.InstallState -eq "Staged"){$_.PackageFullname}}
So, I left the reference image on the network and waited until all the staged entries disappeared (this took about 30 minutes). Rerunning the script above will not show any staged apps.
Once this was done, sysprep worked.
I think in the past, staged apps did not cause sysprep to fail but now it does.
Note that you'll see a wsappx process that runs which updates all the staged apps (view in Task manager).

Why/how are Registry Entries Hidden in Regedit but visible in PowerShell?

I'm working with a new property schema, and have been in the habit of checking the registry when I register or unregister a new version. One of the primary places to check this is HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\PROPERTYSYSTEM\PROPERTYSCHEMA.
Interestingly, I occasionally lose access to this registry location in Regedit. I see see this (note the absence of PropertySchema):
I know the schemas are still registered, because I can use the prop.exe tool and propschema SDK sample application to describe them. The properties are available in Windows Explorer and in Search.
Also, I can use PowerShell to list the contents of this hive:
C:\Users\carlton> cd hklm:
HKLM:\>
C:\Users\carlton> cd hklm:
HKLM:\> cd SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\PROPERTYSYSTEM\PROPERTYSCHEMA
HKLM:\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\PROPERTYSYSTEM\PROPERTYSCHEMA> dir
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\PROPERTYSYSTEM\PROPERTYSCHEMA
Name Property
---- --------
0000 (default) : C:\Program Files\Internet Explorer\ie9props.propdesc
SchemaId : {D9B5ABA1-5E8A-4902-B6A1-50B3C0311C2E}
URI : ie9props.propdesc
CompactURI : 5376bae4b39f43768806afcb6b8ff5464bf9c989d1a819c6e6d99ba1e8ce2512
0001 (default) : C:\Program Files\Microsoft Office\Office14\Custom.propdesc
SchemaId : {537AAAB1-1D85-48DC-A99E-16EB8C309FE5}
URI : custom.propdesc
CompactURI : 2e3be58e5cbbc0da093956b46a3905f11cf0f5bbf11987a8619e25f7261ee8be
0002 (default) : C:\apps\MSOffice\Office14\VisioCustom.propdesc
SchemaId : {18503526-0466-4942-AC6E-41C1D380EABA}
URI : visiocustom.propdesc
...
Anyway, I don't understand how this happens, and whether I should be worried about it. Exporting this key from a colleague's machine and re-importing it can temporarily help, as it will show keys in Regedit that were hidden/missing (even if they weren't on my colleague's machine).
I'm in the Administrators group, running Windows 7 SP1.
The 32bit program data on 64bit systems available in 'Wow6432Node' folder of the registry (in above case 'SOFTWARE\Wow6432Node\MICROSOFT\WINDOWS...'). This is transparent to the applications, hence you can read data from applications but you don't see that in Regedit.
Harry Johnston's intuition was correct. I re-ran regedit from a command line with the path c:\windows\regedit, and I once again see what I expected under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertySchema. I could've sworn it wasn't showing it either, but it's working now, apparently.
I confirmed as much by exporting the parent key (PropertySystem) from the 64-bit and 32-bit regedit's and running Beyond Compare. The propdesc files are verily not there in the 32-bit version.
See 32-bit and 64-bit Application Data in the Registry (MSDN)

Interpreting the CorFlags flags

How do I interpret the CorFlags flags and how should I use it to determine if a .NET assembly was built for x86 or x64?
Could it be the following?
corflags MyAssembly.dll
Microsoft .NET 4.5 introduced a new option, Any CPU 32-bit Preferred. In the new version of CorFlags.exe, the 32BIT flag no longer exists, instead, two new flags were added, 32BITREQ and 32BITPREF.
Somewhere based on the below explanation, we can interpret new CorFlags as follows.
CPU Architecture PE 32BITREQ 32BITPREF
------------------------ ----- -------- ---------
x86 (32-bit) PE32 1 0
x64 (64-bit) PE32+ 0 0
Any CPU PE32 0 0
Any CPU 32-Bit Preferred PE32 0 1
Flags displayed by the CorFlags.exe located at C:\Program Files
(x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools
Version : Assembly's target framework.
Header : 2.0/2.5 (Must have version of 2.5 or greater to run natively)
PE : PE32 (32-bit)/PE32+ (64-bit)
CorFlags : Hexadecimal value, computed based on below 4 flags.
ILONLY : 1 if MSIL otherwise 0
32BITREQ : 1 if 32-bit x86 only assembly otherwise 0
32BITPREF : 1 if 32-bit x86 only preferred in Any CPU architecture otherwise 0
Signed : 1 if signed with strong name otherwise 0
The following example illustrates the output of C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\CorFlags.exe for different assemblies.
PresentationCore.dll from GAC_32
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_32\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 0xb
ILONLY : 1
32BITREQ : 1
32BITPREF : 0
Signed : 1
System.Data.dll from GAC_64
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x18
ILONLY : 0
32BITREQ : 0
32BITPREF : 0
Signed : 1
System.dll from GAC_MSIL
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1
To know more about Any CPU 32-bit Preferred assemblies refer
What AnyCPU Really Means As Of .NET 4.5 and Visual Studio 11
Open the Visual Studio Command Prompt (in Windows: menu Start → Programs → Microsoft Visual Studio → Visual Studio Tools → Visual Studio 2010 Command Prompt)
CD to the directory containing the DLL in question.
Run corflags like this:
corflags MyAssembly.dll
The output looks like this:
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 1
ILONLY : 1
32BIT : 0
Signed : 0
The flags' interpretation:
Any CPU: PE = PE32 and 32BIT = 0
x86: PE = PE32 and 32BIT = 1
64-bit: PE = PE32+ and 32BIT = 0
To add more detail to the other answers, the actual important value is the hexadecimal CorFlags value since it carries the most information. Here's the list of bits that comprise it:
[Flags]
public enum CorFlags
{
ILOnly = 0x00000001,
Requires32Bit = 0x00000002,
ILLibrary = 0x00000004,
StrongNameSigned = 0x00000008,
NativeEntryPoint = 0x00000010,
TrackDebugData = 0x00010000,
Prefers32Bit = 0x00020000,
}
Corflags outputs the four bits of this value separately (ILONLY, 32BITREQ, 32BITPREF and Signed). However the full CorFlags value also contains information about whether the assembly is strong-name signed or delay signed (0x8 bit) as well as ILLibrary, NativeEntryPoint and TrackDebugData bits (I don't know what those mean).
Note that CorFlags output Signed is not exactly the StrongNameSigned bit. It will print Signed 1 if the assembly is either delay-signed or fully signed, whereas StrongNameSigned bit is set if the assembly is fully signed only.
You can also use this table:
CPU | PE | 32BIT
----------|-------|------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0

Resources