Windows下使用C++(Win32SDK)编程无需提权读取硬盘序列号(XP、Win7和Win10都可用)
2017-12-30 08:35
836 查看
在需要对计算机进行标识的场景下,我们一般会选择获取一些硬件信息。然而CPU序列号可能有重复、网卡MAC地址和计算机名又能被轻易地修改,所以其中最可靠的应该就是硬盘序列号了。Windows下硬盘序列号的获取本身并不复杂,而关键在于如何在无需权限提升的情况下获取到硬盘序列号。为了解决这个问题,我也查了很多资料,基本上各大博客中贴出的都是需要权限提升的代码。
最终,在DiskID32的源码中,我找到了不提权获取硬盘序列号的办法。不过其源码只能使用MBCS多字节字符集方式编译,而无法使用Unicode字符集编译,为此,我进行了一些修改,使之兼容两种方式。下面将经过我修改、测试后的代码贴出来,供大家参考。
其中,获取硬盘序列号的函数命名为GetHDSerial,该函数依赖flipAndCodeBytes函数。前者使用说明如下:
函数名:GetHDSerial
功能:用于获取指定编号的硬盘序列号,无需任何权限提升
参数:
PCHAR pszIDBuff:传入的字符串缓冲区,用于接收硬盘序列号
int nBuffLen:传入的字符串缓冲区大小,当硬盘序列号大于该值时,只复制nBuffLen长度
int nDriveID:要获取的驱动器编号,从0开始,到15为止
返回值:成功获取到的硬盘序列号长度,为0表示获取失败
最终,在DiskID32的源码中,我找到了不提权获取硬盘序列号的办法。不过其源码只能使用MBCS多字节字符集方式编译,而无法使用Unicode字符集编译,为此,我进行了一些修改,使之兼容两种方式。下面将经过我修改、测试后的代码贴出来,供大家参考。
其中,获取硬盘序列号的函数命名为GetHDSerial,该函数依赖flipAndCodeBytes函数。前者使用说明如下:
函数名:GetHDSerial
功能:用于获取指定编号的硬盘序列号,无需任何权限提升
参数:
PCHAR pszIDBuff:传入的字符串缓冲区,用于接收硬盘序列号
int nBuffLen:传入的字符串缓冲区大小,当硬盘序列号大于该值时,只复制nBuffLen长度
int nDriveID:要获取的驱动器编号,从0开始,到15为止
返回值:成功获取到的硬盘序列号长度,为0表示获取失败
#include <locale.h> #include <tchar.h> #include <windows.h> #include <stdio.h> char * flipAndCodeBytes(const char * str, int pos, int flip, char * buf) { int i; int j = 0; int k = 0; buf[0] = '\0'; if (pos <= 0) return buf; if (!j) { char p = 0; // First try to gather all characters representing hex digits only. j = 1; k = 0; buf[k] = 0; for (i = pos; j && str[i] != '\0'; ++i) { char c = tolower(str[i]); if (isspace(c)) c = '0'; ++p; buf[k] <<= 4; if (c >= '0' && c <= '9') buf[k] |= (unsigned char)(c - '0'); else if (c >= 'a' && c <= 'f') buf[k] |= (unsigned char)(c - 'a' + 10); else { j = 0; break; } if (p == 2) { if (buf[k] != '\0' && !isprint(buf[k])) { j = 0; break; } ++k; p = 0; buf[k] = 0; } } } if (!j) { // There are non-digit characters, gather them as is. j = 1; k = 0; for (i = pos; j && str[i] != '\0'; ++i) { char c = str[i]; if (!isprint(c)) { j = 0; break; } buf[k++] = c; } } if (!j) { // The characters are not there or are not printable. k = 0; } buf[k] = '\0'; if (flip) // Flip adjacent characters for (j = 0; j < k; j += 2) { char t = buf[j]; buf[j] = buf[j + 1]; buf[j + 1] = t; } // Trim any beginning and end space i = j = -1; for (k = 0; buf[k] != '\0'; ++k) { if (!isspace(buf[k])) { if (i < 0) i = k; j = k; } } if ((i >= 0) && (j >= 0)) { for (k = i; (k <= j) && (buf[k] != '\0'); ++k) buf[k - i] = buf[k]; buf[k - i] = '\0'; } return buf; } /************************************************************************ GetHDSerial:用于获取指定编号的硬盘序列号,无需任何权限提升 参数: PCHAR pszIDBuff:传入的字符串缓冲区,用于接收硬盘序列号 int nBuffLen:传入的字符串缓冲区大小,当硬盘序列号大于该值时,只复制nBuffLen长度 int nDriveID:要获取的驱动器编号,从0开始,到15为止 返回值: 成功获取到的硬盘序列号长度,为0表示获取失败 作者: famous214(blog.csdn.net/LPWSTR) 源码参考了diskid32(https://www.winsim.com/diskid32/diskid32.html) 版本历史: 20171226 第一版,从diskid32源码中提取 20171226 第二版,兼容Unicode编译方式 20171230 重构后发布第三版 ************************************************************************/ ULONG GetHDSerial(PCHAR pszIDBuff, int nBuffLen, int nDriveID) { HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; ULONG ulSerialLen = 0; __try { // Try to get a handle to PhysicalDrive IOCTL, report failure // and exit if can't. TCHAR szDriveName[32]; wsprintf(szDriveName, TEXT("\\\\.\\PhysicalDrive%d"), nDriveID); // Windows NT, Windows 2000, Windows XP - admin rights not required hPhysicalDrive = CreateFile(szDriveName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hPhysicalDrive == INVALID_HANDLE_VALUE) { __leave; } STORAGE_PROPERTY_QUERY query; DWORD cbBytesReturned = 0; static char l af8b ocal_buffer[10000]; memset((void *)&query, 0, sizeof(query)); query.PropertyId = StorageDeviceProperty; query.QueryType = PropertyStandardQuery; memset(local_buffer, 0, sizeof(local_buffer)); if (DeviceIoControl(hPhysicalDrive, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &local_buffer[0], sizeof(local_buffer), &cbBytesReturned, NULL)) { STORAGE_DEVICE_DESCRIPTOR * descrip = (STORAGE_DEVICE_DESCRIPTOR *)& local_buffer; char serialNumber[1000]; flipAndCodeBytes(local_buffer, descrip->SerialNumberOffset, 1, serialNumber); if (isalnum(serialNumber[0])) { ULONG ulSerialLenTemp = strnlen(serialNumber, nBuffLen - 1); memcpy(pszIDBuff, serialNumber, ulSerialLenTemp); pszIDBuff[ulSerialLenTemp] = NULL; ulSerialLen = ulSerialLenTemp; __leave; } } } __finally { if (hPhysicalDrive != INVALID_HANDLE_VALUE) { CloseHandle(hPhysicalDrive); } return ulSerialLen; } } void GetAllHDSerial(void) { const int MAX_IDE_DRIVES = 16; static char szBuff[0x100]; for (int nDriveNum = 0; nDriveNum < MAX_IDE_DRIVES; nDriveNum++) { ULONG ulLen = GetHDSerial(szBuff, sizeof(szBuff), nDriveNum); if (ulLen > 0) { _tprintf(TEXT("第%d块硬盘的序列号为:%hs\n"), nDriveNum + 1, szBuff); } } } int main() { setlocale(LC_ALL, "chs"); GetAllHDSerial(); system("pause"); return 0; }
相关文章推荐
- Windows c 获取cpu ,网卡,硬盘序列号,win10可用
- [Winhttp]_[C/C++]_[使用win32 SDK的Windows HTTP Services(WinHTTP)通过代理下载网页]
- 面向对象的Windows编程实战(上)(使用C++和Win32 API)
- [Winhttp]_[C/C++]_[使用win32 SDK的Windows HTTP Services(WinHTTP)通过代理下载网页]
- TCP Socket编程 C/C++实现 (Windows Platform SDK)
- TCP Socket编程 C/C++实现 (Windows Platform SDK)
- Win32 SDK 应用程序中使用XP控件外观(VS 2008)
- UDP Socket编程 C/C++实现 (Windows Platform SDK)
- win32 sdk使用xp风格控件
- TCP Socket编程 C/C++实现 (Windows Platform SDK)
- C#使用DISKID32.DLL读取硬盘序列号
- Windows音频编程:Win32 Wave API 的使用
- SDK编程获取硬盘序列号
- TCP/UDP Socket编程 C/C++实现(Windows Platform SDK)
- [转载]【分享】无需刻盘,在windows XP/VISTA/7下,硬盘安装ubuntu
- CP Socket编程 C/C++实现 (Windows Platform SDK)
- 编程读取windows98/2000/xp/2003的登录密码
- TCP Socket编程 C/C++实现 (Windows Platform SDK)
- Win32 SDK 应用程序中使用XP控件外观(VS 2008)
- 使用纯C语言开始win32 sdk编程