导航
  • 主页
  • API 调用
  • 基础类
  • 控件与界面
  • 数据库相关
  • DataWindow
  • 项目管理
  • Web 应用
  • 脚本语言

如何在PB中通过读取硬盘序列号实现软件加密^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

taoguang2 2003-01-10 01:19:02
高手们软件快做完的时候这一步一定不少吧???我想听听各位是怎么实现读取硬盘序列号和实现加密的??能不能把步骤代码写详细一点?
...全文
148 点赞 收藏 16
写回复
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
SUNNMOON 2003-08-11
如果学习探讨对PB软件的序列号加密办法---“路漫漫,其修远兮”。简单概括如下:如果自己搞加密,那只有公开的算法(RSA、ECC等)才是可靠算法的,但算法本身并不反跟踪与破解,它只解决对象安全问题。在共享软件安全保护上,唯有将入口安全和对象安全结合起来,才是稳妥可行的软件加密保护方案。目前具体加密工具产品有:比泰科技(www.bittide.com)的《软件防盗版战士》。能防止跟踪破解。它可以对PB编译的EXE程序加密,控制软件的发行。避免技术破解及最终用户盗版。适合数字化软件发行。可从google查"软件防盗版战士",或从www.bittide.com下载。

现介绍它的序列号版:

这是一个软件加密及数字化发行工具,加密后:
1、软件安全在不同电脑上,显示不同的序列号。序列号分三段,总在30位以内的,形如:3393975694 - 3387027627 - 1719891665 。它们分别对应于一个30位以内的注册码。

2、对于同一台电脑,若因为客户电脑格式化等原因多次安装同一软件,则安装后所显示的最后10位序列号是不会变的(前面20位可能会变),您可以知道因此识别你的软件老客户,而不被骗。

3、对于不同的软件,即使安装在同一电脑上,它们的序列号不会有相同之处。
回复
blazingstar 2003-06-18
GetVolumeInformationA取出的硬盘系列号是format产生的罗辑系列号,不是硬盘的物理系列号。这个系列号很容易被复制。建议使用专门读取物理系列号的DLL。
回复
泥泥 2003-01-10
大概是放在windows的系统目录,
回复
panpass 2003-01-10
to:北极光。
你提供的很对。但是,有一点需要改正,那就是要看你当前系统装在哪个盘上。我的2000在D盘,所以输入C不好使,我想,这是API函数的问题吧。
TO;无名小卒
DDL的声明放在全局或局部函数声明中。
回复
taoguang2 2003-01-10
morningdew(晓峰),你好,谢谢你!可我不知道DISKSER.DLL这个文件放在什么地方?
回复
morningdew 2003-01-10
我有一个DLL...用于获取硬盘序列号.现在放到网上..内有说明.
http://asp.6to23.com/xuguohao/diskserial.rar

剩下的工作,就是对这个序列号进行一些例如ASCII码加密之类的算法...
具体的算法,自已研究吧...
回复
taoguang2 2003-01-10
好什么呀!!我的问题怎么解决呀??
---------- Compiler: Errors
ylbx.pbl(w_about).w_about.getvolumeinformationa.2: Error C0094: Routine must return a value.
---------- Finished Errors
这是什么意思呀
回复
bomber2001 2003-01-10
好!!!好........
取硬盘序列号,写算法产生注册码;
然后根据用户输入的注册码,进行比较
回复
taoguang2 2003-01-10
楼上的,别光顾着爽呀!!为什么会提示那个呀??
回复
qqf 2003-01-10
爽,收起来。
回复
taoguang2 2003-01-10
不行呀!!我把代码写进去了,可不行!!告诉我:

---------- Compiler: Errors
ylbx.pbl(w_about).w_about.getvolumeinformationa.2: Error C0094: Routine must return a value.
---------- Finished Errors
这是什么意思呀
回复
taoguang2 2003-01-10
楼上的那位,那篇文章我早就看过了!可是不明白呀!!
Function Boolean GetVolumeInformationA( &

  ref String ls_Rootpath, &

  ref String ls_volumnename, &

  Ulong lul_VolumeNameSize, ref Ulong lul_VolumeSerialNumber, &

  ref Ulong lul_MaximumComponentLength, &

  ref Ulong lul_FileSystemFlags, &

  ref String ls_FileSystemNameBuffer, &

  Ulong lul_FileSystemNameSize &

  ) Library "Kernel32.dll"
