版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于硬盘序列号和RSA算法的软件加密系统的设计和实现摘要随着计算机软件业的飞速发展和计算机的日益普及计算机软件已经进入社会生活中的各个角落。但是由于计算机软件易于复制,所以随之而来的便是盗版软件的泛滥。这使软件开发人员蒙受了巨大的经济和社会损失,防止软件盗版最行之有效的方法就是对软件进行有效的加密。论文首先介绍了软件加密的发展现状和研究它的意义,接着对软件序列号保护的相关技术分析和当前流行的加密算法详细研究。基于以上理论基础,将本设计的基于硬盘序列号和RSA算法软件加密系统的设计和实现划分为两个层次:采用动态链接库文件DiskSerial.DLL导出的GetSerialNumber()函数获取硬盘的物理序列号,动态链接库的好处是可以采用多种编程语言来编写,增强产品的功能,提供二次开发的平台,简化项目管理,节省磁盘空间和内存,有助于资源的共享;注册机使用RSA加密算法将硬盘物理序列号加密生成为注册码,客户端将注册码进行解密运算,其结果与获取的本地计算机硬盘物理序列号对比,验证注册码的合法性。加密解密使用非对称密钥RSA算法,私钥和公钥不同,理论上从公钥推算出私钥是不可行的,当密钥长度达到1024位时,破解难度极大,所以使用RSA算法加密确保了软件的安全性。本设计因为使用的序列号是硬盘物理序列号,及每台电脑的序列号是不同的,从而保证了注册码的唯一性。经过调试和测试的验证,本设计结构简单,性能可靠,操作方便。本设计在软件保护行业有着广泛的使用价值,如在软件防盗中,用作注册码的生成与验证等。关键词:硬盘物理序列号;RSA算法;注册机;软件加密SystemdesignandimplementationofencryptionsystembasedonharddiskserialnumberandRSAalgorithmStudent:LIZhong-jieTeacher:ZHANGLie-pingAbstract:Withtherapiddevelopmentofcomputersoftwareindustry,andtheincreasingpopularityofcomputersoftwarehasenteredeverycornerofsociallife.However,becausecomputersoftwareiseasytoreplicate,sowhatcomesnextistheproliferationofpiratedsoftware.Thisallowssoftwaredeveloperssufferedhugeeconomicandsocialloss,topreventsoftwarepiracyisthemosteffectivewaytoencryptthesoftwareeffectively.First,thepaperintroducesthecurrentdevelopmentofsoftwareencryptionandresearchitsmeaning,thentheserialnumberofsoftwarerelatedtotechnicalanalysisandprotectionofthepopularencryptionalgorithmindetail.Basedontheabovetheory,thisdesignbasedontheharddiskserialnumberandtheRSAencryptionalgorithmsoftware,systemdesignandimplementationisdividedintotwolevels:thedynamiclinklibraryfilesDiskSerial.DLLexportedGetSerialNumber()functiontogettheharddriveofthephysicsserialnumber,Theadvantageofthedynamiclinklibrarycanbewrittenusingavarietyofprogramminglanguages,andenhanceproduct'sfeatures,provideseconddevelopmentplatform,simplifyingprojectmanagement,savingdiskspaceandmemorytohelpresourcesharing;KeygenusingRSAalgorithmencrypttheharddiskphysicalserialnumberofstudentstobecomeregistrationkey,registrationkeytodecrypttheclientwilloperation,itsresultsforthelocalcomputerharddiskphysicalserialnumbercontrast,validationLicenselegitimacy.EncryptionanddecryptionusingRSAasymmetrickeyalgorithm,theprivatekeyandpublickeydifference,intheorycalculatetheprivatekeyfromthepublickeyisnotfeasible,whenthe1024-bitkeylength,thecrackisextremelydifficult,sousetheRSAencryptionalgorithmtoensurethesecurityofthesoftware.Thedesignforusingtheserialnumberishardphysicalserialnumber,andserialnumberofeachcomputerisdifferent,thusensuringtheregistrationcodeisunique.Aftercommissioningandtestingoftheverification,thedesignissimple,reliable,easytooperate.Thedesignofthesoftwareprotectionindustryhasawiderangeofvalue,suchassoftwaresecurity,theregistrationcodeforthegenerationandverification.Keywords:sharddiskphysicalserialnumber;RSAalgorithm;keygen;softwareencryption目次TOC\o"1-3"\h\u14765摘要 I1470Abstract II106881绪论 1159461.1问题的提出及研究意义 1295421.2软件保护系统概念 1242151.3课题研究内容及论文的主要工作 254762软件序列号保护的相关技术介绍 3132.1序列号保护机制 3272222.1.1注册码保持不变 3262102.1.2注册码因输入信息而异 3216222.1.3注册码因用户计算机而异 4273312.2注册机信息采集技术 4124672.2.1网卡的物理地址(MAC)获取 412912.2.2磁盘逻辑序列号获取 549902.2.3磁盘物理序列号获取 530412.3常用的软件保护技术介绍 794582.3.1时间限制 7191372.3.2KeyFile保护 9243852.3.3CD-CHECK 9177102.4软件保护总结 9188292.5本章小结 10308893加密算法介绍 11231973.1DES算法 11151303.1.1DES算法原理 11189483.1.2DES算法的应用误区 114673.2MD5算法 1129973.2.1MD5算法原理 11320823.2.2MD5算法的应用 12207703.3RSA算法 1262533.3.1RSA算法原理 1211023.3.2RSA的安全性 1375693.3.3RSA的速度 1352493.4本章小结 1469664系统详细设计及实现 15270014.1开发环境介绍 15104254.1.1VisualC++6.0介绍 15146724.1.2MFC程序开发流程 16305184.2大进制数及其运算类定义 2077954.2.1大数类的详细描述 20138584.2.2大数类的类定义 21302924.3注册机的设计及实现 22209094.3.1注册机界面设计 2258334.3.2注册机算法的详细描述 253064.3.3算法的实现代码 2659334.3.4完成的注册机程序 2836574.4客户端的设计及实现 2950554.4.1客户端界面设计 29166864.4.2各种接口硬盘介绍 30176274.4.3客户端算法详细描述 3214354.4.4完成的客户端程序 34207234.5本章小结 36131355结论 3714208致谢 3832716参考文献 391绪论 1.1问题的提出及研究意义计算机软件业的飞速发展和计算机的日益普及计算机软件已经进入社会生活中的各个角落。计算机软件是开发者脑力劳动的成果,具有原创性质[1]。计算机软件开发要求软件开发人员拥有丰富的专业相关知识,具备优秀的逻辑思维和抽象思维能力,了解计算机硬件与软件的最新发展状况与发展趋势,熟练掌握和应用编程语言。尤其是开发具有大规模商业应用的计算机软件,通常需要专业分工、流水作业。必须具有的充足的物质条件和良好的技术储备。而计算机软件的复制是对计算机软件的客观再现,不改变软件内容,不影响软件本身的价值,而把软件转载于有形物体的行为。由于软件存在形式的特殊性,它比传统的作品更容易被复制,且复制所需投入少、耗时短、传播容易,无需借助特殊的装置。尤其在网络环境下计算机软件的复制与传播就更为方便,从而使盗版侵权成了轻易又且暴利的事情。这使软件开发人员蒙受了巨大的经济和社会损失,防止软件盗版最行之有效的方法就是对软件进行有效的加密[2]。随着软件的防盗版措施越来越被软件开发者所重视,其采用的技术也变得越来越广泛和复杂。软件的破解技术与保护技术这两者之间就是矛与盾的关系,它们是在互相斗争中发展进化的。这种技术上的较量归根到底是一种利益的冲突。软件开发者为了维护自身的商业利益,不断地寻找各种有效地技术来保护软件版权,以增加其保护强度,推迟软件被破解的时间;而破解者则受盗版所带来的高额利润的驱使,或出于纯粹的个人兴趣,而不断制作新的破解工具并针对新出现的保护方式进行跟踪分析以找到相应的破解方法。从理论上说,几乎没有破解不了的保护。但是如果一种保护技术的强大强到足以让破解者在软件的生命周期内无法将其完全破解,这种保护技术就可以说是非常成功的。因此,开发研制一种安全可靠、难以破解软件加密系统具有重大的经济意义和社会意义。1.2软件保护系统概念软件与普通作品不同,天生即具有技术属性。软件本身就是实现技术的一段计算机可以识别的编码。因此,在既有功能的基础上,很容易添加新的功能代码用于保护版权。这也意味着,相对于其他普通作品,在软件保护中使用技术手段的成本最低,效率最高。对于软件而言,通过对软件进行加密等技术保护手段可以有效的防止他人对软件擅自访问、复制、操作、散发及传播,同时也便于控制软件正常的授权使用以及使用后的监督。目前各国对于软件的保护性技术措施都有比较明确的概念。美国将技术措施的定义为“任何能够有效控制进入受版权保护的作品并能够有效保护版权人权利的措施。”而欧盟的定义为“设计用于阻止侵犯版权以及与数据库有关的特殊权利的设备、产品或方法。”但是技术措施事实上是一个开放的系统,随着技术的不断进步,不断地会有新类型的技术保护措施的涌现。本文出发点即是通过硬盘物理序列号用RSA算法生成唯一的注册码,从而对软件进行保护。软件权利人通过对软件等数字化形式存在的作品上设置的能够实现对作品的访问、复制、传播、修改和使用进行有效控制的各种技术手段、设备、产品或方法,并借此达到对作品未经授权的访问、复制、传播、修改与使用行为的警示、禁止甚至制裁的目的。这些技术手段、设备、产品或方法的实施阶段既包括在出售前与软件本体打包封装,亦包括在出售后通过在线升级、认证等方式加载。上述的这一类的技术手段、设备、产品或方法统称为软件保护技术[3]。1.3课题研究内容及论文的主要工作本课题研究内容主要有:MFC编程技术、软件保护技术概述、动态链接库文件的生产导入、获得Ring0级权限、获取硬盘物理序列号、定义大整数及其运算法则类、RSA非对称密钥加密解密算法、素数的判定和密钥对的生成;在了解以上技术之后,确定了各个模块的工作原理及作用,最后根据要实现的功能要求,绘制流程图,由流程图应用C++语言编写程序。本论文的主要工作如下:1)了解软件盗版的严重性,以及软件防盗的现状和发展趋势。2)了解软件产品的特点,深入分析软件易于复制传播的原因。掌握软件保护系统概念,熟悉软件保护中常用的技术手段。4)掌握MFC可视化编程常用的方法,动态链接库文件的制作和该文件的导入。5)了解常用的进入Ring0级权限的三种方法:第一种通过中断陷入技术,第二种通过写一个中断VXD(虚拟驱动设备)或WDM,最后一种通过WindowsAPI函数DeviceInControl调用Smartvsdvxd。掌握动态链接库导出函数获取硬盘物理序列号。6)掌握大数类的定义,大数类中定义了赋值、比较大小、加法、减法、乘法、除法、求模等基本运算法则。7)了解常用的加密算法,掌握RSA非对称加密算法的原理,随机生成密钥对(e,n)和(d,n)。熟悉序列号的加密和注册码的解密。8)根据功能需求,画出程序流程图,应用C++语言编写应用程序。2软件序列号保护的相关技术介绍2.1序列号保护机制数学算法一项都是密码加密的核心,但在一般的软件加密中,它似乎并不太为人们关心,因为大多数时候软件加密本身实现的都是一种编程的技巧。但近几年来随着序列号加密程序的普及,数学算法在软件加密中的比重似乎是越来越大了。所谓序列号保护机制就是软件开发者根据用户提供的一些信息,然后使用数学算法生成注册码。用户得到注册码后,经过逆运算得到的结果跟自己提供的信息对比,从而确定软件注册码的合法性。因为采集的用户信息类型不同,所以就有了多种类型的注册码。2.1.1注册码保持不变注册码保持不变就是说不管是哪个用户在哪个台电脑上都能注册,整个软件的安全性寄托在注册码本身的保密上,只要注册码泄漏了,所有人都可以注册该软件。早期的软件保护都采用一串复杂的字符串作为注册码,因为当时的网络并不发达,加上注册码本身难于记忆,所以个人所拥有的注册码一般情况下,是不容易被大量用户非法盗用的。随着时间的推移,网络逐渐普及,覆盖面越来越广,早期软件保护防盗的方法面临前所未有的挑战,只要有一个人把自己一款软件的合法注册码发布在网上,其他使用该软件的用户就能很容易的利用搜索引擎找到此注册码,成功的注册自己的软件,而无需支付相应的费用,这给软件开发商造成了巨大的损失。现在已经很少有人使用注册码保持不变的方法保护软件,此方法已经慢慢淡出了人们的视线。2.1.2注册码因输入信息而异这是传统的注册码保护方法,根据用户输入的不同信息(如用户名)产生注册码,这种方法产生的注册码和用户的信息存在简单的对应机制,安全性极差,只要“用户名”和“注册码”泄漏就可以无限制地在任何计算机上注册使用。网络上大量的“注册用户”和“注册码”使软件的保护形同虚设[4]。注册码保持不变的方法失利之后,软件保护行业亟需一种有效地保护方法,于是在原来的方法上改进为使用注册时输入的信息和注册码对应的方式保护软件,防止盗用,因为生成注册码时时用户输入的用户名只有用户自己知道,因此,就算是本软的某个注册码被别人知道了,但是不知道与这个注册码对应的用户名,同样还是不能注册成功。所以整个软件的安全全部寄托在了用户对自己信息的保密程度,只要某个用户把自己的注册码和用户名公开,或是黑客通过木马获取到了相关信息,那么其他人就可以用这些信息成功的注册该软件。2.1.3注册码因用户计算机而异根据用户计算机各种软硬件信息:如CPUID、分区卷标、硬盘大小、硬盘物理序列号、网卡号等等。通过这些信息可以将任意两台机器区分出来,从而可以生成一段唯一的序列号。这些信息中有的是不可取的,例如分区卷标这种不稳定信息,因其仅与软件系统有关。而有一些是无法得到的,例如当机器中没有网卡时或早于PentiumIII型号的CPU,网卡号和CPUID就得不到了[5]。网络的普及,因一个注册码泄漏而可以无限制的注册该软件的问题越发突出,软件开发商为了能保护自己的合法权益,开发出了一套新的软件保护方法,这也是现阶段最主要的保护方式,因计算机不同而生成不同的注册码。这种注册码一般都是与本机的相关的具有唯一性的一种或多种物理信息,这种物理信息是出厂时就确定了的,一般是固化在了计算机内部,不能修改,因此生成的注册码即使是发布在了网上,别的人还是无法使用该注册码注册自己的软件,因为自己的计算机硬件的相关信息和本注册码不相关。有了这种全新的软件保护方式,软件开发商就能在网络环境中很容易的保护自己的利益,避免软件被非法盗版。2.2注册机信息采集技术注册机信息采集技术是指利用计算机软件技术,针对计算机相关软硬件信息进行采集保存,从而为各种信息服务系统提供数据输入的整个过程。硬件信息包括CPUID、网卡物理地址(MAC)、硬盘的相关物理信息例如硬盘物理序列号等等。这些硬件物理信息有些可以通过windows提供的API函数直接获取,有些需要自己编写相关的函数,而且在windows下,必须编写一个驱动程序或通过一定的技术手段获取,例如,硬盘信息的获取操作,需要运行在Ring0级别,而正常情况,windows的应用程序是运行在Ring3级的,因此在获取硬盘物理信息前,必须通过一定的技术方法进入windows的Ring0级。2.2.1网卡的物理地址(MAC)获取MAC(MediaAccessControl,介质访问控制)MAC地址是烧录在NetworkInterfaceCard(网卡,NIC)里的。MAC地址,也叫硬件地址,是由48比特长(6字节),16进制的数字组成。0-23位叫做组织唯一标志符(organizationallyunique),是识别LAN(局域网)节点的标识,24-47位是由厂家自己分配,其中第40位是组播地址标志位。网卡的物理地址通常是由网卡生产厂家烧入网卡的EPROM(一种闪存芯片,通常可以通过程序擦写),它存储的是传输数据时真正赖以标识发出数据的电脑和接收数据的主机的地址。也就是说,在网络底层的物理传输过程中,是通过物理地址来识别主机的,它一般也是全球唯一的。比如,著名的以太网卡,其物理地址是48bit(比特位)的整数,如:44-45-53-54-00-00,以机器可读的方式存入主机接口中。以太网地址管理机构(除了管这个外还管别的)(IEEE)(IEEE:电气和电子工程师协会)将以太网地址,也就是48比特的不同组合,分为若干独立的连续地址组,生产以太网网卡的厂家就购买其中一组,具体生产时,逐个将唯一地址赋予以太网卡。形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。众所周知,一个网卡对应唯一MAC地址,对一些应用程序来说,获取网卡MAC地址有时是必要的,使用VC提供的NetBIOS网络编程接口可以方便获取网卡MAC地址。NetBIOS中所有的函数声明、常数等等均是在头文件nb30.h内定义的,nb30.h中一些类型在wtypes.h中定义,另外,若想使用NetBIOS,须连接的库是netapi.dll。2.2.2磁盘逻辑序列号获取硬盘的磁盘逻辑序列号的获取很简单,可直接调用windows的API函数GetVolumeInformation()获取硬盘的逻辑序列号[6]。该函数如下所示:GetVolumeInformation(
lpRootPathName:PChar;{磁盘驱动器代码字符串}
lpVolumeNameBuffer:PChar;{磁盘驱动器卷标名称}
nVolumeNameSize:DWORD;{磁盘驱动器卷标名称长度}
lpVolumeSerialNumber:PDWORD;{磁盘驱动器卷标序列号}
varlpMaximumComponentLength:DWORD;{系统允许的最大文件名长度}
varlpFileSystemFlags:DWORD;{文件系统标识}
lpFileSystemNameBuffer:PChar;{文件操作系统名称}
nFileSystemNameSize:DWORD{文件操作系统名称长度}
):BOOL;采用注册码的保护方式,最好是一机一码,即注册码与机器特征相关,这样一台机器上的注册码就无法在另外一台机器上使用,可以防止有人散播注册码,然而硬盘逻辑序列号用相关工具可以修改其值,所以使用逻辑序列号不安全。2.2.3磁盘物理序列号获取硬盘的序列号是厂家设定的,且只能用I/O指令读取,所以,这在以前的DOS时根本不是什么问题,方法非常简单,如下面的代码所示:
staticintWaitIde(){
intal;
while((al=inp(0x1F7))>=0x80);
returnal;
}
staticvoidReadIDE(){
intal;
inti;
WORDpw[256];
WaitId();
outp(0x1F6,0xA0);
al=WaitIde();
if((al&0x50)!=0x50)return;
outp(0x1F6,0xA0);
outp(0x1F7,0xEC);
al=WaitIde();
if((al&0x58)!=0x58)return;
for(i=0;i<256;i++){
pw[i]=inpw(0x1F0);
}
}
至此,关于IDE硬盘的信息已经在pw数组中了,需要注意的是该数组是一个WORD类型,硬盘的序列号存放于pw[10]开始的10个WORD中,使用时需要将每个WORD的高低字节颠倒一下。真正有点麻烦的是在Windows95/98下,I/O指令作为特权指令在应用程序级别,即Ring3是不可使用的,所以上面的代码在执行到WaitIde()时会陷到死循环中,原因就是IN0x1F7总是返回0xFF容易想到的解决办法是写一个VxD,因为VxD运行Ring0级别上,即最高特权级上,所以所有的指令都是可用的,硬盘物理序列号的获取需要使用特权指令,要进入Ring0特权级常用的还有两种方法:1)中断陷入技术;2)通过WindowsAPI函数DeviceInControl调用Smartvsdvxd。其中第一种方法相对简单实用,但不能取得NT下的Ring0级,因为NT下得不到中断向量表,本文只介绍第一种方法的实现机制。计算机操作系统都有一个中断描述表(IDT),该表有IDTR寄存器指向。矢量号作为IDT表的索引,从IDT表中获取一个8字节的门描述符。在门中包含48位的全指针及占用了16位的属性。48位的全指针包含32位的偏移量及16位的选择子。这里的偏移量分为两个部分存放。全指针的选择子部分存放在m+2及m+3字节,偏移量的低16位存放在m及m+1字节,高16位存放在m+6及m+7字节。在门描述符中,属性位存放在m+4及m+5字节。P为存在位,P=1表示门有效,P=0表示门无效,使用无效门将引起异常。DPL为描述符特权级,定义与门相联系的特权级。门的DPL只在INTn及INTO时进行检查,以避免应用程序执行INTn时,使用了各种设备在中断表中使用的矢量号。对于所有其它的异常或中断,忽略门DPL。DT为DType位,用于区分储存段(DT=1)及非储存段(及系统段或门,DT=0)。我们现在讨论的是门描述符,故此处有DT=0。Type为四位类型字段,用于定义门的类型:5为任务门;6为286中断门;7为286陷阱门;14为386中断门;15为386陷阱门。我们利用重新定义门描述符的偏移量将自己的程序放入中断中,通过执行中断从而得到Ring0级的权限来读到硬盘序列号[7]。2.3常用的软件保护技术介绍2.3.1时间限制定时器
有些程序的试用版每次运行都有时间限制,例如运行10分钟或20分钟就停止工作,必须重新运行该程序才能正常工作。这些程序里面自然有个定时器来统计程序运行的时间。
1)使用Settimer()
常用的计数器是函数Settimer(),调用这个函数创建的定时器可以发出消息VM_TIMER,或者在定时期满时调用一个回调函数。使用这个函数会使时间延时,精度不高。
2)使用timeSetEvent()
给Windows驱动程序最精确的周期性通知是由Windows的多媒体服务timeSetEvent()提供的。它的时间可以精确到1毫秒。
3)使用VXD
可以使用VMM的Set_Global_time_Out()服务来迫使回调函数的几个毫秒再执行,这就创造了一个“只有一次”的定时器。VXD可以在回调中再次调用Set_Global_time_Out()来开始下一个定时器,这样提供了一个连续运行的定时器了。4)其它
GetTickCount():精度不高;timeGetTime():可以以毫秒级返回windows开始后的时间。
时间限制
一般这类保护的软件都有时间上的限制,如试用30天等,当过了共享软件的试用期后,就不予运行,只有向软件作者付费注册之后才能得到一个无时间限制的注册版本。这种类型程序很多,让你有10天、20天、30天等,它们在安装时,在你的系统某处做上时间标记,每次运行时用当前系统时间和安装时的时间比较,判断你还否能使用。如最典型的30天限制的一种情况:
movecx,1E;把1E(30天十进制)放入ecx
moveax,[esp+10];把用过天数放到eax
cmpeax,ecx;在此比较
如碰到这种情况,只需把moveax,[esp+10]改成moveax,1。
要记住当前年份、月份的十六进制的一些表示方法,如:2000年的十六进制是07D0,然后用W32DASM反汇编你的程序,用查找字符串的方法找D007(在机器码中位置颠倒了一下)或其它类似时间的数字,有可能会找到有价值的线索。你别小看这种方法,对那些没怎么防范的程序,此招很有效。如:一程序限定在2000年使用,可能有如下一代码::00037805817C2404D0070000cmpdwordptr[esp+04],000007D0比较是否在2000年。
1)GetSystemTime得当前系统时间
在一个SYSTEMTIME中载入当前系统时间,这个时间采用的是“协同世界时间”(即UTC,也叫做GMT)格式。
VOIDGetSystemTime(LPSYSTEMTIMElpSystemTime);//随同当前时间载入的结构。
2)GetLocalTime得当前本地时间
VOIDGetLocalTime(LPSYSTEMTIMElpSystemTime);//用于装载本地时间的结构。
3)SystemTimeToFileTime根据一个FILETIME结构内容,载入一个SYSTEMTIME
BOOLSystemTimeToFileTime(CONSTSYSTEMTIME*lpst,LPFILETIMElpft);//包含了系统时间信息的一个结构。
//用于装载文件时间的一个结构。4)SetTimer创建一定时器,在指定时间内暂停
UINTSetTimer(HWNDhwnd,UINTidtimer,UINTuTimeout,TIMERPROCtmprc);
//时间信息句柄。
//定时器ID标识符。
//暂停时间。
//处理定时过程的程序入口地址。一般这类保护的软件都有时间上的限制,如试用30天等,当过了共享软件的试用期后,就不予运行,只有向软件作者付费注册之后才能得到一个有(或无)时间限制的注册版本。使用时间限制技术时,不要依赖于GetLocalTime()、GetSystemTime()这样众所周知的函数来获取系统时间,可以通过读取关键的系统文件的修改时间来得到系统时间的信息。2.3.2KeyFile保护KeyFile(注册文件)是一种利用文件来注册软件的保护方式。KeyFile一般是一个小文件,可以是纯文本文件,也可以是包含不可显示字符的二进制文件,其内容是一些加密过或未加密的数据,其中可能有用户名、注册码等信息。文件格式则由软件作者自己定义。采用keyfile的保护方式时,keyfile的尺寸不能太小,可将其结构设计得比较复杂,在程序中不同的地方对keyfile的不同部分进行复杂的运算和检查。试用版软件没有注册文件,当用户向作者付费注册之后,会收到作者寄来的注册文件,其中可能包含用户的个人信息。用户只要将该文件放入指定的目录,就可以让软件成为正式版。该文件一般是放在软件的安装目录中或系统目录下。软件每次启动时,从该文件中读取数据,然后利用某种算法进行处理,根据处理的结果判断是否为正确的注册文件,如果正确则以注册版模式来运行[8]。2.3.3CD-CHECK简单也最常见的光盘保护就是程序在启动时判断光驱中的光盘上是否存在特定的文件,如果不存在则认为用户没有正版光盘,拒绝运行。在程序运行的过程当中一般不再检查光盘的存在与否。Windows下的具体实现一般是这样的:先用GetLogicalDriveStrings()或GetLogicalDrives()得到系统中安装的所有驱动器的列表,然后再用GetDriveType()检查每一个驱动器,如果是光驱则用CreateFileA()或FindFirstFileA()等函数检查特定的文件存在与否,并可能进一步地检查文件的属性、大小、内容等。这种光盘检查是比较容易被破解的,解密者只要利用上述函数设断点找到程序启动时检查光驱的地方,修改判断指令就可以跳过光盘检查[9]。2.4软件保护总结本节将给出关于软件保护的一般性建议,这些都是无数人经验的总结。程序员在设计自己的保护方式时最好能够遵守这里给出的准则,这样会提高软件的保护强度。1)软件最终发行之前一定要将可执行程序进行加壳/压缩,使得解密者无法直接修改程序。如果时间允许并且有相应的技术能力,最好是设计自己的加壳/压缩方法。如果采用现成的加壳工具,最好不要选择流行的工具,因为这些工具已被广泛深入地加以研究,有了通用的脱壳/解压办法。另外,最好采用两种以上的不同的工具来对程序进行加壳/压缩,并尽可能地利用这些工具提供的反跟踪特性。2)增加对软件自身的完整性检查。这包括对磁盘文件和内存映像的检查,以防止有人未经允许修改程序以达到破解的目的。DLL和EXE之间可以互相检查完整性。3)所有与软件保护相关的字符串都不能以明文形式直接存放在可执行文件中,这些字符串最好是动态生成。尽可能少地给用户提示信息,因为这些蛛丝马迹都可能导致解密者直接深入到保护的核心。比如,当检测到破解企图之后,不要立即给用户提示信息,而是在系统的某个地方做一个记号,随机地过一段时间后使软件停止工作,或者装作正常工作但实际上却在所处理的数据中加入了一些垃圾。4)将注册码、安装时间记录在多个不同的地方。检查注册信息和时间的代码越分散越好。不要调用同一个函数或判断同一个全局标志,因为这样做的话只要修改了一个地方则全部都被破解了。在检查注册信息的时候插入大量无用的运算以误导解密者,并在检查出错误的注册信息之后加入延时。5)如果试用版与正式版是分开的两个版本,且试用版的软件没有某项功能,则不要仅仅使相关的菜单变灰,而是彻底删除相关的代码,使得编译后的程序中根本没有相关的功能代码。2.5本章小结本章主要介绍了序列号保护机制,注册机信息采集技术,其中详细介绍了硬盘物理序列号的获取和一些其它的软件保护技术,通过对比分析,每种算法都有自己的优势,具体使用哪种算法要根据问题的需求,最终本设计选用硬盘物理序列生成注册码的方法。采用硬盘物理序列号生成注册码的保护方式,最好的优势是一机一码,即注册码与机器特征相关,这样一台机器上的注册码就无法在另外一台机器上使用,能有效地防止软件盗版的问题。
3加密算法介绍3.1DES算法3.1.1DES算法原理数据加密算法(DataEncryptionAlgorithm,DEA)的数据加密标准(DataEncryptionStandard,DES)是规范的描述,它出自IBM的研究工作,并在1977年被美国政府正式采纳。它是一种对称加密算法,很可能是使用最广泛的密钥系统,特别是在保护金融数据的安全中,最初开发的DES是嵌入硬件中的。通常自动取款机(AutomatedTellerMachine,ATM)都使用DES。
DES使用一个56位的密钥以及附加的8位奇偶校验位,产生最大64位的分组大小。这是一个迭代的分组密码,使用称为Feistel的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES使用16个循环,使用异或,置换,代换,移位操作四种基本运算。3.1.2DES算法的应用误区DES算法加密与解密均工作中。唯一需要避免的是:在应用中,避开使用Key的第8,1664位作为有效数据位,从而便避开DES算法在应用中的误区。避开DES算法应用误区的具体操作在DES密钥Key的使用、管理及密钥更换的过程中,应绝对避开DES算法的应用误区,即:绝对不能把Key的第8,16,2464位作为有效数据位,来对Key进行管理。这一点,特别推荐给金融银行界及非金融业界的领导及决策者们,尤其是负责管理密钥的人,要对此点予以高度重视。有的银行金融交易网络,利用定期更换DES密钥Key的办法来进一步提高系统的安全性和可靠性,如果忽略了上述应用误区,那么,更换新密钥将是徒劳的,对金融交易网络的安全运行将是十分危险的,所以更换密钥一定要保证新Key与旧Key真正的不同,即除了第8,16,24,...64位外其它位数据发生了变化,请务必对此保持高度重视[10]!3.2MD5算法3.2.1MD5算法原理MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。大家都知道,地球上任何人都有自己独一无二的指纹,这常常成为公安机关鉴别罪犯身份最值得信赖的方法;与之类似,MD5就可以为任何文件(不管其大小、格式、数量)产生一个同样独一无二的“数字指纹”,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”都会发生变化。
我们常常在某些软件下载站点的某软件信息中看到其MD5值,它的作用就在于我们可以在下载该软件后,对下载回来的文件用专门的软件(如WindowsMD5Check等)做一次MD5校验,以确保我们获得的文件与该站点提供的文件为同一文件。利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、系统文件安全等方面。3.2.2MD5算法的应用MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方。如在UNIX系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来Hash值就行了[11]。3.3RSA算法3.3.1RSA算法原理密钥对的产生:选择两个大素数p和q计算:
n=p*q
然后随机选择加密密钥e,要求e和(p-1)*(q-1)互质。最后,利用Euclid算法计算解密密钥d,满足:
e*d=1(mod(p-1)*(q-1))
其中n和d也要互质。数e和n是公钥,d是私钥。两个素数p和q不再需要,应该丢弃,不要让任何人知道。
加密信息m(二进制表示)时,首先把m分成等长数据块m1,m2,...,mi,块长s,其中2^s<=n,s尽可能的大。对应的密文是:
ci=mi^e(modn)(a)
解密时作如下计算:
mi=ci^d(modn)(b)
RSA可用于数字签名,方案是用(a)式签名,(b)式验证。具体操作时考虑到安全性和m信息量较大等因素,一般是先作HASH运算[12]。3.3.2RSA的安全性RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何,而且密码学界多数人士倾向于因子分解不是NPC问题。RSA的缺点主要有:1)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。2)分组长度太大,为保证安全性,n至少也要600bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET(SecureElectronicTransaction)协议中要求CA采用2048比特长的密钥,其他实体使用1024比特的密钥。
这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:RonRivest,AdiShamir和LeonardAdleman。但RSA的安全性一直未能得到理论上的证明。RSA的安全性依赖于大数分解。公钥和私钥都是两个大素数(大于100个十进制位)的函数。据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积。3.3.3RSA的速度由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,无论是软件还是硬件实现。速度一直是RSA的缺陷。一般来说只用于少量数据加密。RSA的选择密文攻击。RSA在选择密文攻击面前很脆弱。一般攻击者是将某一信息作一下伪装(Blind),让拥有私钥的实体签署。然后,经过计算就可得到它所想要的信息。实际上,攻击利用的都是同一个弱点,即存在这样一个事实:乘幂保留了输入的乘法结:(XM)^d=X^d*M^dmodn
前面已经提到,这个固有的问题来自于公钥密码系统的最有用的特征--每个人都能使用公钥。但从算法上无法解决这一问题,主要措施有两条:一条是采用好的公钥协议,保证工作过程中实体不对其他实体任意产生的信息解密,不对自己一无所知的信息签名;另一条是决不对陌生人送来的随机文档签名,签名时首先使用One-WayHashFunction对文档作HASH处理,或同时使用不同的签名算法。在中提到了几种不同类型的攻击方法。3.4本章小结本章详细介绍了当前比较流行的几种加密算法,使我们对加密解密有了更深入的了解,从中我们可以看出各种加密算法的安全性,速度,和适用的条件,以便针对不同的问题使用不同的加密算法。那我们在实际使用的过程中究竟该使用哪一种比较好呢?我们应该根据自己的使用特点来确定,由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。对称加密算法不能实现签名,因此签名只能非对称算法。由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。如果在选定了加密算法后,那采用多少位的密钥呢?一般来说,密钥越长,运行的速度就越慢,应该根据的我们实际需要的安全级别来选择,一般来说,RSA建议采用1024位的数字,如果有更高的保密要求,可采用2048位数字。通过比较分析,本设计决定使用RSA加密算法加密生成注册码,虽然RSA算法没有DES算法速度快,但是RSA加密解密使用不同的非对称密钥这是它的优势。本设计注册码的生成是在注册机上完成的,注册码的验证在客服端程序上,客户端程序段中含有解密时使用的密钥,如我们使用DES对称密钥算法加密,破解人员很容就能根据客服端程序写出自己的注册机,从而完成注册,在软件保护中,这是很不安全的。但我们使用RSA加密算法,这些问题就迎刃而解了,因为RSA算法的密钥对私钥和公钥是非对称的,客服端程序验证时使用公钥进行解密,注册机由开发商保管,注册机使用私钥加密生成注册码,破解者根据公钥推导出私钥在理论上是不可能的,开发商为了增大破解难度,还可以加长密钥的位数和分组的长度,这使得该软件在其生命周期内可以有效避免被人破解,非法使用。4系统详细设计及实现4.1开发环境介绍4.1.1VisualC++6.0介绍用VC6编写并处理的任何程序都与工程有关(都要创建一个与其相关的工程),而每一个工程又总与一个工程工作区相关联。实际上,VC6是通过工程工作区来组织工程及其各相关元素的,就好像是一个工作间(对应于一个独立的文件夹,或称子目录),以后程序所牵扯到的所有的文件、资源等元素都将放入到这一工作间中,从而使得各个工程之间互不干扰,使编程工作更有条理,更具模块化。最简单情况下,一个工作区中用来存放一个工程,代表着某一个要进行处理的程序(我们先学习这种用法)。但如果需要,一个工作区中也可以用来存放多个工程,其中可以包含该工程的子工程或者与其有依赖关系的其他工程。可看出,工程工作区就像是一个“容器”,由它来“盛放”相关工程的所有有关信息,当创建新工程时,同时要创建这样一个工程工作区,而后则通过该工作窗口来观察与存取此工程的各种元素及其有关信息。创建工程工作区之后,系统将创建出一个相应的工作区文件(.dsw),用来存放与该工作区相关的信息;另外还将创建出的其他几个相关文件是:工程文件(.dsp)以及选择信息文件(.opt)等。编制并处理C++程序时要创建工程,VC6已经预先为用户准备好了近20种不同的工程类型以供选择,选定不同的类型意味着让VC6系统帮着提前做某些不同的准备以及初始化工作(例如,事先为用户自动生成一个所谓的底层程序框架或称框架程序,并进行某些隐含设置,如隐含位置、预定义常量、输出结果类型等)。工程类型中,其中有一个为“MFCAppWizard(exe)”如图4.1所示,它是我们本设计要掌握的、用来编制具有可视化窗体界面运行C++程序的工程。图4.14.1.2MFC程序开发流程MFC介绍MFC,微软基础类(MicrosoftFoundationClasses),同VCL类似,是一种ApplicationFramework,随微软VisualC++开发工具发布。目前最新版本为9.0(截止2008年11月)。该类库提供一组通用的可重用的类库供开发人员使用。大部分类均从CObject直接或间接派生,只有少部分类例外。MFC应用程序的总体结构通常由开发人员从MFC类派生的几个类和一个CWinApp类对象(应用程序对象)组成。MFC提供了MFCAppWizard自动生成框架。Windows应用程序中,MFC的主包含文件为"Afxwin.h"。此外MFC的部分类为MFC/ATL通用,可以在Win32应用程序中单独包含并使用这些类。由于它的易用性,初学者常误认为VC++开发必须使用MFC。这种想法是错误的。作为ApplicationFramework,MFC的使用只能提高某些情况下的开发效率,只起到辅助作用,而不能替代整个Win32程序设计。MFC特点MFC,微软基础类(MicrosoftFoundationClasses),实际上是微软提供的,用于在C++环境下编写应用程序的一个框架和引擎,VC++是WinDOS下开发人员使用的专业C++SDK(SDK,StandardSoftWareDevelopKit,专业软件开发平台),MFC就是挂在它之上的一个辅助软件开发包,MFC作为与VC++血肉相连的部分(注意C++和VC++的区别:C++是一种程序设计语言,是一种大家都承认的软件编制的通用规范,而VC++只是一个编译器,或者说是一种编译器+源程序编辑器的IDE,WS,PlatForm,这跟Pascal和Delphi的关系一个道理,Pascal是Delphi的语言基础,Delphi使用Pascal规范来进行Win下应用程序的开发和编译,却不同于Basic语言和VB的关系,Basic语言在VB开发出来被应用的年代已经成了Basic语言的新规范,VB新加的Basic语言要素,如面向对象程序设计的要素,是一种性质上的飞跃,使VB既是一个IDE,又成长成一个新的程序设计语言),MFC同BC++集成的VCL一样是一个非外挂式的软件包,类库,只不过MFC类是微软为VC++专配的。MFC是WinAPI与C++的结合,API,即微软提供的WinDOS下应用程序的编程语言接口,是一种软件编程的规范,但不是一种程序开发语言本身,可以允许用户使用各种各样的第三方(如我是一方,微软是一方,Borland就是第三方)的编程语言来进行对WinDOS下应用程序的开发,使这些被开发出来的应用程序能在WinDOS下运行,比如VB,VC++,Java,Dehpi编程语言函数本质上全部源于API,因此用它们开发出来的应用程序都能工作在WinOS的消息机制和绘图里,遵守WinDOS作为一个操作系统的内部实现,这其实也是一种必要,微软如果不提供API,这个世上对Win编程的工作就不会存在,微软的产品就会迅速从时尚变成垃圾,上面说到MFC是微软对API函数的专用C++封装,这种结合一方面让用户使用微软的专业C++SDK来进行Win下应用程序的开发变得容易,因为MFC是对API的封装,微软做了大量的工作,隐藏了好多程序开发人员在Win下用C++&MFC编制软件时的大量内节,如应用程序实现消息的处理,设备环境绘图,这种结合是以方便为目的的,必定要付出一定代价(这是微软的一向作风),因此就造成了MFC对类封装中的一定程度的的冗余和迂回,但这是可以接受的。最后要明白MFC不只是一个功能单纯的界面开发系统,它提供的类绝大部分用来进行界面开发,关联一个窗口的动作,但它提供的类中有好多类不与一个窗口关联,即类的作用不是一个界面类,不实现对一个窗口对象的控制(如创建,销毁),而是一些在WinDOS(用MFC编写的程序绝大部分都在WinDOS中运行)中实现内部处理的类,如数据库的管理类等,学习中最应花费时间的是消息和设备环境,对C++和MFC的学习中最难的部分是指针,C++面向对像程序设计的其它部分,如数据类型,流程控制都不难,建议学习数据结构C++版。MFC是微软封装了的API。什么意思呢?windows作为一个提供功能强大的应用程序接口编程的操作系统,的确方便了许多程序员,传统的win32开发(直接使用windows的接口函数API)对于程序员来说非常的困难,因为,API函数实在太多了,而且名称很乱,从零构架一个窗口动辄就是上百行的代码。MFC是面向对象程序设计与Applicationframework的完美结合,他将传统的API进行了分类封装,并且为你创建了程序的一般框架。MFC是对WindowsAPI的封装,大大简化了我们的工作;学VC主要就是要学MFC,大约有100多个类,但常用的也就二三十个。应该象背4级单词一样将这些常用类搞懂;当然不要死记,要通过看帮助、看例子、动手练习来学会它们;而且,并非每个类的内部的所有函数都要学会,要日积月累。如果真的想成为高手,做个笔记本把自己认为重要的类、函数记下来,随时学习,也是很好的突击方法。MFC基于事件驱动的程序设计MFC是基于事件驱动的程序设计,事件的产生有操作输入设备,如键盘和鼠标;点击屏幕上可视的对象,如菜单、工具栏按钮、滚动条和对话框上的控件;来自Windows内部,如当一个后面的窗口显示到前面来时。基于事件驱动的程序模型如图4.2所示。程序开始程序开始消息源1消息源1捕获消息派发消息消息源2捕获消息派发消息消息源2 . .退出消息?处理消息N退出消息?处理消息消息源n 消息源n 程序结束Y 程序结束图4.2支持队列特征的消息驱动模型Windows程序的消息处理过程Windows程序的消息处理过程首先是application都有其对应的windowprocedure,当窗口显现出来以后,对窗口所做的操作就会作为消息传递给application,而application就用GetMessage()函数来接收,接着application则必须对消息进行分析,这使用TranslateMessage()来实现,接着application就要把分析后的消息传递给此application的windowprocedure,即lpfnWndProc所指定的处理过程,要使用DispatchMessage()来实现,而windowprocedure则会根据收到的消息作出具体的措施。到此为止已经形成了一个完整的消息处理循环,其形式如下所示:while(GetMessage(&Msg,NULL,0,0)){
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}这便是典型的windows应用程序的消息处理与传递机制。Windows程序和消息的基本流程如图4.3所示。开始执行开始执行初始化初始化从消息队列取得一个消息从消息队列取得一个消息是否本程序要处理的消息?是否本程序要处理的消息?当前消息是否“退出当前消息是否“退出”消息?处理消息默认处理终止执行 Y N默认处理终止执行图4.3Windows程序和消息的基本流程MFC(MicrosoftFoundationClass,微软基础类库)是基于Win32API的C++类库集,它提供了管理窗口、菜单、对话框等大量可重用代码,隐藏了程序设计中的许多复杂工作,是用户能够较为轻松地开发出标准的Wingdows应用程序。MFC按照C++类的层次形式进行组织,层次较高的类提供一般的功能,层次较低的类从层次较高的类派生而来,继承了高层次类的行为,实现更为具体的功能。MFC用C++类对大多数Win32API函数进行了封装,使程序员的开发工作变得更加容易。MFC提供的基于文档/视图(简称Doc/View)的应用程序开发模型,是将应用程序数据与用户界面元素分离的编程方法,使得更改其中一部分程序时不必大量更改另一部分程序。程序设计流程图本系统程序采用MFC编程,整个系统分为两个部分,软件使用方的客户端程序和软件开发方的注册机程序,客户端程序通过访问硬盘信息,获取硬盘物理序列号,然后通过E-mail等方式发给软件开发方,软件开发方通过自己的注册机把获取到的硬盘物理序列号加密生成注册码,加密使用RSA非对称加密算法的私钥K,软件开发方把生成的注册号R返回给软件使用者,软件使用方根据得到的注册码,通过使用RSA非对称加密算法的公钥p解密,把解密出来的字符串和本机的硬盘物理序列号进行对比匹配,若相同则注册成功,否则注册失败。整个流程图如图4.4所示。软件使用方 软件开发方私有密钥k模数n获取硬盘序列号S私有密钥k模数n获取硬盘序列号S公有密钥p模数nRSA加密算法公有密钥p模数nRSA加密算法注册号R注册号RRSA解密算法RSA解密算法解密值S解密值S匹配匹配注册失败否注册失败注册成功 是注册成功图4.4本系统设计流程图4.2大进制数及其运算类定义4.2.1大数类的详细描述RSA依赖大数运算,目前主流RSA算法都建立在512位到1024位的大数运算之上,所以我们在现阶段首先需要掌握1024位的大数运算原理。其优点是算法符合人们的日常习惯,易于理解。另一种思路是将大数当作一个二进制流进行处理,使用各种移位和逻辑操作来进行加减乘除运算,但是这样做代码设计非常复杂,可读性很低,难以理解也难以调试。于是选取了一种介于两者之间的思路:将大数看作一个n进制数组,对于目前的32位系统而言n可以取值为2的32次方,即0x100000000,假如将一个1024位的大数转化成0x100000000进制,它就变成了32位,而每一位的取值范围就不是0-1或0-9,而是0-0xffffffff。我们正好可以用一个无符号长整数来表示这一数值。所以1024位的大数就是一个有32个元素的unsignedlong数组。而且0x100000000进制的数组排列与2进制流对于计算机来说,实际上是一回事,但是我们完全可以针对unsignedlong数组进行“竖式计算”,而循环规模被降低到了32次之内,并且算法很容易理解。4.2.2大数类的类定义本设计在使用RSA算法加密时会遇到大整数的运算,VC++自带的数据结构无法满足1024位加密运算的需求,根据以上大数运算的原理,于是定义了一个大数类,使其能完成大整数的计算。自定义的大数CBigInt类为0x100000000进制,同时根据十进制的基本运算法则为大数类定义了基本的运算成员函数,例如加减乘除等等,具体定义见以下代码。classCBigInt{public:unsignedm_nLength; //大数在0x100000000进制下的长度。unsignedlongm_ulValue[BI_MAXLEN];//用数组记录大数在0x100000000进制下每一位的值。CBigInt();~CBigInt();/*****************************************************************基本操作与运算Mov,赋值运算,可赋值为大数或普通整数,可重载为运算符“=”Cmp,比较运算,可重载为运算符“==”、“!=”、“>=”、“<=”等Add,加,求大数与大数或大数与普通整数的和,可重载为运算符“+”Sub,减,求大数与大数或大数与普通整数的差,可重载为运算符“-”Mul,乘,求大数与大数或大数与普通整数的积,可重载为运算符“*”Div,除,求大数与大数或大数与普通整数的商,可重载为运算符“/”Mod,模,求大数与大数或大数与普通整数的模,可重载为运算符“%”*****************************************************************/voidMov(unsigned__int64A);voidMov(CBigInt&A);CBigIntAdd(CBigInt&A);CBigIntSub(CBigInt&A);CBigIntMul(CBigInt&A);CBigIntDiv(CBigInt&A);CBigIntMod(CBigInt&A);CBigIntAdd(unsignedlongA);CBigIntSub(unsignedlongA);CBigIntMul(unsignedlong
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 宠物饲料配方对宠物体重控制的贡献考核试卷
- 企业员工培训系统维护合同
- 2024师徒合作协议:针对性技艺传授与考核标准3篇
- 智能家居家居生活品质提升方案
- 2024年消防器材采购合同3篇
- 小麦种植农业生产效率评价考核试卷
- 天然气开采业的供应链优化与管理考核试卷
- 健身器材用户界面设计创新考核试卷
- 在线考试系统c语言课程设计
- 插齿机 课程设计
- 项目全周期现金流管理培训
- 生物化学实验智慧树知到答案章节测试2023年浙江大学
- 少儿美术教案课件-《美丽的枫叶》
- 中国传统文化剪纸PPT模板
- 高中家长给孩子寄语
- 药物警戒体系主文件(根据指南撰写)
- 2022重症医学科优质护理工作计划
- 系列压路机xmr30s40s操作保养手册
- 广州教科版六年级英语上册M1-6复习练习题(含答案)
- GB/T 24159-2022焊接绝热气瓶
- GB/T 37136-2018电力用户供配电设施运行维护规范
评论
0/150
提交评论