Phương pháp lấy số seri thẻ SD trên Windows CE 6.0

Trong cộng đồng lập trình nhúng, việc bảo vệ phần mềm thông qua mã hóa hoặc đọc số seri phần cứng luôn là chủ đề nóng. Hai phương pháp này có ưu và nhược điểm riêng. Đối với cách đọc số seri phần cứng, nó phụ thuộc nhiều vào thiết bị cụ thể. Thông thường, CPU và thẻ T-Flash có thể chứa số seri. Bài viết này sẽ trình bày chi tiết cách đọc số seri từ thẻ SD (T-Flash) trên nền tảng Windows CE 6.0.

Trước tiên, chúng ta cần khai báo các hằng số và nguyên mẫu hàm trong file header (.h):

#define SD_PART_NAME    L"DSK2:"
#define VALID_SD_SERIAL_1    L"A7DFB784"
BOOL GetStorageID(TCHAR *ptcCardName, TCHAR *ptcManufactureID, TCHAR *ptcSerialNum);

Phần triển khai hàm như sau:

BOOL GetStorageID(TCHAR *ptcCardName, TCHAR *ptcManufactureID, TCHAR *ptcSerialNum)
{
    DWORD dwSize = 0;
    DWORD dwReqSize = 0;
    STORAGE_IDENTIFICATION StoreInfo;
    STORAGE_IDENTIFICATION StoreInfo2;
    HANDLE hVolume = NULL;
    BOOL bRet = FALSE;

    BYTE *pucSerialNo = NULL;
    BYTE *pucManuID = NULL;
    int i = 0;

    ZeroMemory(&StoreInfo, sizeof(STORAGE_IDENTIFICATION));

    hVolume = CreateFile(ptcCardName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (NULL == hVolume || INVALID_HANDLE_VALUE == hVolume)
    {
        RETAILMSG(1, (L"Open Partation failed!\r\n"));
        return FALSE;
    }

    bRet = DeviceIoControl(hVolume, IOCTL_DISK_GET_STORAGEID,
        NULL, 0, (LPVOID)&StoreInfo, 3000, &dwSize, NULL);
    if (!bRet)
    {
        DWORD dwErr = GetLastError();
        RETAILMSG(1, (L"Device IO 1 failed: %d!\r\n", dwErr));
        CloseHandle(hVolume);
        return FALSE;
    }

    dwReqSize = StoreInfo.dwSize;
    ASSERT(dwReqSize > 0);

    dwSize = 0;
    StoreInfo2.dwSize = dwReqSize;
    bRet = DeviceIoControl(hVolume, IOCTL_DISK_GET_STORAGEID,
        NULL, 0, (LPVOID)&StoreInfo, dwReqSize, &dwSize, NULL);
    if (FALSE == bRet)
    {
        DWORD dwErr = GetLastError();
        RETAILMSG(1, (L"Device IO 2 failed: %d!\r\n", dwErr));
        CloseHandle(hVolume);
        return FALSE;
    }

    pucSerialNo = (((BYTE *)&StoreInfo) + StoreInfo.dwSerialNumOffset);
    pucManuID = (((BYTE *)&StoreInfo) + StoreInfo.dwManufactureIDOffset);

    i = 0;
    while (pucSerialNo[i] != 0 && i < 200 && i < (int)(dwSize - StoreInfo.dwSerialNumOffset))
    {
        ptcSerialNum[i] = pucSerialNo[i];
        i++;
    }
    ptcSerialNum[i] = '\0';

    i = 0;
    while (pucManuID[i] != 0 && i < 200 && i < (int)(StoreInfo.dwSerialNumOffset - StoreInfo.dwManufactureIDOffset))
    {
        ptcManufactureID[i] = pucManuID[i];
        i++;
    }
    ptcManufactureID[i] = '\0';

    CloseHandle(hVolume);
    return TRUE;
}

Ví dụ gọi hàm:

TCHAR tcSDSerial[256];
TCHAR tcSDManu[256];

ZeroMemory(tcSDSerial, sizeof(TCHAR) * 256);
ZeroMemory(tcSDManu, sizeof(TCHAR) * 256);

if (GetStorageID(SD_PART_NAME, tcSDManu, tcSDSerial))
{
    MessageBox(tcSDSerial);
    if (wcsncmp(VALID_SD_SERIAL_1, tcSDSerial, wcslen(VALID_SD_SERIAL_1)) == 0)
    {
        // Serial khớp
    }
    else
    {
        // Serial không khớp
    }
}
else
{
    // Xử lý lỗi
}

Trong quá trình triển khai, tôi gặp phải một số lỗi phổ biến:

  • Khi thay đổi tên partition thành "DSK1:" (dù DSK1 tồn tại), hàm DeviceIoControl trả về lỗi Error 50: The request is not supported. Điều này cho thấy không phải partition nào cũng hỗ trợ IOCTL_DISK_GET_STORAGEID.
  • Nếu truyền sai kích thước bộ đệm (ví dụ: sizeof(STORAGE_IDENTIFICATION) thay vì giá trị đủ lớn), hệ thống báo lỗi Error 122: The data area passed to a system call is too small. Do đó, luôn kiểm tra kích thước thực tế từ lệnh gọi đầu tiên và cấp phát bộ đệm tương ứng. Nên gọi GetLastError() để lấy thông tin lỗi chi tiết.

Thẻ: Windows CE 6.0 SD Card Serial Number IOCTL_DISK_GET_STORAGEID embedded systems

Đăng vào ngày 12 tháng 7 lúc 12:58