Get PE build version from resource directory in UEFI bootloader - winapi

I'm trying to get the build number from a 64-bit PE file (from the resource directory), namely the Windows bootmanager (bootmgfw.efi), using an UEFI bootloader. Currently I'm doing the following: Load the PE file from disk using BootServices->LoadImage and get the image base address using BootServices->OpenProtocol. Then I'm using the base address for the function below (HbeGetBuildNumber). Note that this exact function works flawless on bootmgfw.efi if I load the file using MapViewOfFile from a Windows executable, but not when using it inside my bootloader.
Code to obtain the build number by image base address:
#define IMAGE_DOS_SIGNATURE 0x5A4D
#define IMAGE_NT_SIGNATURE 0x00004550
#define TRUE 1
#define FALSE 0
#define NULL 0
#define FIELD_OFFSET(type, field) ((long)(long long)&(((type *)0)->field))
#define MAKEINTRESOURCE(i) ((PWSTR)((DWORD_PTR)((WORD)(i))))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define RT_VERSION MAKEINTRESOURCE(16)
#define DUMMYSTRUCTNAME
#define DUMMYUNIONNAME
#define DUMMYSTRUCTNAME2
#define DUMMYUNIONNAME2
typedef int BOOL, * PBOOL;
typedef unsigned short WCHAR_T, *PWSTR;
typedef unsigned long DWORD, *PDWORD;
typedef unsigned long long DWORD_PTR, * PDWORD_PTR;
typedef unsigned char BYTE, * PBYTE;
typedef BYTE UCHAR, * PUCHAR;
typedef void* PVOID;
typedef unsigned short WORD, *PWORD;
typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
DWORD BeginAddress;
DWORD EndAddress;
union {
DWORD UnwindInfoAddress;
DWORD UnwindData;
} DUMMYUNIONNAME;
} RUNTIME_FUNCTION, * PRUNTIME_FUNCTION, _IMAGE_RUNTIME_FUNCTION_ENTRY, * _PIMAGE_RUNTIME_FUNCTION_ENTRY;
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[8];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
unsigned long long ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
unsigned long long SizeOfStackReserve;
unsigned long long SizeOfStackCommit;
unsigned long long SizeOfHeapReserve;
unsigned long long SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, * PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
long e_lfanew;
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER;
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
} IMAGE_RESOURCE_DIRECTORY, * PIMAGE_RESOURCE_DIRECTORY;
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
union {
struct {
DWORD NameOffset : 31;
DWORD NameIsString : 1;
} DUMMYSTRUCTNAME;
DWORD Name;
WORD Id;
} DUMMYUNIONNAME;
union {
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory : 31;
DWORD DataIsDirectory : 1;
} DUMMYSTRUCTNAME2;
} DUMMYUNIONNAME2;
} IMAGE_RESOURCE_DIRECTORY_ENTRY, * PIMAGE_RESOURCE_DIRECTORY_ENTRY;
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData;
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, * PIMAGE_RESOURCE_DATA_ENTRY;
typedef struct tagVS_FIXEDFILEINFO
{
DWORD dwSignature;
DWORD dwStrucVersion;
DWORD dwFileVersionMS;
DWORD dwFileVersionLS;
DWORD dwProductVersionMS;
DWORD dwProductVersionLS;
DWORD dwFileFlagsMask;
DWORD dwFileFlags;
DWORD dwFileOS;
DWORD dwFileType;
DWORD dwFileSubtype;
DWORD dwFileDateMS;
DWORD dwFileDateLS;
} VS_FIXEDFILEINFO;
typedef struct tag_VS_VERSIONINFO
{
unsigned short wLength;
unsigned short wValueLength;
unsigned short wType;
WCHAR_T szKey[17];
VS_FIXEDFILEINFO Value;
}VS_VERSIONINFO, * PVS_VERSIONINFO;
PVOID HbGetPtr2(DWORD_PTR relativeAddress, PIMAGE_NT_HEADERS64 ntHeaders, DWORD_PTR imageBase)
{
PVOID retVal = NULL;
BOOL found = FALSE;
PIMAGE_SECTION_HEADER secHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)ntHeaders + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader) + ntHeaders->FileHeader.SizeOfOptionalHeader);
for (DWORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++, secHeader++)
{
if ((relativeAddress >= secHeader->VirtualAddress)
&& (relativeAddress < (secHeader->VirtualAddress + secHeader->Misc.VirtualSize)))
{
found = TRUE;
break;
}
}
if (found)
retVal = (PVOID)(imageBase + relativeAddress - (int)(secHeader->VirtualAddress - secHeader->PointerToRawData));
return retVal;
}
//Get build number for PE file
unsigned long HbeGetBuildNumber(void* imageBase)
{
DWORD retVal = 0;
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)imageBase);
PIMAGE_NT_HEADERS64 ntHeaders = (PIMAGE_NT_HEADERS64)((DWORD_PTR)imageBase + dosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY dataDir = NULL;
PIMAGE_RESOURCE_DIRECTORY resDir = NULL, subDir = NULL;
PIMAGE_RESOURCE_DIRECTORY_ENTRY dirEntry = NULL, versionDir = NULL;
PIMAGE_RESOURCE_DATA_ENTRY dataEntry = NULL;
PVS_VERSIONINFO versionInfo;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
goto Done;
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
goto Done;
dataDir = &ntHeaders->OptionalHeader.DataDirectory[2];
resDir = (PIMAGE_RESOURCE_DIRECTORY)HbGetPtr2(dataDir->VirtualAddress, ntHeaders, (DWORD_PTR)imageBase);
dirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
if (!resDir)
goto Done;
for (DWORD i = 0; i < resDir->NumberOfIdEntries; i++, dirEntry++)
{
if (dirEntry->Id == (WORD)RT_VERSION
&& dirEntry->DataIsDirectory)
{
subDir = (PIMAGE_RESOURCE_DIRECTORY)((dirEntry->OffsetToData & 0x7FFFFFFF) + (DWORD_PTR)resDir);
versionDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(subDir + 1);
if (versionDir->DataIsDirectory)
{
subDir = (PIMAGE_RESOURCE_DIRECTORY)((versionDir->OffsetToData & 0x7FFFFFFF) + (DWORD_PTR)resDir);
versionDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(subDir + 1);
dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((versionDir->OffsetToData & 0x7FFFFFFF) + (DWORD_PTR)resDir);
versionInfo = (PVS_VERSIONINFO)HbGetPtr2(dataEntry->OffsetToData, ntHeaders, (DWORD_PTR)imageBase);
if (versionDir)
retVal = HIWORD(versionInfo->Value.dwFileVersionLS);
}
}
}
Done:
return retVal;
}
Through debugging I figured out that the error occurs when trying to locate PIMAGE_RESOURCE_DIRECTORY using HbGetPtr2, since resDir->NumberOfIDEntries should have the value 4, but in the error case it contains multiple thousand (obviously wrong). Where is my error in this code? Why does the code work on the same file if I run it from a Windows exe but not from my bootloader? Is there a difference between BootServices->LoadImage (Bootloader) and MapViewOfFile (Windows executable)?
Edit:
This is how I use the code above in my Windows executable (working):
HANDLE hFile;
HANDLE hFileMapping;
LPVOID lpFileBase;
hFile = CreateFileW(L"C:\\Users\\XY\Reverse Engineering\\EFI\\bootmgfw.efi", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
return 1;
hFileMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == 0)
{
CloseHandle(hFile);
return 1;
}
lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
if (lpFileBase == 0)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
return 1;
}
std::cout << HbeGetBuildNumber(lpFileBase) << std::endl;
This is how I use the code above in my bootloader (fails):
BOOL retVal = FALSE;
PEFI_BOOT_SERVICES services = systemTable->BootServices;
PEFI_LOADED_IMAGE loadedImage;
PEFI_LOADED_IMAGE_PROTOCOL winImageInfo;
PEFI_DEVICE_PATH winPath;
EFI_HANDLE winHandle = NULL;
EFI_STATUS loadSuccess = -1;
DWORD bootmgfwBuildNumber = 0;
if (EFI_ERROR(services->HandleProtocol(curImageHandle, &gEfiLoadedImageProtocolGuid, &loadedImage)))
goto Done;
if (!(winPath = FileDevicePath(loadedImage->DeviceHandle, L"EFI\\Microsoft\\Boot\\bootmgfw.efi")))
goto Done;
if (EFI_ERROR(loadSuccess = services->LoadImage(TRUE, curImageHandle, winPath, NULL, 0, &winHandle)))
goto Done;
DBGMSG(L"Loaded bootmgfw.efi\n");
FreePool(winPath);
if (EFI_ERROR(services->OpenProtocol(winHandle, &gEfiLoadedImageProtocolGuid, (PVOID *)&winImageInfo, curImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)))
goto Done;
DBGMSG(L"Got file information\n");
if (!(bootmgfwBuildNumber = HbGetBuildNumber(winImageInfo->ImageBase))) //ERROR: Returns 0
goto Done
//...
Done:
DBGMSG(L"Start image\n");
if (!EFI_ERROR(loadSuccess) && !EFI_ERROR(services->StartImage(winHandle, 0, NULL)))
retVal = TRUE;
return retVal;

