现在我们采用VC编写生成密钥的代码,VC靠近底层,所有可以很方便的读取硬件的一些底层信息,然后C/C++可以直接进行位操作,因此可以编写出很高效的密钥运算代码,先给出完整代码然后一一解读。
#pragma once
#pragma comment(lib,"Setupapi.lib")
#pragma comment(lib,"shlwapi.lib")
#include "stdafx.h"
//#include <WinSock2.h>//如果要加上这个文件,那么必须放在windows.h的前面,并且放在很前面,因为它会包含windows.h
#include <Windows.h>
#include <Setupapi.h>
#include <winioctl.h>
#include <initguid.h>
#include <Iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>// 生成随机数
#include <tchar.h>
DEFINE_GUID(UsbClassGuid, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
#define MAXSIZE 1024// usb设备信息最大长度
TCHAR ID[] = { TEXT("usb") };
TCHAR ErrorMsg[100];// 错误信息提示
//#define MAXLEN 104// 104/4=21表示最多允许21个盘符
#define FILESIZE 111110// 100KB
#define FAIL "1" //失败标志,传递给界面程序
VOID TransError()// 不判断函数成功与否,因为这个函数只起一个进程间通信的作用,失败影响不大
{
if (!OpenClipboard(NULL))
{
return;
}
TCHAR *data = TEXT(FAIL);
HGLOBAL hGClip = GlobalAlloc(GHND, 2);// 申请切剪内存堆,hGClip是句柄
TCHAR *ClipBuff = (TCHAR *)GlobalLock(hGClip);// ClipBuff 堆的地址
strcpy(ClipBuff, data);
GlobalUnlock(hGClip);
EmptyClipboard();// 清空剪切内存并得到控制权
HANDLE Clib = SetClipboardData(CF_TEXT, hGClip);
CloseClipboard();
}
BOOL CreateKey(TCHAR *msg)// 写入硬件信息,标志PC已经唯一加密,防止人利用本程序重新加密而破解保护
{
HKEY hCompanyKey = NULL;
DWORD dw;
LONG ret = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("USBLOCK"), 0, REG_NONE, REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_READ, NULL,
&hCompanyKey, &dw);
if (ret != ERROR_SUCCESS)
{
//MessageBox(0, "错误1", "", 0);
TransError();// 传递出错信息
return FALSE;
}
RegSetValueExA(hCompanyKey, "LOCK", NULL, REG_SZ, (const BYTE *)msg, _tcslen(msg));
return TRUE;
}
BOOL SetSecret(TCHAR *Disk, int Key[], int KeyLen)// 创建Key文件
{
// 检测PC是否被加密过
HKEY hKey = NULL;
LONG ret = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("USBLOCK"), NULL, KEY_ALL_ACCESS, &hKey);
if (ret == ERROR_SUCCESS)
{
//MessageBox(0, "错误2", "", 0);
TransError();// 传递出错信息
return FALSE;// 判断PC是否已经加密
}
TCHAR uPath[20]; //tKey.sys,fKey.sys
_stprintf_s(uPath, TEXT("%stKey.sys"), Disk);// 合成路径
BYTE RandNum;
DWORD dwSize;
HANDLE hFile = CreateFile(uPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, NULL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
//MessageBox(0, "错误3", "", 0);
TransError();// 传递出错信息
return FALSE;
}
for (int i = 0; i < FILESIZE; i++)
{
srand((unsigned)(Key[i%KeyLen] + i));//这样使每次加密产生的数据都不一样,增加混乱度
RandNum = rand() % 256;
SetFilePointer(hFile, (LONG)i, NULL, FILE_BEGIN);
WriteFile(hFile, &RandNum, 1, &dwSize, NULL);
}
int k = 0;
BYTE data;
while (k < KeyLen)
{
data = Key[k] % 256;//每次写入的数据限制在一字节内
SetFilePointer(hFile, (LONG)Key[k++], NULL, FILE_BEGIN);
WriteFile(hFile, &data, 1, &dwSize, NULL);
}
SetVolumeLabel(Disk, TEXT("Eye of God"));
return TRUE;
}
int KernelSerial(int _USB[], int _MAC[], int _number[], int _len)//联合USB序列和网卡序列
{
int j;
int _len_temp1 = _len > 6 ? 6 : _len;
int _len_temp2 = _len < 6 ? 6 : _len;
int *temp3 = _len_temp2 != 6 ? _USB : _MAC;
for (j = 0; j < _len_temp1; j++)
{
_number[j] = _USB[j] ^ (_MAC[j] + j);
}
while (j < _len_temp2)
{
_number[j] = (temp3[j] + j) % 100000; // 将Key控制在十万字节“=”100kb
j++;
}
return j;
}
BOOL GetMac(int number[])
{
PIP_ADAPTER_INFO Adapt_Device;//网卡适配器指针
Adapt_Device = (PIP_ADAPTER_INFO)GlobalAlloc(GMEM_ZEROINIT, sizeof(IP_ADAPTER_INFO));//申请适配器空间
ULONG size = sizeof(IP_ADAPTER_INFO);
int bRet = GetAdaptersInfo(Adapt_Device, &size);
if (bRet == ERROR_BUFFER_OVERFLOW)
{
GlobalFree(Adapt_Device);//释放空间
Adapt_Device = (PIP_ADAPTER_INFO)GlobalAlloc(GMEM_ZEROINIT, size);//重新申请适配器空间
}
bRet = GetAdaptersInfo(Adapt_Device, &size);//重新调用
if (bRet != NO_ERROR)
{
//MessageBox(0, "错误4", "", 0);
TransError();// 传递出错信息
return FALSE;
}
for (int i = 0; i < Adapt_Device->AddressLength; i++)
{
number[i] = Adapt_Device->Address[i];
}
return TRUE;
}
BOOL MathDevice(TCHAR *detail)//匹配设备是否是U盘
{
for (int i = 4, k = 0; i < 7; i++, k++)
{
if (detail[i] != ID[k])
{
return FALSE;
}
}
return TRUE;
}
VOID EnDecrypt(TCHAR *Str1, int Str2[], int len)//加密字符串,几乎不会出现重复的数字
{
int key[10] = { 0x21,0x3C,0x0BF,0x0F4,0x0BB,0x2B,0x9A,0x7D,0x1E,0x0CF };
int i, temp;
for (i = 0; i<len; i++)
{
temp = (~(Str1[i] * (i + 1) + i)) ^ (i*(i + 3));
Str2[i] = (temp^key[i % 10]) ^ (~key[i % 10] + i);
}
}
int Format(TCHAR *Origi_Num, int Serial_Num[])//格式化usb序列
{
int mark = 0, k = 0;
TCHAR temp[300];
for (int j = 0;; j++)
{
while (mark<2)
{
if (Origi_Num[j] == '#') mark++;
j++;
continue;
}
if (Origi_Num[j] == '&') break;//物理序号终止标志
temp[k++] = Origi_Num[j];
}
EnDecrypt(temp, Serial_Num, k);
return k;
}
BOOL GetDevicePath(LPCGUID guid, TCHAR *path)//读取设备路径
{
BOOL bResult = FALSE;//成功判断
DWORD index = 0;
SP_DEVICE_INTERFACE_DATA DeviceInfoData;//枚举的其中某个设备的综合信息
//.............分配并且初始化某个设备细节的信息空间
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetail;
DeviceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(GMEM_ZEROINIT, MAXSIZE);
if (DeviceDetail == NULL)
{
//MessageBox(0, "错误5", "", 0);
TransError();// 传递出错信息
return FALSE;
}
DeviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//......................
HDEVINFO hDevinfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevinfo == INVALID_HANDLE_VALUE)
{
//MessageBox(0, "错误6", "", 0);
TransError();// 传递出错信息
return FALSE;
}
DeviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (SetupDiEnumDeviceInterfaces(hDevinfo, NULL, guid, index, &DeviceInfoData))
{
SetupDiGetDeviceInterfaceDetail(hDevinfo, &DeviceInfoData, DeviceDetail, MAXSIZE, NULL, NULL);
if (MathDevice(DeviceDetail->DevicePath))
{
memcpy(path, DeviceDetail->DevicePath, _tcslen(DeviceDetail->DevicePath) + 1);//取设备路径
bResult = TRUE;
break;
}
index++;
}
GlobalFree(DeviceDetail);//释放空间
SetupDiDestroyDeviceInfoList(hDevinfo);//关闭设备信息集句柄
return bResult;
}
BOOL ExistMark()// doing for main form!!!refuse Crack!
{
HKEY key;
HKEY hCompanyKey;
DWORD dw;
LONG ret = RegOpenKeyEx(HKEY_CURRENT_CONFIG, "System", 0, KEY_ALL_ACCESS, &key);
if (ret != ERROR_SUCCESS)
{
//MessageBox(0, "错误7", "", 0);
TransError();// 传递出错信息
return FALSE;
}
ret = RegCreateKeyEx(key, TEXT("Email"), 0, REG_NONE, REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_READ, NULL,
&hCompanyKey, &dw);
if (ret != ERROR_SUCCESS)
{
//MessageBox(0, "错误8", "", 0);
TransError();// 传递出错信息
return FALSE;
}
RegSetValueExA(hCompanyKey, "Exist", NULL, REG_SZ, (const BYTE*)TEXT("Non-existent"),12);
RegSetValueExA(hCompanyKey, "GUID", NULL, REG_SZ, (const BYTE*)TEXT("NULL"), 4);
return TRUE;
}
int APIENTRY WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,// lpCmdLine为USB盘符
_In_ int nShowCmd
)
{
int Serial_Len; //usb序列长度
int Final_Len; //最终序列长度
int Serial_Number[300]; //加密后的usb序列
int Kernel_Num[100];//最终合成序列
int MAC[6]; //网卡序列
TCHAR messge[300];
BOOL retResult = GetDevicePath(&UsbClassGuid, messge);
if (!retResult)
{
//MessageBox(0, "错误9", "", 0);
return 0;
}
Serial_Len = Format(messge, Serial_Number);
if (!GetMac(MAC))
{
//MessageBox(0, "错误10", "", 0);
return 0;
}
Final_Len = KernelSerial(Serial_Number, MAC, Kernel_Num, Serial_Len);
retResult = SetSecret(lpCmdLine, Kernel_Num, Final_Len);
if (!retResult)
{
//MessageBox(0, "错误11", "", 0);
return 0;
}
retResult = CreateKey(messge);
if (!retResult)
{
//MessageBox(0, "错误12", "", 0);
return 0;
}
retResult = ExistMark();
if (!retResult)
{
//MessageBox(0, "错误13", "", 0);
return 0;
}
//MessageBox(0, "成功", "", 0);
return 0;
}
我们的程序是基于win32的,并非传统上显示“黑框框”的控制台程序,所以入口点不再是main()函数,而是WinMain()。int APIENTRY WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,// lpCmdLine为USB盘符
_In_ int nShowCmd
)
请注意lpCmdLine这个命令行参数,主程序通过这个指针把U盘盘符传递给当前程序,如同:C:\的形式。
BOOL GetDevicePath(LPCGUID guid, TCHAR *path)这个函数的主要目的就是读取USB设备的一系列信息,其中就包括了硬件序列号,guid是个传入参数,它的定义为DEFINE_GUID(UsbClassGuid, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b),这串16进制就是windows上用于表示USB设备的GUID,path是个传出参数,它包含了被函数初步加密的硬件序列。
BOOL MathDevice(TCHAR *detail)这个函数用来匹配设备是否是U盘,因为
我们能够读取出的设备信息全部是:”\\?\usb”的形式,所有我们需要判断信息是否含有”usb”的字样来确定是否是U盘。
得到了设备信息后,我们编写int Format(TCHAR *Origi_Num, int Serial_Num[])函数分离并初步加密硬件序列,其中Origi_Num指向设备信息,Serial_Num里则保存生成的信息,函数分离出序列号之后,再调用VOID EnDecrypt(TCHAR *Str1, int Str2[], int len)函数对序列号进行初次加密,结果保存于Str2[]中,在EnDecrypt函数中定义了一组密钥:0x21,0x3C,0x0BF,0x0F4,0x0BB,0x2B,0x9A,0x7D,0x1E,0x0CF
这组密钥保证了加密过的硬件序列几乎不可能出现重复的数据,然后再运用一系列的取反,位运算加密。
BOOL GetMac(int number[])函数获取本机第一块网卡的MAC序列,结果保存在number中,然后程序调用int KernelSerial(int _USB[], int _MAC[], int _number[], int _len)将MAC序列和硬件序列联合在一起进行混合运算,生成最终的密钥,保存在_number中,注意这句_number[j] = (temp3[j] + j) % 100000;为什么要除10万?听我慢慢道来,先说说我们密钥的作用,密钥其实是一个int类型的数组,里面的每一个数据都代表着我们生成的密钥文件的文件偏移,所有为了让密钥文件小于100kb,为什么要小于100kb?因为我们生成密钥文件的时候为了最大限度防止破解,在写入密钥数据的同时还用密钥数据作种子,随机生成很多垃圾数据,而这些数据的写入都是以字节加密为单位的,而且每次写入一个数据时候需要的偏移地址也是根据密钥数据临时生成的,因此一为了减小文件大小,二为了提高加密速度,所有限制在100kb左右,10万字节约等于100kb。前面的工作完成了,接下来调用BOOL SetSecret(TCHAR *Disk, int Key[], int KeyLen)生成最后的密钥文件并写入USB中。
使用USB硬件序列和网卡MAC进行加密的好处在于,第一,即使其他人用其他手段得到了USB里面的密钥文件,他也无法从其中得到密钥,因为我们的密钥是用算法以字节为单位散开存储在文件中的,每个USB生成的垃圾数据都是随机的,不可能通过对比找出密钥,而且在10万字节的数据中,一个字节一个自己的寻找出密钥几乎是不可能的事情。第二,硬件序列和网卡MAC是唯一的,格式化也无法改变,如果别有用心的人把密钥文件放在另外一个U盘里,那他这么做只是徒劳而已,因为在进行解锁的时候,程序会读取USB硬件序列和网卡MAC,再进行一次加密运算,然后将生成的数据与U盘中密钥文件中的密钥以字节为单位进行比对,所有其他USB是无法生成正确数据的,同样,拿加密过的U盘去解锁另外一台加密过的主机也是不可能的,因为每台主机的MAC是绝对不一样的,这样就保证了USB与被加密电脑的唯一性。
BOOL CreateKey(TCHAR *msg)这个函数在注册表里面生成HKEY_CURRENT_USER\USBLOCK这个键,并建立了一个名为“LOCK”的项,并往其中写入了USB设备信息,标志PC已经唯一加密,防止他人调用本程序重新生成密钥而达到破解保护的目的。
BOOL ExistMark()这个函数的目的类似,只不过是为主界面程序获取的密保Email进行保护。
VOID TransError()采用剪切板与主进程进行通信,如果因为各种原因安装密钥失败,就会通知主进程。
关于生成密钥的分析就到这里,其他细节请详细参考代码。
更多推荐
C#+VC打造炫酷USB电脑锁<二>密钥生成
发布评论