I need to use win32 NetLocalGroupGetMembers in C#. I found and tested three solutions. All three fail with an FatalExecutionEngineError. The framework is .net 4.0
Here is a full example:
Reference to the api:
static class NetworkAPI
{
[DllImport("Netapi32.dll")]
public extern static int NetLocalGroupGetMembers([MarshalAs(UnmanagedType.LPWStr)] string servername, [MarshalAs(UnmanagedType.LPWStr)] string localgroupname, int level, out IntPtr bufptr, int prefmaxlen, out int entriesread, out int totalentries, out int resumehandle);
[DllImport("Netapi32.dll")]
public extern static int NetApiBufferFree(IntPtr Buffer);
// LOCALGROUP_MEMBERS_INFO_1 - Structure for holding members details
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_MEMBERS_INFO_1
{
public int lgrmi1_sid;
public int lgrmi1_sidusage;
public string lgrmi1_name;
}
}
calling the function:
static void Main(string[] args)
{
int EntriesRead;
int TotalEntries;
int Resume;
IntPtr bufPtr;
string groupName = "Administrators";
NetworkAPI.NetLocalGroupGetMembers(null, groupName, 1, out bufPtr, -1, out EntriesRead, out TotalEntries, out Resume);
if (EntriesRead > 0)
{
NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[] Members = new NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[EntriesRead];
IntPtr iter = bufPtr;
// EntriesRead has the correct quantity of members of the group, so the group is found
for (int i = 0; i < EntriesRead; i++)
{
// --------------------------------------------------
// ==> here the FatalExecutionEngineError happens:
Members[i] = (NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));
//
// --------------------------------------------------
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)));
Console.WriteLine(Members[i].lgrmi1_name);
}
NetworkAPI.NetApiBufferFree(bufPtr);
}
}
I see the following errors:
The resume handle is a pointer. Use ref IntPtr resumehandle for that parameter, and pass IntPtr.Zero on the first call. Or if you don't need to use a resume handle declare the parameter as IntPtr resumehandle and pass IntPtr.Zero. Consult the function documentation on MSDN for the full details.
The lgrmi1_sid member of the struct is a pointer. Declare it as such: public IntPtr lgrmi1_sid.
Casting an IntPtr to an int will lead to pointer truncation on 64 bit. Either use arithmetic directly on the IntPtr, or for older C# versions cast to long. The former is better, like so: iter += Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));.
You do not check the return value for errors.
Fix those errors and your program will run correctly.
For the sake of completeness, here is the code how to pinvoke
NetLocalGroupGetMembers.
I corrected the code as David suggested. There is also a suggestion from Martin Liversage which I didn't implement. But it maybe usefull.
If you like it, please do not upvode this answer but upvote Davids answer, who found the errors.
Reference to the api:
public static class NetworkAPI
{
[DllImport("Netapi32.dll")]
public extern static uint NetLocalGroupGetMembers([MarshalAs(UnmanagedType.LPWStr)] string servername, [MarshalAs(UnmanagedType.LPWStr)] string localgroupname, int level, out IntPtr bufptr, int prefmaxlen, out int entriesread, out int totalentries, out IntPtr resumehandle);
[DllImport("Netapi32.dll")]
public extern static int NetApiBufferFree(IntPtr Buffer);
// LOCALGROUP_MEMBERS_INFO_1 - Structure for holding members details
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_MEMBERS_INFO_1
{
public IntPtr lgrmi1_sid;
public int lgrmi1_sidusage;
public string lgrmi1_name;
}
// documented in MSDN
public const uint ERROR_ACCESS_DENIED = 0x0000005;
public const uint ERROR_MORE_DATA = 0x00000EA;
public const uint ERROR_NO_SUCH_ALIAS = 0x0000560;
public const uint NERR_InvalidComputer = 0x000092F;
// found by testing
public const uint NERR_GroupNotFound = 0x00008AC;
public const uint SERVER_UNAVAILABLE = 0x0006BA;
}
Calling the function:
static void Main(string[] args)
{
int EntriesRead;
int TotalEntries;
IntPtr Resume;
IntPtr bufPtr;
string groupName = "Administratoren";
string computerName = null; // null for the local machine
uint retVal = NetworkAPI.NetLocalGroupGetMembers(computerName, groupName, 1, out bufPtr, -1, out EntriesRead, out TotalEntries, out Resume);
if(retVal != 0)
{
if (retVal == NetworkAPI.ERROR_ACCESS_DENIED) { Console.WriteLine("Access denied"); return; }
if (retVal == NetworkAPI.ERROR_MORE_DATA) { Console.WriteLine("ERROR_MORE_DATA"); return; }
if (retVal == NetworkAPI.ERROR_NO_SUCH_ALIAS) { Console.WriteLine("Group not found"); return; }
if (retVal == NetworkAPI.NERR_InvalidComputer) { Console.WriteLine("Invalid computer name"); return; }
if (retVal == NetworkAPI.NERR_GroupNotFound) { Console.WriteLine("Group not found"); return; }
if (retVal == NetworkAPI.SERVER_UNAVAILABLE) { Console.WriteLine("Server unavailable"); return; }
Console.WriteLine("Unexpected NET_API_STATUS: " + retVal.ToString());
return;
}
if (EntriesRead > 0)
{
NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[] Members = new NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[EntriesRead];
IntPtr iter = bufPtr;
for (int i = 0; i < EntriesRead; i++)
{
Members[i] = (NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));
//x64 safe
iter += Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));
Console.WriteLine(Members[i].lgrmi1_name);
}
NetworkAPI.NetApiBufferFree(bufPtr);
}
}
Related
I am trying to directly access video memory for a framebuffer video device on a Raspberry Pi using C# code running via Mono. I have a C program that works fine, but when I port it to C# it consistently fails on the "map to memory" step.
The working C program (courtesy of tasanakorn) looks like this:
#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <bcm_host.h>
int process() {
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T display_info;
DISPMANX_RESOURCE_HANDLE_T screen_resource;
VC_IMAGE_TRANSFORM_T transform;
uint32_t image_prt;
VC_RECT_T rect1;
int ret;
int fbfd = 0;
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
bcm_host_init();
display = vc_dispmanx_display_open(0);
if (!display) {
syslog(LOG_ERR, "Unable to open primary display");
return -1;
}
ret = vc_dispmanx_display_get_info(display, &display_info);
if (ret) {
syslog(LOG_ERR, "Unable to get primary display information");
return -1;
}
syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height);
fbfd = open("/dev/fb1", O_RDWR);
if (fbfd == -1) {
syslog(LOG_ERR, "Unable to open secondary display");
return -1;
}
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
syslog(LOG_ERR, "Unable to get secondary display information");
return -1;
}
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
syslog(LOG_ERR, "Unable to get secondary display information");
return -1;
}
syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt);
if (!screen_resource) {
syslog(LOG_ERR, "Unable to create screen buffer");
close(fbfd);
vc_dispmanx_display_close(display);
return -1;
}
fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if (fbp <= 0) {
syslog(LOG_ERR, "Unable to create mamory mapping");
close(fbfd);
ret = vc_dispmanx_resource_delete(screen_resource);
vc_dispmanx_display_close(display);
return -1;
}
vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres);
while (1) {
ret = vc_dispmanx_snapshot(display, screen_resource, 0);
vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8);
usleep(25 * 1000);
}
munmap(fbp, finfo.smem_len);
close(fbfd);
ret = vc_dispmanx_resource_delete(screen_resource);
vc_dispmanx_display_close(display);
}
int main(int argc, char **argv) {
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("fbcp", LOG_NDELAY | LOG_PID, LOG_USER);
return process();
}
The C# code (in which I've tried to port all of the C code related to /dev/fb1) is:
using System;
using System.Runtime.InteropServices;
namespace MainProgram {
class MainClass {
static void Main(string[] args) {
int fbfd = -1; // file descriptor for framebuffer device
int fbp = -1; // pointer to mapped framebuffer memory
uint fbs = 0; // size of mapped framebuffer memory
int result = 0; // utility result variable
try {
// Initialize (not sure if this is needed, but...).
Libc.bcm_host_init();
// Open the device. (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
fbfd = Libc.open(args[0], Libc.O_RDWR);
if (fbfd < 0)
throw new Exception("open: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfd=" + fbfd);
// Get fixed screen info.
Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
if (result < 0)
throw new Exception("ioctl1: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);
// Get variable screen info.
Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
if (result < 0)
throw new Exception("ioctl2: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);
// Map framebuffer memory to virtual space.
fbs = fixInfo.smem_len;
Console.WriteLine("Confirm non-zero size: fbs=" + fbs);
fbp = Libc.mmap(0, fbs, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
if (fbp < 0)
throw new Exception("mmap: error " + Marshal.GetLastWin32Error());
Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
}
catch (Exception ex) {
Console.WriteLine("*** Error: " + ex.Message);
}
finally {
if (fbp >= 0)
result = Libc.munmap(fbp, fbs);
if (fbfd >= 0)
result = Libc.close(fbfd);
};
}
public static class Libc {
public const int O_RDWR = 0x0002;
public const int PROT_READ = 0x04;
public const int PROT_WRITE = 0x02;
public const int MAP_FILE = 0x0001;
public const int MAP_SHARED = 0x0010;
public const int FBIOGET_VSCREENINFO = 0x4600;
public const int FBIOGET_FSCREENINFO = 0x4602;
[DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
public static extern void bcm_host_init();
[DllImport("libc", EntryPoint="open", SetLastError = true)]
public static extern int open(
[MarshalAs(UnmanagedType.LPStr)] string filename,
[MarshalAs(UnmanagedType.I4)] int flags
);
[DllImport("libc", EntryPoint="close", SetLastError = true)]
public static extern int close(
[MarshalAs(UnmanagedType.I4)] int filedes
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl1(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_fix_screeninfo data
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl2(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_var_screeninfo data
);
[DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
public static extern int mmap(
[MarshalAs(UnmanagedType.U4)] uint addr,
[MarshalAs(UnmanagedType.U4)] uint length,
[MarshalAs(UnmanagedType.I4)] int prot,
[MarshalAs(UnmanagedType.I4)] int flags,
[MarshalAs(UnmanagedType.I4)] int fdes,
[MarshalAs(UnmanagedType.I4)] int offset
);
[DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
public static extern int munmap(
[MarshalAs(UnmanagedType.I4)] int addr,
[MarshalAs(UnmanagedType.U4)] uint length
);
[StructLayout(LayoutKind.Sequential)]
public struct fb_fix_screeninfo {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
[MarshalAs(UnmanagedType.U4)] public uint smem_start;
[MarshalAs(UnmanagedType.U4)] public uint smem_len;
[MarshalAs(UnmanagedType.U4)] public uint type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
};
[StructLayout(LayoutKind.Sequential)]
public struct fb_var_screeninfo {
[MarshalAs(UnmanagedType.U4)] public uint xres;
[MarshalAs(UnmanagedType.U4)] public uint yres;
[MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint xoffset;
[MarshalAs(UnmanagedType.U4)] public uint yoffset;
[MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
};
}
}
}
When I try to run the compiled code on the Pi, I get this following:
$ sudo mono ConsoleApp6.exe /dev/fb1
fbfd=4
fbfix: mem start=00000000, len=307200
fbvar: res=480x320, bpp=16
Confirm non-zero size: fbs=307200
*** Error: mmap: error 22
(I tried the same thing with the main monitor, also a framebuffer device, and got the following -- same error.)
$ sudo mono ConsoleApp6.exe /dev/fb0
fbfd=4
fbfix: mem start=1E876000, len=3686400
fbvar: res=1280x720, bpp=32
Confirm non-zero size: fbs=3686400
*** Error: mmap: error 22
Error 22 is EINVAL, which the mmap() documentation describes as, "We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary)." [It could also mean that: a) the length parameter is zero (which it isn't), or b) that both MAP_SHARED and MAP_PRIVATE are set (which they aren't)]. However, the values I'm passing in should be the same values used by the C code.
Does anyone have any idea what I'm doing wrong?
Solved. The problem is the constants PROT_READ, PROT_WRITE, MAP_SHARED, ... on the Raspberry Pi are not the same as the values I uncovered via Google searches (headslap). I found the correct values by looking at the .h files in /usr/include. Also, I discovered that a negative value for mmap is not necessarily an error; I needed to be looking specifically for MAP_FAILED (-1).
Here is the working code if anyone can use it:
using System;
using System.Runtime.InteropServices;
namespace MainProgram {
class MainClass {
static void Main(string[] args) {
int fbfd = -1; // file descriptor for framebuffer device
int fbp = -1; // pointer to mapped framebuffer memory
uint fbs = 0; // size of mapped framebuffer memory
int result = 0; // utility result variable
try {
// Initialize (not sure if this is needed, but...).
Libc.bcm_host_init();
// Open the device. (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
fbfd = Libc.open(args[0], Libc.O_RDWR);
if (fbfd == -1)
throw new Exception("open: result=" + fbfd + ", error=" + Marshal.GetLastWin32Error());
Console.WriteLine("fbfd=" + fbfd);
// Get fixed screen info.
Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
if (result == -1)
throw new Exception("ioctl1: result=" + result + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);
// Get variable screen info.
Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
if (result == -1)
throw new Exception("ioctl2: result=" + result + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);
// Map framebuffer memory to virtual space.
fbp = Libc.mmap(0, fixInfo.smem_len, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
if (fbp == Libc.MAP_FAILED)
throw new Exception("mmap: result=" + fbp + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
}
catch (Exception ex) {
Console.WriteLine("*** Error: " + ex.Message);
}
finally {
if (fbp != -1)
result = Libc.munmap(fbp, fbs);
if (fbfd != -1)
result = Libc.close(fbfd);
};
}
public static class Libc {
public const int O_RDWR = 0x0002;
public const int PROT_READ = 0x1;
public const int PROT_WRITE = 0x2;
public const int MAP_SHARED = 0x01;
public const int MAP_FAILED = -1;
public const int FBIOGET_VSCREENINFO = 0x4600;
public const int FBIOGET_FSCREENINFO = 0x4602;
[DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
public static extern void bcm_host_init();
[DllImport("libc", EntryPoint="open", SetLastError = true)]
public static extern int open(
[MarshalAs(UnmanagedType.LPStr)] string filename,
[MarshalAs(UnmanagedType.I4)] int flags
);
[DllImport("libc", EntryPoint="close", SetLastError = true)]
public static extern int close(
[MarshalAs(UnmanagedType.I4)] int filedes
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl1(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_fix_screeninfo data
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl2(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_var_screeninfo data
);
[DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
public static extern int mmap(
[MarshalAs(UnmanagedType.U4)] uint addr,
[MarshalAs(UnmanagedType.U4)] uint length,
[MarshalAs(UnmanagedType.I4)] int prot,
[MarshalAs(UnmanagedType.I4)] int flags,
[MarshalAs(UnmanagedType.I4)] int fdes,
[MarshalAs(UnmanagedType.I4)] int offset
);
[DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
public static extern int munmap(
[MarshalAs(UnmanagedType.I4)] int addr,
[MarshalAs(UnmanagedType.U4)] uint length
);
[StructLayout(LayoutKind.Sequential)]
public struct fb_fix_screeninfo {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
[MarshalAs(UnmanagedType.U4)] public uint smem_start;
[MarshalAs(UnmanagedType.U4)] public uint smem_len;
[MarshalAs(UnmanagedType.U4)] public uint type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
};
[StructLayout(LayoutKind.Sequential)]
public struct fb_var_screeninfo {
[MarshalAs(UnmanagedType.U4)] public uint xres;
[MarshalAs(UnmanagedType.U4)] public uint yres;
[MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint xoffset;
[MarshalAs(UnmanagedType.U4)] public uint yoffset;
[MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
};
}
}
}
I need to read out the IMEI of an IOS device using C#...
Is this even possible in C#/Xamarin?
Or is there another value that i can use to identify a device?
Some device identifiers are now impossible to be obtained from public APIs of iOS:
IMSI - International Mobile Subscriber Identity (SIM card number)
IMEI - International Mobile Equipment Identity (Device ID)
UDID - Unique Device Identifier for Apple iDevices
MAC address - Media Access Control Address (Network address)
Take a look here:
http://studyswift.blogspot.gr/2015/12/asidentifiermanager-get-idfv-vendor.html
If you could use any of the provided IDs the code is in Swift but if you use C# / Xamarin it won't be difficult to convert.
Hope this helps
I've also tried to find a way to capture the IMEI, but I believe this is not possible. The only way I solved it was to use this code, it returns serial number
public class IosDevice
{
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IOServiceMatching(string s);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IORegistryEntryCreateCFProperty(uint entry, IntPtr key, IntPtr allocator, uint options);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOObjectRelease(uint o);
public string GetIdentifier()
{
string serial = string.Empty;
uint platformExpert = IOServiceGetMatchingService(0, IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert != 0)
{
NSString key = (NSString)"IOPlatformSerialNumber";
IntPtr serialNumber = IORegistryEntryCreateCFProperty(platformExpert, key.Handle, IntPtr.Zero, 0);
if (serialNumber != IntPtr.Zero)
{
serial = NSString.FromHandle(serialNumber);
}
IOObjectRelease(platformExpert);
}
return serial;
}
}
In case someone wants to get vid, pid of an USB Device in MacOS
public class OsxDeviceDiscovery
{
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOServiceGetMatchingService(int masterPort, IntPtr matching);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOServiceGetMatchingServices(int masterPort, IntPtr matching, out IntPtr iterator);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IOServiceMatching(string name);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern IntPtr IORegistryEntryCreateCFProperty(int entry, IntPtr key, IntPtr allocator, uint options);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOObjectRelease(int o);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IOIteratorNext(IntPtr iterator);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern bool CFNumberGetValue(IntPtr number,long type, ref long value);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int CFNumberGetType(IntPtr number);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern bool CFStringGetCString(IntPtr stringRef, byte[] str, int size, int encoding);
[DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
private static extern int IORegisterEntryCreateIterator(IntPtr entry, IntPtr plane, int options, out IntPtr iterator);
public static string GetIdentifier()
{
string deviceName = string.Empty;
IntPtr matchingNodes;
int platformExpert = IOServiceGetMatchingServices(0, IOServiceMatching("IOUSBDevice"), out matchingNodes);
int node = -1;
while ((node = IOIteratorNext(matchingNodes)) != 0)
{
long vendorID = 0;
long productID = 0;
long locationId = 0;
NSString key = (NSString)"idVendor";
IntPtr proRef = IORegistryEntryCreateCFProperty(node, key.Handle, IntPtr.Zero, 0);
if (proRef != IntPtr.Zero)
{
long type = CFNumberGetType(proRef);
CFNumberGetValue(proRef, type, ref vendorID);
}
key = (NSString)"idProduct";
proRef = IORegistryEntryCreateCFProperty(node, key.Handle, IntPtr.Zero, 0);
if (proRef != IntPtr.Zero)
{
long type = CFNumberGetType(proRef);
CFNumberGetValue(proRef, type, ref productID);
}
if (vendorID != 0x1234 || productID != 0x5678)
{
IOObjectRelease(node);
continue;
}
key = (NSString)"locationID";
proRef = IORegistryEntryCreateCFProperty(node, key.Handle, IntPtr.Zero, 0);
if (proRef != IntPtr.Zero)
{
long type = CFNumberGetType(proRef);
CFNumberGetValue(proRef, type, ref locationId);
}
key = (NSString)"kUSBSerialNumberString";
proRef = IORegistryEntryCreateCFProperty(node, key.Handle, IntPtr.Zero, 0);
if (proRef != IntPtr.Zero)
{
byte[] byteArray = new byte[20];
CFStringGetCString(proRef, byteArray, 20, 0x0600);
string serialNumber = System.Text.Encoding.UTF8.GetString(byteArray);
deviceName = "/dev/cu.usbmodem" + serialNumber;
}
IOObjectRelease(node);
}
return deviceName;
}
}
I'd like to list out all CSP and CNG providers installed on a system, but I can't find a good method for doing so in C#. For CSP, I can enumerate a certain registry key (inelegant, but functional), but I've been unable to find any way to get a list of CNG providers.
Is there anything remotely like System.Security.Cryptography.Get[CSP/CNG]Providers() or similarly logical/straightforward in .NET that could be used? Thanks!
To my knowledge, there isn't anything like that in .NET Framework.
For CSP providers, enumerate the subkeys of:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider
For CNG providers, enumerate the subkeys of:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Cryptography\Providers
Use this to enumerate CSP providers and containers:
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace CspSample
{
struct Provider
{
public string Name { get; set; }
public int Type { get; set; }
}
class CspUtils
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CryptEnumProviderTypes(
uint dwIndex,
uint pdwReserved,
uint dwFlags,
[In] ref uint pdwProvType,
StringBuilder pszTypeName,
[In] ref uint pcbTypeName);
[DllImport("Advapi32.dll")]
private static extern bool CryptEnumProviders(
int dwIndex,
IntPtr pdwReserved,
int dwFlags,
ref int pdwProvType,
StringBuilder pszProvName,
ref int pcbProvName);
public static List<Provider> ListAllProviders()
{
List<Provider> installedCSPs = new List<Provider>();
int cbName;
int dwType;
int dwIndex;
StringBuilder pszName;
dwIndex = 0;
dwType = 1;
cbName = 0;
while (CryptEnumProviders(dwIndex, IntPtr.Zero, 0, ref dwType, null, ref cbName))
{
pszName = new StringBuilder(cbName);
if (CryptEnumProviders(dwIndex++, IntPtr.Zero, 0, ref dwType, pszName, ref cbName))
{
installedCSPs.Add(new Provider { Name = pszName.ToString(), Type = dwType });
}
}
return installedCSPs;
}
const int PP_ENUMCONTAINERS = 2;
const int PROV_RSA_FULL = 1;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int CRYPT_FIRST = 1;
const int CRYPT_NEXT = 2;
//TODO: Find how to disable this flag (not machine keystore)
const int CRYPT_MACHINE_KEYSET = 0x20;
const int CRYPT_VERIFYCONTEXT = unchecked((int)0xF0000000);
public static IList<string> EnumerateKeyContainers(string providerName, int providerType)
{
ProvHandle prov;
if (!CryptAcquireContext(out prov, null, providerName, providerType, CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT))
throw new Win32Exception(Marshal.GetLastWin32Error());
List<string> list = new List<string>();
IntPtr data = IntPtr.Zero;
try
{
int flag = CRYPT_FIRST;
int len = 0;
if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, IntPtr.Zero, ref len, flag))
{
if (Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
data = Marshal.AllocHGlobal(len);
do
{
if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, data, ref len, flag))
{
if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
break;
//throw new Win32Exception(Marshal.GetLastWin32Error());
}
list.Add(Marshal.PtrToStringAnsi(data));
flag = CRYPT_NEXT;
}
while (true);
}
finally
{
if (data != IntPtr.Zero)
{
Marshal.FreeHGlobal(data);
}
prov.Dispose();
}
return list;
}
private sealed class ProvHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public ProvHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return CryptReleaseContext(handle, 0);
}
[DllImport("advapi32.dll")]
private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CryptAcquireContext(out ProvHandle phProv, string pszContainer, string pszProvider, int dwProvType, int dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CryptGetProvParam(ProvHandle hProv, int dwParam, IntPtr pbData, ref int pdwDataLen, int dwFlags);
}
}
Short question
How can I get information about multiple code signing certificates from an executable (.EXE/.DLL)?
Expected answer
The final accepted answer should propose a way to get all certificates in C#. Concept / pseudo code is ok, I don't expect you to write the full source.
For an intermediate answer suggesting a tool, please see my question on Security.StackExchange.
Long question
I am researching whether we could use multiple code signing certificates on a plugin (.DLL) to check whether it has been officially tested or not. This is the procedure:
the plugin DLL is signed by the vendor just like any other application
the plugin DLL comes into a test lab and undergoes a set of tests
the plugin DLL gets signed again by the test lab so that the application using the DLL can find out whether it is using a tested plugin or not
It seems possible to sign a DLL a second time using
signtool /v /f <pfx> /as <dll>
Indications that this may have worked:
the file increases in size
the tool prints a success message
However, there are some issues showing the second signature:
although Windows Explorer says "Signature list", it shows only one certificate
the C# X509Certificate.CreateFromSignedFile() method can only return one certificate
At the moment I'm actually trying my code on an EXE file rather than a DLL file, but that shouldn't matter. The EXE is already signed with a trusted root certificate and a timestamp. The second signature is created with my own certificate following these steps currently without a timestamp.
Things I did before asking the question:
search on Stackoverflow for existing answers
search for tools on Google
The only related question I found so far is How does one correctly dual-sign with a timestamp but it doesn't have an answer.
I have recently implemented code to do this myself. I can't post the full solution as it is embedded in a larger static analysis tool, but the code for a working bare-bones C# console application that enumerates the Authenticode signatures in a specified file path is provided below using the WinVerifyTrust() Windows API function with assistance from this Knowledge Base article.
Things to note:
Enumerating more than one certificate is only supported on Windows 8 and Windows Server 2012 (or later). Earlier versions of Windows will only ever report there being zero or one certificates.
The code as provided here only handles validly signed files and files with no Authenticode signature. It does not properly handle files with invalid signatures. This is left as an excercise for the reader.
Here's the code:
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace ReadAuthenticodeSignatures
{
internal static class Program
{
internal static void Main(string[] args)
{
string fileName = args[0];
IntPtr hWind = IntPtr.Zero;
Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
byte[] actionIdBytes = WINTRUST_ACTION_GENERIC_VERIFY_V2.ToByteArray();
IntPtr pcwszFilePath = Marshal.StringToHGlobalAuto(fileName);
try
{
WINTRUST_FILE_INFO File = new WINTRUST_FILE_INFO()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)),
pcwszFilePath = pcwszFilePath,
hFile = IntPtr.Zero,
pgKnownSubject = IntPtr.Zero,
};
IntPtr ptrFile = Marshal.AllocHGlobal(File.cbStruct);
try
{
Marshal.StructureToPtr(File, ptrFile, false);
WINTRUST_DATA WVTData = new WINTRUST_DATA()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_DATA)),
pPolicyCallbackData = IntPtr.Zero,
pSIPClientData = IntPtr.Zero,
dwUIChoice = WTD_UI_NONE,
fdwRevocationChecks = WTD_REVOKE_NONE,
dwUnionChoice = WTD_CHOICE_FILE,
pFile = ptrFile,
dwStateAction = WTD_STATEACTION_IGNORE,
hWVTStateData = IntPtr.Zero,
pwszURLReference = IntPtr.Zero,
dwProvFlags = WTD_REVOCATION_CHECK_NONE,
dwUIContext = WTD_UICONTEXT_EXECUTE,
pSignatureSettings = IntPtr.Zero,
};
// N.B. Use of this member is only supported on Windows 8 and Windows Server 2012 (and later)
WINTRUST_SIGNATURE_SETTINGS signatureSettings = default(WINTRUST_SIGNATURE_SETTINGS);
bool canUseSignatureSettings = Environment.OSVersion.Version > new Version(6, 2, 0, 0);
IntPtr pSignatureSettings = IntPtr.Zero;
if (canUseSignatureSettings)
{
// Setup WINTRUST_SIGNATURE_SETTINGS to get the number of signatures in the file
signatureSettings = new WINTRUST_SIGNATURE_SETTINGS()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_SIGNATURE_SETTINGS)),
dwIndex = 0,
dwFlags = WSS_GET_SECONDARY_SIG_COUNT,
cSecondarySigs = 0,
dwVerifiedSigIndex = 0,
pCryptoPolicy = IntPtr.Zero,
};
pSignatureSettings = Marshal.AllocHGlobal(signatureSettings.cbStruct);
}
try
{
if (pSignatureSettings != IntPtr.Zero)
{
Marshal.StructureToPtr(signatureSettings, pSignatureSettings, false);
WVTData.pSignatureSettings = pSignatureSettings;
}
IntPtr pgActionID = Marshal.AllocHGlobal(actionIdBytes.Length);
try
{
Marshal.Copy(actionIdBytes, 0, pgActionID, actionIdBytes.Length);
IntPtr pWVTData = Marshal.AllocHGlobal(WVTData.cbStruct);
try
{
Marshal.StructureToPtr(WVTData, pWVTData, false);
int hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);
if (hRESULT == 0)
{
if (pSignatureSettings != IntPtr.Zero)
{
// Read back the signature settings
signatureSettings = (WINTRUST_SIGNATURE_SETTINGS)Marshal.PtrToStructure(pSignatureSettings, typeof(WINTRUST_SIGNATURE_SETTINGS));
}
int signatureCount = signatureSettings.cSecondarySigs + 1;
Console.WriteLine("File: {0}", fileName);
Console.WriteLine("Authenticode signatures: {0}", signatureCount);
Console.WriteLine();
for (int dwIndex = 0; dwIndex < signatureCount; dwIndex++)
{
if (pSignatureSettings != IntPtr.Zero)
{
signatureSettings.dwIndex = dwIndex;
signatureSettings.dwFlags = WSS_VERIFY_SPECIFIC;
Marshal.StructureToPtr(signatureSettings, pSignatureSettings, false);
}
WVTData.dwStateAction = WTD_STATEACTION_VERIFY;
WVTData.hWVTStateData = IntPtr.Zero;
Marshal.StructureToPtr(WVTData, pWVTData, false);
hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);
try
{
if (hRESULT == 0)
{
WVTData = (WINTRUST_DATA)Marshal.PtrToStructure(pWVTData, typeof(WINTRUST_DATA));
IntPtr ptrProvData = WTHelperProvDataFromStateData(WVTData.hWVTStateData);
CRYPT_PROVIDER_DATA provData = (CRYPT_PROVIDER_DATA)Marshal.PtrToStructure(ptrProvData, typeof(CRYPT_PROVIDER_DATA));
for (int idxSigner = 0; idxSigner < provData.csSigners; idxSigner++)
{
IntPtr ptrProvSigner = WTHelperGetProvSignerFromChain(ptrProvData, idxSigner, false, 0);
CRYPT_PROVIDER_SGNR ProvSigner = (CRYPT_PROVIDER_SGNR)Marshal.PtrToStructure(ptrProvSigner, typeof(CRYPT_PROVIDER_SGNR));
CMSG_SIGNER_INFO Signer = (CMSG_SIGNER_INFO)Marshal.PtrToStructure(ProvSigner.psSigner, typeof(CMSG_SIGNER_INFO));
if (Signer.HashAlgorithm.pszObjId != IntPtr.Zero)
{
string objId = Marshal.PtrToStringAnsi(Signer.HashAlgorithm.pszObjId);
if (objId != null)
{
Oid hashOid = Oid.FromOidValue(objId, OidGroup.All);
if (hashOid != null)
{
Console.WriteLine("Hash algorithm of signature {0}: {1}.", dwIndex + 1, hashOid.FriendlyName);
}
}
}
IntPtr ptrCert = WTHelperGetProvCertFromChain(ptrProvSigner, idxSigner);
CRYPT_PROVIDER_CERT cert = (CRYPT_PROVIDER_CERT)Marshal.PtrToStructure(ptrCert, typeof(CRYPT_PROVIDER_CERT));
if (cert.cbStruct > 0)
{
X509Certificate2 certificate = new X509Certificate2(cert.pCert);
Console.WriteLine("Certificate thumbprint of signature {0}: {1}", dwIndex + 1, certificate.Thumbprint);
}
if (ProvSigner.sftVerifyAsOf.dwHighDateTime != provData.sftSystemTime.dwHighDateTime &&
ProvSigner.sftVerifyAsOf.dwLowDateTime != provData.sftSystemTime.dwLowDateTime)
{
DateTime timestamp = DateTime.FromFileTimeUtc(((long)ProvSigner.sftVerifyAsOf.dwHighDateTime << 32) | (uint)ProvSigner.sftVerifyAsOf.dwLowDateTime);
Console.WriteLine("Timestamp of signature {0}: {1}", dwIndex + 1, timestamp);
}
}
}
}
finally
{
WVTData.dwStateAction = WTD_STATEACTION_CLOSE;
Marshal.StructureToPtr(WVTData, pWVTData, false);
hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);
}
Console.WriteLine();
}
}
else if ((uint)hRESULT == 0x800b0100)
{
Console.WriteLine("{0} has no Authenticode signatures.", fileName);
}
}
finally
{
Marshal.FreeHGlobal(pWVTData);
}
}
finally
{
Marshal.FreeHGlobal(pgActionID);
}
}
finally
{
if (pSignatureSettings != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSignatureSettings);
}
}
}
finally
{
Marshal.FreeHGlobal(ptrFile);
}
}
finally
{
Marshal.FreeHGlobal(pcwszFilePath);
}
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
private const int SGNR_TYPE_TIMESTAMP = 0x00000010;
private const int WTD_UI_NONE = 2;
private const int WTD_CHOICE_FILE = 1;
private const int WTD_REVOKE_NONE = 0;
private const int WTD_REVOKE_WHOLECHAIN = 1;
private const int WTD_STATEACTION_IGNORE = 0;
private const int WTD_STATEACTION_VERIFY = 1;
private const int WTD_STATEACTION_CLOSE = 2;
private const int WTD_REVOCATION_CHECK_NONE = 16;
private const int WTD_REVOCATION_CHECK_CHAIN = 64;
private const int WTD_UICONTEXT_EXECUTE = 0;
private const int WSS_VERIFY_SPECIFIC = 0x00000001;
private const int WSS_GET_SECONDARY_SIG_COUNT = 0x00000002;
[DllImport("wintrust.dll")]
private static extern int WinVerifyTrust(IntPtr hWind, IntPtr pgActionID, IntPtr pWVTData);
[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperProvDataFromStateData(IntPtr hStateData);
[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperGetProvSignerFromChain(IntPtr pProvData, int idxSigner, bool fCounterSigner, int idxCounterSigner);
[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperGetProvCertFromChain(IntPtr pSgnr, int idxCert);
[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_DATA
{
internal int cbStruct;
internal IntPtr pPolicyCallbackData;
internal IntPtr pSIPClientData;
internal int dwUIChoice;
internal int fdwRevocationChecks;
internal int dwUnionChoice;
internal IntPtr pFile;
internal int dwStateAction;
internal IntPtr hWVTStateData;
internal IntPtr pwszURLReference;
internal int dwProvFlags;
internal int dwUIContext;
internal IntPtr pSignatureSettings;
}
[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_SIGNATURE_SETTINGS
{
internal int cbStruct;
internal int dwIndex;
internal int dwFlags;
internal int cSecondarySigs;
internal int dwVerifiedSigIndex;
internal IntPtr pCryptoPolicy;
}
[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_FILE_INFO
{
internal int cbStruct;
internal IntPtr pcwszFilePath;
internal IntPtr hFile;
internal IntPtr pgKnownSubject;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_DATA
{
internal int cbStruct;
internal IntPtr pWintrustData;
internal bool fOpenedFile;
internal IntPtr hWndParent;
internal IntPtr pgActionID;
internal IntPtr hProv;
internal int dwError;
internal int dwRegSecuritySettings;
internal int dwRegPolicySettings;
internal IntPtr psPfns;
internal int cdwTrustStepErrors;
internal IntPtr padwTrustStepErrors;
internal int chStores;
internal IntPtr pahStores;
internal int dwEncoding;
internal IntPtr hMsg;
internal int csSigners;
internal IntPtr pasSigners;
internal int csProvPrivData;
internal IntPtr pasProvPrivData;
internal int dwSubjectChoice;
internal IntPtr pPDSip;
internal IntPtr pszUsageOID;
internal bool fRecallWithState;
internal System.Runtime.InteropServices.ComTypes.FILETIME sftSystemTime;
internal IntPtr pszCTLSignerUsageOID;
internal int dwProvFlags;
internal int dwFinalError;
internal IntPtr pRequestUsage;
internal int dwTrustPubSettings;
internal int dwUIStateFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_SGNR
{
internal int cbStruct;
internal System.Runtime.InteropServices.ComTypes.FILETIME sftVerifyAsOf;
internal int csCertChain;
internal IntPtr pasCertChain;
internal int dwSignerType;
internal IntPtr psSigner;
internal int dwError;
internal int csCounterSigners;
internal IntPtr pasCounterSigners;
internal IntPtr pChainContext;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_CERT
{
internal int cbStruct;
internal IntPtr pCert;
internal bool fCommercial;
internal bool fTrustedRoot;
internal bool fSelfSigned;
internal bool fTestCert;
internal int dwRevokedReason;
internal int dwConfidence;
internal int dwError;
internal IntPtr pTrustListContext;
internal bool fTrustListSignerCert;
internal IntPtr pCtlContext;
internal int dwCtlError;
internal bool fIsCyclic;
internal IntPtr pChainElement;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_ALGORITHM_IDENTIFIER
{
internal IntPtr pszObjId;
internal CRYPT_INTEGER_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential)]
private struct CMSG_SIGNER_INFO
{
internal int dwVersion;
internal CRYPT_INTEGER_BLOB Issuer;
internal CRYPT_INTEGER_BLOB SerialNumber;
internal CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
internal CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
internal CRYPT_INTEGER_BLOB EncryptedHash;
internal CRYPT_ATTRIBUTES AuthAttrs;
internal CRYPT_ATTRIBUTES UnauthAttrs;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_INTEGER_BLOB
{
internal int cbData;
internal IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_ATTRIBUTES
{
internal int cAttr;
internal IntPtr rgAttr;
}
}
}
Running the application against the SQL Server 2014 SP1 installer gives the following output on Windows 8.1:
File: SQLServer2014SP1-KB3058865-x64-ENU.exe
Authenticode signatures: 2
Hash algorithm of signature 1: sha1.
Certificate thumbprint of signature 1: 67B1757863E3EFF760EA9EBB02849AF07D3A8080
Timestamp of signature 1: 22/04/2015 06:03:40
Hash algorithm of signature 2: sha256.
Certificate thumbprint of signature 2: 76DAF3E30F95B244CA4D6107E0243BB97F7DF965
Timestamp of signature 2: 22/04/2015 06:03:51
Press enter to exit.
Give Mono a try. It's able to pull all of the file's Authenticode certificates in one line!
using Mono.Security.Authenticode;
AuthenticodeDeformatter monoFileCert = new AuthenticodeDeformatter("System.Windows.dll");
Console.WriteLine($"Found certificates {monoFileCert.Certificates.Count}");
https://github.com/mono/mono/blob/master/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeDeformatter.cs
Usage example:
https://github.com/mono/mono/blob/master/mcs/tools/security/chktrust.cs
I'm trying to translate this c++/cli code to c#
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
using namespace System;
using namespace System::Runtime::InteropServices;
struct CREDENTIAL
{
DWORD Flags;
DWORD Type;
LPSTR TargetName;
LPSTR Comment;
Runtime::InteropServices::ComTypes::FILETIME LastWritten;
DWORD CredentialBlobSize;
LPBYTE CredentialBlob;
DWORD Persist;
DWORD AttributeCount;
LPBYTE Attributes;
LPSTR TargetAlias;
LPWSTR UserName;
};
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet::Unicode)]
extern BOOL CredEnumerate(LPCTSTR Filter, DWORD Flags, DWORD* count, CREDENTIAL*** Credentials);
[DllImport("advapi32.dll")]
extern VOID CredFree(LPVOID);
int main( array<System::String^>^argv )
{
String^ credentialList = "";
Int32 count = 0;
CREDENTIAL** credentialCollection = 0;
if( CredEnumerate( _T("WindowsLive:name=*"), 0, (DWORD*)&count, &credentialCollection) )
{
for( Int32 n = 0; n < count; n++ )
{
credentialList += "\n";
credentialList += "Username " + gcnew System::String( credentialCollection[n]->UserName ) + "\n";
credentialList += "Password: " + gcnew System::String( (LPWSTR)credentialCollection[n]->CredentialBlob ) + "\n";
}
CredFree( &credentialCollection );
Console::WriteLine(credentialList);
}
Console::ReadLine();
}
Here's my c# code .. (I am not sure how CredEnumerate does work)
using System;
using System.Runtime.InteropServices; // DLL support
using System.Collections.Generic;
public struct CREDENTIAL
{
public UInt32 flags;
public UInt32 type;
public string targetName;
public string comment;
public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten;
public UInt32 credentialBlobSize;
public IntPtr credentialBlob;
public UInt32 persist;
public UInt32 attributeCount;
public IntPtr credAttribute;
public string targetAlias;
public string userName;
}
class Test
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CredEnumerate(string filter, int flag, out int count, out IntPtr
pCredentials);
static void Main()
{
try
{
int count = 0;
IntPtr pCredentials = IntPtr.Zero;
IntPtr[] credentials = null;
bool ret = CredEnumerate("WindowsLive:name=*", 0, out count, out pCredentials);
if (ret != false)
{
credentials = new IntPtr[count];
IntPtr p = pCredentials;
for (int n = 0; n < count; n++)
{
if (Marshal.SizeOf(p) == 4) //32 bit CLR?
p = new IntPtr(p.ToInt32() + n);
else
p = new IntPtr(p.ToInt64() + n);
credentials[n] = Marshal.ReadIntPtr(p);
}
List<CREDENTIAL> creds = new List<CREDENTIAL>(credentials.Length);
foreach (var ptr in credentials)
{
creds.Add((CREDENTIAL)Marshal.PtrToStructure(ptr, typeof(CREDENTIAL)));
}
}
}
catch (Exception x)
{
Console.WriteLine(x.ToString());
}
Console.ReadLine();
}
}
I hope someone can help me
It's pretty scary code, I have my doubts about the CLI/C++ being right. You should look up the definitions of your structure e.g.
http://msdn.microsoft.com/en-us/library/aa374788(VS.85).aspx
Then clean-up the code properly before posting.
I would be tempted to use the code from this article on credential management
Still, that involves keeping the CLI/C++ which you seem to want to get rid of so I gave fixing it a go.
Now this works on my machine, that I've hacked it together... (note: I've removed your filter so I could test it)
[StructLayout(LayoutKind.Sequential)]
internal struct CREDENTIAL {
public int Flags;
public int Type;
[MarshalAs(UnmanagedType.LPWStr)]
public string TargetName;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
public long LastWritten;
public int CredentialBlobSize;
public IntPtr CredentialBlob;
public int Persist;
public int AttributeCount;
public IntPtr Attributes;
[MarshalAs(UnmanagedType.LPWStr)]
public string TargetAlias;
[MarshalAs(UnmanagedType.LPWStr)]
public string UserName;
}
Then the reading
try
{
uint count;
IntPtr pCredentials = IntPtr.Zero;
IntPtr[] credentials;
bool ret = CredEnumerateW("*", 0, out count, out pCredentials);
if (ret)
{
credentials = new IntPtr[count];
List<CREDENTIAL> creds = new List<CREDENTIAL>(credentials.Length);
for(int i = 0; i < count; i++) {
IntPtr structs= Marshal.ReadIntPtr(pCredentials, IntPtr.Size * i);
CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(structs, typeof(CREDENTIAL));
creds.Add(c);
}
}
}
catch (Exception x)
{
Console.WriteLine(x.ToString());
}
and
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CredEnumerateW(string filter, uint flag, out uint count, out IntPtr pCredentials);
It doesn't free the structure etc.
have a look at pinvoke.net it may have an example of how to call CredEnumerate