Related

How to exactly modify the Local Descriptor table on 64 bits Windows?

The aim is to enable 16 bits segments for 16 bits addressing like on 64 bits Linux Kernel with the modify_ldt() system call.
I was unable to find if Cygwin provides a wrapper and I have only barely an idea that it’s about something like NtSetLdtEntries with :
typedef struct
{
ULONG Start;
ULONG Length;
LDT_ENTRY LdtEntries[1];
} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION;
Please note this is not related to the vm86 mode (which is a different method of doing it used by Microsoft on 32 bits systems). And As stated above, this way is used on Linux for running 16 bits code in protected mode without any emulation. See CONFIG_X86_16BIT for more informations.
Of course, if it’s not supported by default it’s Ok to modify system files.
on x86-based windos possible (tested on xp and win 8.1 x86) set several descriptors in LDT table and use this. this can be done via NtSetInformationProcess with ProcessLdtInformation (undocumented) or, if we need set only 1 or 2 selectors - more easy use undocumented api:
EXTERN_C
__declspec(dllimport)
NTSTATUS
NTAPI
NtSetLdtEntries
(
__in_opt ULONG Selector1,
__in SEGMENT_ENTRY LdtEntry1,
__in_opt ULONG Selector2,
__in SEGMENT_ENTRY LdtEntry2
);
so we need allocate 1 or more SEGMENT_ENTRY (or LDT_ENTRY - declared in winnt.h), allocate memory for segment, and call api. I did not pay much attention for 16 bit code and fill actual descriptors, check only memory fill via LDT selector (assigned to ES) and then read it via "plain" selector.
typedef struct SEGMENT_ENTRY
{
ULONG LimitLow : 16;
ULONG BaseLow : 16;
ULONG BaseMid : 8;
ULONG Type : 4;
ULONG IsGegment : 1;// = 1
ULONG DPL : 2;
ULONG P : 1;// Present
ULONG LimitHi : 4;
ULONG AVL : 1;// Available For software use
ULONG L : 1;// Long-mode segment
ULONG D : 1;// Default operand size
ULONG G : 1;// Granularity
ULONG BaseHi : 8;
}*PSEGMENT_ENTRY;
typedef struct PROCESS_LDT_INFORMATION
{
ULONG StartSelector;
ULONG Length;
SEGMENT_ENTRY LdtEntries[];
} *PPROCESS_LDT_INFORMATION;
EXTERN_C
__declspec(dllimport)
NTSTATUS
NTAPI
NtSetLdtEntries
(
__in_opt ULONG Selector1,
IN SEGMENT_ENTRY LdtEntry1,
__in_opt ULONG Selector2,
IN SEGMENT_ENTRY LdtEntry2
);
NTSTATUS TestLdt()
{
PVOID BaseAddress = 0;
SIZE_T RegionSize = 0x100000;//1mb
NTSTATUS status = NtAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (0 <= status)
{
#if 1
SEGMENT_ENTRY LdtEntry = {};
LdtEntry.LimitLow = 0xffff;
LdtEntry.BaseLow = ((ULONG_PTR)BaseAddress) & 0xFFFF;
LdtEntry.BaseMid = ((ULONG_PTR)BaseAddress >> 16) & 0xff;
LdtEntry.BaseHi = ((ULONG_PTR)BaseAddress >> 24) & 0xff;
LdtEntry.P = 1;
LdtEntry.DPL = 3;
LdtEntry.IsGegment = 1;
LdtEntry.Type = 2;//ldt
status = NtSetLdtEntries(8, LdtEntry, 0, LdtEntry);
#else
const ULONG cb = sizeof(PROCESS_LDT_INFORMATION) + 1 * sizeof(LDT_ENTRY);
PPROCESS_LDT_INFORMATION LdtInfo = (PPROCESS_LDT_INFORMATION)alloca(cb);
LdtInfo->Length = 1 * sizeof(LDT_ENTRY);
LdtInfo->StartSelector = 8;
SEGMENT_ENTRY* LdtEntry = LdtInfo->LdtEntries;
LdtEntry->LimitLow = 0xffff;
LdtEntry->BaseLow = ((ULONG_PTR)BaseAddress) & 0xFFFF;
LdtEntry->BaseMid = ((ULONG_PTR)BaseAddress >> 16) & 0xff;
LdtEntry->BaseHi = ((ULONG_PTR)BaseAddress >> 24) & 0xff;
LdtEntry->L = 0;
LdtEntry->D = 0;
LdtEntry->G = 0;
LdtEntry->AVL = 0;
LdtEntry->P = 1;
LdtEntry->DPL = 3;
LdtEntry->IsGegment = 1;
LdtEntry->Type = 2;//ldt
status = NtSetInformationProcess(NtCurrentProcess(), ProcessLdtInformation, LdtInfo, cb);
#endif
if (0 <= status)
{
DbgPrint("%s\n", BaseAddress); // print empty string
#ifdef _X86_
__asm {
push edi
mov ax,0xf
mov dx,es
mov es,ax
mov ecx,32
mov al,0x33
xor edi,edi
rep stosb
mov es,dx
pop edi
}
#endif
DbgPrint("%s\n", BaseAddress);// print 33333333...
}
NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE);
}
return status;
}
however This is valid only on x86-based windows systems.
if you call this on any x64 windows you got error STATUS_NOT_IMPLEMENTED. here windows not support LDT at all. and this can not be changed (even by modify system files. ?!)
more info - Local Descriptor Table on x64

