用户需要有一个license文件,内容是加密之后的硬盘序列号信息;
程序需要通过自己特定算法,将本地硬盘序列号混淆后使用SHA1加密为固定字符串;
程序在关键代码处检测许可证状态,对比用户持有的license文件是否跟程序加密后的字符串相同,如果相同则进行授权,否则阻止下一步操作。
演示程序通过“Generate”按钮创建允许授权的license文件,“Check”按钮进行授权验证。
//https://learn.microsoft.com/zh-cn/windows/win32/fileio/disk-management-control-codes //https://learn.microsoft.com/zh-cn/windows/win32/api/winioctl/ni-winioctl-ioctl_storage_query_property //https://learn.microsoft.com/zh-cn/windows/win32/api/winioctl/ns-winioctl-storage_property_query //https://blog.csdn.net/lengye7/article/details/122953234 set^ EnviMode=1 set^ ForceLocal=1 set$ nl=0d 0a envi DriveSerialNumber= envi usercode1=123 envi usercode2=456 envi hsn= //set disk=\\?\STORAGE#Volume#{bd7e99c2-72f8-11ed-b079-806e6f6e6963}#0000000000100000#{7f108a28-9833-4b3b-b780-2c6b5fa5c062} //检索设备接口路径 //set disk=\\?\scsi#disk&ven_st2000dm&prod_001-1ch164#4&15828421&0&030000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} //检索设备接口路径 //set disk=\\?\scsi#disk&ven_samsung&prod_ssd_850_evo_500g#4&15828421&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} //检索设备接口路径 //set disk=\\.\Volume{e1d1e74e-4d47-11ed-aa55-806e6f6e6963} //检索卷 //set disk=\\.\HarddiskVolume2 //检索 MS-DOS 设备 set disk=\\.\PhysicalDrive0 //检索磁盘 //set disk=\\.\Harddisk0Partition1 //检索分区 //set disk=\\.\GLOBALROOT\device\Harddisk0\Partition1 //检索分区 //set disk=\\.\C: //检索 C 盘 set generic_read=0x80000000 set file_share_read=0x00000001 set file_share_write=0x00000002 calc dwShareMode=%file_share_read% | %file_share_write% set open_existing=3 set file_attribute_normal=0x00000080 call $--qd --ret:h Kernel32.dll,CreateFileW,$%disk%,#%generic_read%,#%dwShareMode%,#0,#%open_existing%,#%file_attribute_normal%,#0 //如果函数成功,则返回值是指定文件、设备、命名管道或邮件槽的打开句柄。如果函数失败,则返回值为 INVALID_HANDLE_VALUE (-1)。 要获得更多的错误信息,请调用 GetLastError。 ifex $%h%<>-1, { set ioctl_storage_base=0x0000002d set Function=0x0500 set method_buffered=0 set file_any_access=0 calc ioctl_storage_query_property=shl(%ioctl_storage_base%,16) | shl(%file_any_access%,14) | shl(%Function%,2) | %method_buffered% //0x2D1400 set nInBufferSize=0xC //结构体 storage_property_query 的长度 set$# lpInBuffer=*%nInBufferSize% 0 set-long PropertyId=0 //由 storage_property_id 枚举的 StorageDeviceProperty 值,指示调用方是请求设备描述符、适配器描述符、写入缓存属性、设备唯一 ID (DUID) ,还是设备 SCSI 重要产品数据 (VPD) 页中提供的设备标识符。 set-long QueryType=0 //由 storage_query_type 枚举的 PropertyStandardQuery 值,要查询类型的标志 set-long AdditionalParameters=0 //包含可用于检索特定查询的其他参数的字节数组 set-copy lpInBuffer=PropertyId;0;4;0 set-copy lpInBuffer=QueryType;0;4;4 set-copy lpInBuffer=AdditionalParameters;0;4;(4 + 4) ifex $%::bX64%<3, set lpdword=4! set lpdword=8 //%&::bX64%=0, PECMD32+Win32 //%&::bX64%=1, PECMD32+WIN64 //%&::bX64%=3, PECMD64+WIN64 calc nOutBufferSize=0x28 + 1K //结构体 storage_device_descriptor 的长度 set$# lpOutBuffer=*%nOutBufferSize% 0 set$# lpBytesReturned=*%lpdword% 0 //LPDWORD 实际就是DWORD类型,int call $--qd --ret:RetDeviceIoControl Kernel32.dll,DeviceIoControl,#%h%,#%ioctl_storage_query_property%,*lpInBuffer,#%nInBufferSize%,*lpOutBuffer,#%nOutBufferSize%,*lpBytesReturned,#0 //如果操作成功完成,则返回值为非零 (TRUE) 。如果操作失败或挂起,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。 call $--qd --bool --ret:RetCloseHandle Kernel32.dll,CloseHandle,#%h% //如果函数成功,则返回值为非零值。如果函数失败,则返回值为零。若要获取扩展的错误信息,请调用 GetLastError。如果应用程序在调试器下运行,则函数在收到无效的句柄值或伪句柄值时将引发异常。如果关闭句柄两次,或者对 FindFirstFile 函数返回的句柄调用 CloseHandle,而不是调用 FindClose 函数,则可能会发生这种情况。 ifex $%RetDeviceIoControl%<>0, { //结构体 storage_device_descriptor set?int lpOutBuffer=Size:4 set?int lpOutBuffer=SerialNumberOffset:(4 + 4 + 1 + 1 + 1 + 1 + 4 + 4 + 4) call GetStr SerialNumber %SerialNumberOffset% set DriveSerialNumber=%SerialNumber% } } HASH $%usercode1%$%DriveSerialNumber%$%usercode2%,hsn,SHA1 READ %CurDir%\license.txt,0,userlic call keygen _sub GetStr envi szId= ifex $%~2>0, { set-make lpHex=&lpOutBuffer@%~2;*(%Size% - %~2) code **ansi,lpHex,**uni,szId exit - //以下未使用 getf -bin lpOutBuffer,%~2#(%Size% - %~2),szHex lpos* * szPos= 0x00,1,szHex ifex $%szPos%>0, { mstr * lpHex=1,%szPos%,szHex code ***ansi,szHex,**uni,szId } } set-ret %~1=%szId% _end _SUB keygen,W410H160,KeyGen LABE labe1,L20T30W88H48,User license: LABE labe2,L140T30W288H28,%userlic% LABE labe3,L20T60W128H48,Local license: LABE labe4,L140T60W248H28,%hsn% item item1,L20T100W80H20,Generate,call createlic item item2,L120T100W80H20,Check,call checklic labe reg1,L220T100W100H20,%register% _END _SUB createlic WRIT *c %CurDir%\license.txt,$+0,%hsn% READ %CurDir%\license.txt,0,userlic2 envi @labe2=%userlic2% find $%userlic2%=%hsn%,mess License file created successfully!mess Failed to create license file _END _SUB checklic find $%userlic%=%hsn%,envi @reg1=registered!envi @reg1=unregistered _END
感谢527104427的代码:[原创]调用 api 实例(检索指定磁盘设备描述符,即磁盘型号、序列号、总线类型等)(storage_device_descriptor)-PECMD脚本源码分享-PECMD技术社区
学习一下
你非常擅长你所做的事情,非常感谢你
thanks you very much
谢谢老师分享!