这句话写在哪里呀??
回复
xuxutj 2003-01-10
lz
回复
wgy2008 2003-01-10
一、如何读取硬盘序列号

  
要读取硬盘序列号我们可以用汇编来实现,但毕竟不容易,况且也不能有效的结合到PB脚本中。在PB中我们可以通过调用Windows提供的外部函数GetVolumeInformationA()来实现。这相对来说比较简单。

  该函数的原型为:

  BOOL GetVolumeInformation(

  LPCTSTR lpRootPathName,

  LPTSTR lpVolumeNameBuffer,

  DWORD nVolumeNameSize,

  LPDWORD lpVolumeSerialNumber,

  LPDWORD lpMaximumComponentLength,

  LPDWORD lpFileSystemFlags,

  LPTSTR lpFileSystemNameBuffer,

  DWORD nFileSystemNameSize

  上述原型中,参数类型只要是以"LP-"开头的表明该参数用的是长指针(Long Pointer)类型,即在PB中调用时的参数传递是通过引用传递。在8个参数中对我们真正有用的只有两个LPCTSTR lpRootPathName和LPDWORD lpVolumeSerialNumber。其中参数lpRootPathName是指向文件系统根目录的地址,我们需要用它来指明所要获取序列号的硬盘盘符;参数lpVolumeSerialNumber是返回的硬盘序列号的地址,这正是我们需要的。

  众所周知,PB在调用任何外部函数前都要首先进行函数声明,可以将声明放在全局或局部函数声明中。具体声明如下:

  Function Boolean GetVolumeInformationA( &

  ref String ls_Rootpath, &

  ref String ls_volumnename, &

  Ulong lul_VolumeNameSize, ref Ulong lul_VolumeSerialNumber, &

  ref Ulong lul_MaximumComponentLength, &

  ref Ulong lul_FileSystemFlags, &

  ref String ls_FileSystemNameBuffer, &

  Ulong lul_FileSystemNameSize &

  ) Library "Kernel32.dll"



  上述声明中,"ref"指明是该参数是通过引用传递的,有关函数引用的详细内容请参见有关教程。声明完毕我们不能马上进行调用,还必需确保已为它分配足够的内存空间,即使是参数引用传递也是这样,否则的话将会出现调用错误,这跟C语言的引用调用不同,这一点往往被忽视,希望读者能够注意。也就是为什么我在调用该函数前将有些字符串参数给它预先分配了多达256个字符空间以及给一些整型类型的参数赋初始值256。完整的读取硬盘序列号的程序代码如下:

/******************* 程序代码 ************************/

String ls_Rootpath, ls_volumnename

ls_Rootpath = "C:" // 指定要得到序列号的硬盘,

// 一般情况都是C盘,除非你能保证用户存在其它逻辑盘或物理盘

ls_volumnename = Space(256) // 分配足够的空间,下同

Ulong lul_VolumeNameSize

lul_VolumeNameSize = 256

Ulong lul_VolumeSerialNumber, lul_MaximumComponentLength, lul_FileSystemFlags

lul_MaximumComponentLength = 256

String ls_FileSystemNameBuffer

ls_FileSystemNameBuffer = space(256)

Ulong lul_FileSystemNameSize

lul_FileSystemNameSize = 256

beep(1)

boolean lb_rtn

lb_rtn = False

lb_rtn = GetVolumeInformationA(ls_Rootpath, ls_volumnename, lul_VolumeNameSize,

lul_VolumeSerialNumber, lul_MaximumComponentLength, lul_FileSystemFlags,

ls_FileSystemNameBuffer, lul_FileSystemNameSize)

if lb_rtn = true then

MessageBox("提示","函数调用成功!")

else

MessageBox("提示","函数调用失败!")

end if

sle_1.text = String(lul_VolumeSerialNumber) // 得到硬盘序列号

/********************* 结束 *************************/

  一旦读取成功我们的任务也就完成了近一半,接下来要做的是怎样选择一个合适的加密算法。

二、选取一个优秀的加密算法

  1、数据加密概述

  早在几千年前人类就已经有了通信保密的思想和方法。但直到1949年,信息论创始人香农发表著名文章,论证了一般经典加密方法得到的密文几乎都是可破译的。密码学才得以进入了一个新的发展时期。70年代后期,美国的数据加密标准DES和公开密钥密码体制的出现成为近代密码学发展史上的两个重要里程碑。

  公开密钥密码体制的概念是由Difie与Hellman于1976年提出。所谓公开密钥密码体制就是加密密钥与解密密钥不同,是一种由已知加密密钥推导出解密密钥在计算上是不可行的密码体制。其中,基于数论中大数分解问题的RSA体制曾被ISO/TC97的数据加密技术委员会SC20推荐为公开密钥数据加密标准。

  2、RSA体制的基本原理

  该体制是根据寻求两个大素数比较简单,而将它们的乘积分解开则极其困难这一原理来设计的。在已提出的公开密钥算法中它是最容易理解和实现的。RSA在世界上许多地方已成事实上的标准。ISO几乎(但没有明确)已指定RSA用作数字签名标准。该算法已经经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明了该算法有一定的可信度。它的安全性是与大数分解密切相关的。我想通过下表你将会对它的安全性有一个较好的认识,它给出了在计算机每一微妙做一次操作的假定下分解不同大小的N所需要的时间。

  N的十进位数  50    75    100   200

  时间      3.9小时  104天  74年  3.8X1015年

  RSA加密算法具体如下:

  (1)选取两个大素数,p和q。为了获得最大程序的安全性,两个素数的长度一样。并计算乘积N(N=pq)。

(2) 随后计算出N的欧拉函数ф(N)=(p-1)(q-1),ф(N)定义为不超过N并与N互素的数的个数。

(3)从[0,ф(N)- 1]中随机选取加密密钥e,使得e和ф(N)互为素数。 

  (4)计算出满足公式ed=1 modф(N)的d,d为解密密钥。 

  (5)若用整数X表示明文,整数Y表示密文(X,Y均小于N),则加解密运算为:

  加密:Y = Xe mod N 

  解密:X = Yd mod N 

  注意,其中的d和N也互素。e和N是公开密钥,d是秘密密钥。两个素数p和q应舍弃,但千万不要泄密哦。

  3、相关数学背景知识

  (1)素数:素数是一个比1大,其因子只有1和它本身,没有其它数可以整除它的数。素数是无限的。例如,2,3,5,7……等。

(2)两个数互为素数:指的是它们除了1之外没有共同的因子。也可以说这两个数的最大公因子是1。例如,4和9,13和27等。

(3)模变换:两个数相模,如A模N运算,它给出了A的余数,余数是从0到N-1的某个整数,这种运算称为模运算。

  4、算法的具体实现

  从RSA的基本原理我们得知,对明文进行加密选择一个合适的e很重要,如果你选择合适的话,RSA的加密速度将快得多,并且也不会因为用户机器的限制而要做更多的变换(指在计算中为了避免数据的溢出所进行的转换,毕竟我们用的是PC机再说也用不着很高的安全性)。最常用的三个e值是3,17,65537。在这里我们取的e等于3,当然到底选取哪个e值并没有规定,这里只是为了演示方便罢了。

  根据算法定义,

  (1)为了方便起见我们选取素数p = 3和q = 11,则N = pq = 3 * 11 = 33。 

  (2)ф(N)=(p-1)(q-1)= 2 * 10 = 20。 

  (3)从[0,ф(N) - 1]中,即,[0, 19]之间任意选取加密密钥e = 3,且e和ф(N)互素。

  (4)如何从公式ed=1 modф(N)求出解密密钥d?

  由模的定理我们可以将公式ed=1 modф(N)转换成形式ed= k * ф(N)+ 1,即3d = k * 20 + 1,将0,1,2,3…依次代入k,求出d。取k = 1,得d = 7。

  读者可以通过编程实现随机选取p和q来求出相应的N,e,d。

  (5)进行加解密。

  对明文进行加密

  根据定义,我们首先要根据N的值对明文进行分组,每个分组的值应小于N。如果要加密固定的消息分组,那么可以在它的左边填充一些0(零)并确保该值比N小。例如,我们要对数据X=172035594进行加密(在我的计算机上C盘的序列号是0A41-0E0A,转换成十进制就是172035594),我们首先要将它分成小于N(N=33)的若干小组。可以分成,X1=17,X2=20,X3=3,X4=5,X5=5,X6=9,X7=4。对第一分组X1运用加密公式得到加密密文Y1=X1e mod N = 173 mod 33 = 29,依次将其余分组进行加密得到,Y2=14,Y3=27,Y4=26,Y5=26,Y6=3,Y7=31。即密文Y= 2914272626331。我们可以将密文存储在文件或注册表中,每当应用程序启动时先读取密文,并将其解密,再将解密后的结果与硬盘序列号进行比较,以此来判断软件是否合法。在实际运用中我们可以随时通过程序修改密文,比如,将密文去掉一位或将密文颠倒等,就可以实现诸如测试版软件的使用限制问题,

  对密文进行解密

  对密文进行解密同样要首先对密文进行分组,使每个分组都小于N。将密文Y=2914272626331分组成:

  Y1=29,Y2=14,Y3=27,Y4=26,Y5=26,Y6=3,Y7=31

  这时我们一定要注意,不要急于将将各分组代入解密公式X=Yd mod N,如果这样做了我们所得到的明文将是X=1202811913,并不是加密时的明文!是不是加密算法有错?绝对不是。回顾加解密的公式,我们不难发现它们做的都是先将一个数进行n次方运算然后在做模运算。问题就出在"n次方运算"上,千万不要忽略PowerBuilder中数值的取值范围,在其它的编程语言中也是如此。在本例中我给明文和密文用的都是unsigned long类型,它的32位所允许最大值是4294967295,的确很大,但我们不能保证一个数在进行了7次方后不超过该最大值。其实,这种情况在对明文加密时也是会发生的,只是33的3次方是35937,远小于最大值,我们将其忽略罢了。

  好在问题并不像我们想象的那么复杂。由模的运算规律得知,模运算像普通的运算一样,它是可交换的、可结合的、可分配的。而且,简化运算每一个中间结果的模n运算,其作用与先进行全部运算,然后再简化模
回复
xingxing 2003-01-10
要得不急的话就等到明天!!!!今天没办法给你!!!
回复
1。取硬盘序列号;
2。对此号进行加密,产生注册码;
3。用此注册码进行注册;
4。比较注册码对否。
回复
发动态
发帖子
PowerBuilder
创建于2007-09-28

813

社区成员

PowerBuilder 相关问题讨论
申请成为版主
社区公告
暂无公告