get /dev/random in kernel module

I need to get both /dev/random and /dev/urandom within kernel module.
get_random_bytes API provided to get /dev/urandom.
But there is no API for /dev/random so I tried to ioctl and read file in kernel space.
Here is what I have done.
using RNDGETPOOL ioctl
in include/linux/random.h
RNDGETPOOL is declared
/* Get the contents of the entropy pool. (Superuser only.) */
#define RNDGETPOOL _IOR( 'R', 0x02, int [2] )
but, It won't work so I checked driver/char/random.h noticed RNDGETPOOL is gone!!
static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
int size, ent_count;
int __user *p = (int __user *)arg;
int retval;
switch (cmd) {
case RNDGETENTCNT:
/* inherently racy, no point locking */
if (put_user(input_pool.entropy_count, p))
return -EFAULT;
return 0;
case RNDADDTOENTCNT:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (get_user(ent_count, p))
return -EFAULT;
credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDADDENTROPY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (get_user(ent_count, p++))
return -EFAULT;
if (ent_count < 0)
return -EINVAL;
if (get_user(size, p++))
return -EFAULT;
retval = write_pool(&input_pool, (const char __user *)p,
size);
if (retval < 0)
return retval;
credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDZAPENTCNT:
case RNDCLEARPOOL:
/* Clear the entropy pool counters. */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
rand_initialize();
return 0;
default:
return -EINVAL;
}
}
I searched google and find out ioctl RNDGETPOOL is removed. done!
using random_read function from driver/char/random.c:997
static ssize_t random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
here is my kernel module's function accesses to /dev/random.
static void read_file()
{
struct file *file;
loff_t pos = 0;
//ssize_t wc;
unsigned char buf_ent[21]={0,};
int ent_c;
int i;
ssize_t length = 0;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
file = filp_open("/dev/random", O_WRONLY, 0);
file->f_op->unlocked_ioctl(file, RNDGETENTCNT, &ent_c);
if(ent_c < sizeof(char))
{
printk("not enough entropy\n");
}
printk("ent counter : %d\n", ent_c);
//file->f_op->unlocked_ioctl(file, RNDGETPOOL, &ent_st.buf);
length = file->f_op->read(file, buf_ent, ent_c/ 8, &pos);
if(length <0)
{
printk("failed to random_read\n");
}
printk("length : %d\n", length);
printk("ent: ");
for(i=0;i<length; i++)
{
printk("%02x", buf_ent[i]);
}
printk("\n");
filp_close(file,0);
set_fs(old_fs);
}
outputs seems to be random
first try
[1290902.992048] ent_c : 165
[1290902.992060] length : 20
[1290902.992060] ent: d89290f4a5eea8e087a63943ed0129041e80b568
second try
[1290911.493990] ent_c : 33
[1290911.493994] length : 4
[1290911.493994] ent: 7832640a
by the way random_read function argument has __user keyword. Buf buf in code is in kernel space.
Is appropriate using random_read function in kernel space??
The in-kernel interface to get random bytes is get_random_bytes():
static void read_file(void)
{
unsigned char buf_ent[21];
get_random_bytes(buf_ent, 21);
print_hex_dump_bytes("ent: ", DUMP_PREFIX_NONE, buf_ent, 21);
}

SetupDiEnumDeviceInterfaces returns ERROR_INVALID_PARAMETER when querying bluetooth devices

I'm trying to get a HANDLE from a Bluetooth Low Energy device by using CreateFile().
Therefore I need to extract the device path of the device.
I get an ERROR_INVALID_PARAMETER error when calling SetupDiEnumDeviceInterfaces. It seems that the second parameter (DeviceInfoData) has a problem.
Any ideas what the problem could be?
EDITED: Simplified code
HDEVINFO hDevInfo;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_BLUETOOTH, 0, 0, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return;//1;
}
PSP_DEVINFO_DATA DeviceInfoData = new SP_DEVINFO_DATA;
DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, DeviceInfoData); i++)
{
DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
char detailDataBuf[0x100];
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailDataBuf;
ULONG length;
ULONG requiredLength = 0;
bool bResult = FALSE;
for(DWORD j = 0; j < 10; j++ )
{
SP_DEVICE_INTERFACE_DATA interfaceData;
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
bResult = SetupDiEnumDeviceInterfaces(hDevInfo, DeviceInfoData, &GUID_DEVCLASS_BLUETOOTH, j, &interfaceData );
if (!bResult) {
int lastError = GetLastError(); // always returns ERROR 259
continue;
}
// Get the size of the buffer required to receive the device info
SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, NULL, 0, &requiredLength, NULL );
if( requiredLength >= sizeof( detailDataBuf ) )
break;
// Get the name of the device
detailData->cbSize = sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA );
length = requiredLength;
bResult = SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, detailData, length, &requiredLength, NULL ) != 0;
if( !bResult )
break;
}
}
EDITED2:
Passing in NULL for DeviceInfoData: This simple case always returns false
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_BLUETOOTH, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
bool bResult = FALSE;
for(DWORD j = 0; j < 10; j++ )
{
SP_DEVICE_INTERFACE_DATA interfaceData;
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
bResult = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVCLASS_BLUETOOTH, j, &interfaceData );
if (!bResult) {
int lastError = GetLastError(); // ERROR 259
continue;
}
}
The documentation says:
DeviceInfoData [in, optional]
A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet.
In other words, it must point to an element of deviceInfo, which the pointer you are passing doesn't. If you don't want to filter the results to the interfaces of a specific device in the device information set, pass NULL.
(Note that this is an input parameter, as indicated by the "in" tag. The output is passed via the fifth parameter, DeviceInterfaceData.)

No-overflow cast on x64

I have an existing C codebase that works on x86.
I'm now compiling it for x64.
What I'd like to do is cast a size_t to a DWORD, and throw an exception if there's a loss of data.
Q: Is there an idiom for this?
Here's why I'm doing this:
A bunch of Windows APIs accept DWORDs as arguments, and the code currently assumes sizeof(DWORD)==sizeof(size_t). That assumption holds for x86, but not for x64. So when compiling for x64, passing size_t in place of a DWORD argument, generates a compile-time warning.
In virtually all of these cases the actual size is not going to exceed 2^32. But I want to code it defensively and explicitly.
This is my first x64 project, so... be gentle.
see boost::numeric_cast
http://www.boost.org/doc/libs/1_33_1/libs/numeric/conversion/doc/numeric_cast.html
I just defined a function to perform the cast.
I included an assert-like behavior to insure I'm not silently rubbishing pointers.
DWORD ConvertSizeTo32bits(size_t sz, char *file, int line)
{
if (!(0 <= sz && sz <= INT32_MAX)) {
EmitLogMessage("Invalid Pointer size: %d file(%s) line(%d)",
sz, file, line);
ExitProcess( 0 );
}
return (DWORD) sz;
}
#define size_t_to_DWORD(st,dw) if ((DWORD)(st) != st) RaiseException(exLossOfData, 0, 0, NULL); else dw = (DWORD)(st)
size_t st;
DWORD dw;
st = 0xffffffff;
size_t_to_DWORD(st,dw); // this succeeds
st = 0xffffffff1;
size_t_to_DWORD(st,dw); // this throws
EDIT:
Or better yet, do this so you can use it in an expression:
DWORD MyRaiseException()
{
RaiseException(1, 0, 0, NULL);
return 0;
}
#define size_t_to_DWORD(st) (DWORD)(st) != (st) ? MyRaiseException() : (DWORD)(st)
void main(void)
{
size_t st;
DWORD dw;
st = 0xffffffff1;
dw = size_t_to_DWORD(st);
printf("%u %u\n", st, dw);
}

How to enumerate process' handles?

Is there any way how to enumerate process with given PID in windows, and get list of all his opened handles(locked files, etc.)?
EDIT: I dont care about language. If it is in .NET, I'd be glad, if in WinApi (C), it won't hurt. If in something else, I think I can rewrite it :-)
I did a deep googling and found this article.
This article gave a link to download source code:
I tried method in NtSystemInfoTest.cpp ( downloaded source code ) and it worked superbly.
void ListHandles( DWORD processID, LPCTSTR lpFilter )
The code has following declaimer:
// Written by Zoltan Csizmadia, zoltan_csizmadia#yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
// The source is free, but if you want to use it, mention my name and e-mail address
//
//////////////////////////////////////////////////////////////////////////////////////
//
I hope this helps you.
The command-line 'Handle' tool from Sysinternals does this, if you just want a tool. This won't help you if you're looking for a code solution, though.
Here is an example using ZwQueryProcessInformation from the DDK. The DDK is now known as the "WDK" and is available with MSDN. If you don't have MSDN, apparantly, you can also get it from here.
I haven't tried it, I just googled your question.
#include "ntdll.h"
#include <stdlib.h>
#include <stdio.h>
#include "ntddk.h"
#define DUPLICATE_SAME_ATTRIBUTES 0x00000004
#pragma comment(lib,"ntdll.lib")
BOOL EnablePrivilege(PCSTR name)
{
TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};
LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid);
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof priv, 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
int main(int argc, char *argv[])
{
if (argc == 1) return 0;
ULONG pid = strtoul(argv[1], 0, 0);
EnablePrivilege(SE_DEBUG_NAME);
HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
ULONG n = 0x1000;
PULONG p = new ULONG[n];
while (NT::ZwQuerySystemInformation(NT::SystemHandleInformation, p, n * sizeof *p, 0)
== STATUS_INFO_LENGTH_MISMATCH)
delete [] p, p = new ULONG[n *= 2];
NT::PSYSTEM_HANDLE_INFORMATION h = NT::PSYSTEM_HANDLE_INFORMATION(p + 1);
for (ULONG i = 0; i < *p; i++) {
if (h[i].ProcessId == pid) {
HANDLE hObject;
if (NT::ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &hObject,
0, 0, DUPLICATE_SAME_ATTRIBUTES)
!= STATUS_SUCCESS) continue;
NT::OBJECT_BASIC_INFORMATION obi;
NT::ZwQueryObject(hObject, NT::ObjectBasicInformation, &obi, sizeof obi, &n);
printf("%p %04hx %6lx %2x %3lx %3ld %4ld ",
h[i].Object, h[i].Handle, h[i].GrantedAccess,
int(h[i].Flags), obi.Attributes,
obi.HandleCount - 1, obi.PointerCount - 2);
n = obi.TypeInformationLength + 2;
NT::POBJECT_TYPE_INFORMATION oti = NT::POBJECT_TYPE_INFORMATION(new CHAR[n]);
NT::ZwQueryObject(hObject, NT::ObjectTypeInformation, oti, n, &n);
printf("%-14.*ws ", oti[0].Name.Length / 2, oti[0].Name.Buffer);
n = obi.NameInformationLength == 0
? MAX_PATH * sizeof (WCHAR) : obi.NameInformationLength;
NT::POBJECT_NAME_INFORMATION oni = NT::POBJECT_NAME_INFORMATION(new CHAR[n]);
NTSTATUS rv = NT::ZwQueryObject(hObject, NT::ObjectNameInformation, oni, n, &n);
if (NT_SUCCESS(rv))
printf("%.*ws", oni[0].Name.Length / 2, oni[0].Name.Buffer);
printf("\n");
CloseHandle(hObject);
}
}
delete [] p;
CloseHandle(hProcess);
return 0;
}

Resources