/

C# SDK (Software Development Kit) exe dll 防止反编译

加密工具 dotNET Reactor 是一款强大的 .NET 代码保护和授权管理系统,安全可靠、简单易用,主要用来帮助开发人员保护他们的 .NET 软件产品。开发人员从此不必担心如何保护他们的知识产权,可以将更多精力放在产品功能的开发上。
与代码混淆工具(Obfuscator)相比,.NET Reactor 可以完全阻止对 .NET 程序集(由 C#, VB.NET, Delphi.NET, J#, MSIL… 等语言编写)的反编译。通俗的讲,.NET Reactor 在破解者和您的 .NET 代码之间构建了强大的防破解保护屏障,生成一个基于 Windows 的而不是基于MSIL 的兼容格式文件。原始的 .NET 代码完整的封装在本地代码内,无论何时都不会释放到硬盘,对于破解者是不可见的,目前还没有任何工具可以反编译 .NET Reactor 保护过的程序集。

1.顺序安装

2.选择文件,选择加密项

单击 Main Assembly 右边的 Open,选择要加密的软件文件,exe 或 dll 都可以。
勾选 Quick Settings 下要加密的项,每项的含意如下:
  NecroBit:把程序集转为非托管代码;
  Native Exe File:生成本机 Exe 文件;
  Anti ILDASM:反编译;
  Obfuscation:混淆;
  Create Mapping File:创建地图文件;
  Anti Tampering:防篡改;
  String Encryption:加密字符;
  Compress & Encrypt Resources:压缩并加密资源;
  Control FlowObfuscation:混淆控制流。
通常勾选“NecroBit、Anti ILDASM、Obfuscation、Anti Tampering 和 String Encryption”,根据自己实际情况勾选

3.选择 Actions 菜单中的 Protect

则开始加密,加密完成后在源文件同目录下生成一个加密的文件,将此文件作为发布文件使用即可

生成了一个新得文件夹以 _Secure 结尾

新建两个VS C#工程test.sln 和 reactor.sln

test工程代码中初始化时,删除reactor.exe

生成test工程

用软件 dotNET_Reactor 设置,保存成 setting.nrproj

Reactor工程代码中实现以下功能,

1

2

3

4

5

d:

cd D:\software\C#反编译\.NET Reactor

dotNET_Reactor.exe -project debug\test.nrproj

copy Debug\AutoShim_Secure\AutoShim.exe Debug\AutoShim.exe /y

copy Debug\BBSChart_Secure\BBSChart.dll Debug\BBSChart.dll /y

编译运行Rector工程,运行Test.exe.

//

The fastest method of c# dll encryption Use the packing tool Virbox Protector, directly encrypt, Virbox Protector can perform performance analysis on dll, analyze the number of calls of each function, and choose a protection method for each function, such as: obfuscation/virtualization/fragmentation /code encryption, etc.; what are the characteristics of each encryption method?

Code Encryption (X86):

For x86 assembly code: a code self-modification technique (SMC) to protect the code. Encrypt and store the current code as ciphertext, store it, automatically decrypt and execute it when the program runs to the protected function, erase the code after execution, and decrypt the code wherever it runs. The code of memory integrity runs fast because it is a pure memory operation, and it is a cost-effective protection method. It is recommended to add all

Code Encryption (IL)

Protecting IL code for dotNet programs: a dynamic running method to decrypt protected code. Encrypt and store the current code as ciphertext, store it, automatically decrypt and execute when the program runs to the protected function, erase the code after execution, erase the code after execution, and decrypt the code wherever it runs,** *The original intermediate language instruction and memory integrity code cannot be obtained. Because it is a pure memory operation, it runs fast and is a cost-effective protection method. It is recommended to add all

compression

Compression software such as zip compresses the code and data segments. Because of the dynamic password, no tool can automatically unpack it, which is the key means to prevent decompilation and disassembly.

Code Obfuscation (IL):

Rewrite the names of various elements in the code, such as variables, functions, and classes, into meaningless names. For example, rewriting it into a single letter, or a short meaningless combination of letters, or even rewriting it into a symbol like "__" makes it impossible for readers to guess its purpose from the name.

a) Rewrite part of the logic in the code into a functionally equivalent, but less understandable form. For example, rewrite the for loop into a while loop, rewrite the loop into recursion, simplify intermediate variables, and so on.

b) 打乱代码的格式。比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。

c) 添加花指令,通过特殊构造的指令来使得反汇编器出错,进而干扰反编译工作的进行。

代码混淆器也会带来一些问题。主要的问题包括:· 被混淆的代码难于理解,因此调试除错也变得困难起来。开发人员通常需要保留原始的未混淆的代码用于调试。· 对于支持反射的语言,代码混淆有可能与反射发生冲突。· 代码混淆并不能真正阻止反向工程,只能增大其难度。因此,对于对安全性要求很高的场合,仅仅使用代码混淆并不能保证源代码的安全。

代码混淆的特点是安全度低、不会影响效率。

代码虚拟化:

针对X86代码: 是指将机器代码翻译为机器和人都无法识别的一串伪代码字节流;在具体执行时再对这些伪代码进行一一翻译解释,逐步还原为原始代码并执行。 这段用于翻译伪代码并负责具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。 由于虚拟机代码和虚拟机CPU的实现可以做到每次都是随机设计和随机执行 并且代码每次可以随机变化,包括一些逻辑上的等价变化可以参考硬件N个与非门NOT-AND实现各种逻辑门,算法和访问内存形式的变化,包括数学上的非等价变化,代码体积几乎可以膨胀达到100到10000倍,造成机器无法做算法还原到原有逻辑。

代码虚拟化的特点是:安全度中、不会影响效率。

代码碎片化

深思自主知识产权的最新技术:基于 LLVM 和 ARM 虚拟机技术,自动抽取海量代码移入 SS 内核态模块,极大的降低了使用门槛, 不再需要手动移植算法,可移植的算法从有限的几个增长到几乎无限多,支持的语言也不再限于 C, 这是加密技术的一次综合应用,效果上类似于将软件打散执行,让破解者无从下手。

安全度高、建议关键函数或调用加密锁方法;使用太多会影响效率

//

一、混淆类的工具(如Dotfuscator,但是可以通过ILSpy、Reflector等反编译哦,直接COPY代码也能运行)

二、加密类的工具(如MaxToCode,网上有相应的破解教程)

三、加壳类的工具(如Sixxpack,网上有相应的破解教程)

四、强签名(签名只是防止项目中的某一个DLL被篡改了,不能防止反编译或反射的哦)

上面那些工具的目的归结出来大约完成两个目的,一是不能看,二是不能调,当然,我们也是实现这两个目的,只是手段不同。

一、不能看:.NET DLL可以包含托管堆代码(可以被反编译的)与非托管堆代码(不能被反编译,要反编译也是更高层次的了,不在讨范围内),我们将核心逻辑代码置于非托堆代码中,由托管堆代码提供接口供外部调用,调用时将非托管代码通过.NET动态编译特性编译后返回执行结果。这样就保证了不能看。

二、不能调:我们在非托管代码中加入验证调用者来源功能,判断调用者的HASH值是不是与在非托管代码中约定的HASH值(发布时需要提前生成相关引用者的HASH值存于非托管代码,最后生成非托管代码的DLL放于安装包中)一致,如一致则通过执行返回结果,不一致则返回空。这样就解决了非合法来源不能调的问题。

此保护思路适用于有.net 源码加密、.net 源代码加密、.net 代码保护、.net dll加密、.net dll保护、.NET 产品保护、asp.net源码加密、asp.net 代码保护、asp.net dll保护、C# 代码保护、C# dll保护、VB.net 代码保护、VB.net dll保护需求的用户,能有效的保护.net源码及dll,达到.net 防止反编译、.net代码防止反编译、.net 防止破解、asp.net 防止反编译、asp.net 防止破解、C# 防止反编译、C# 防止破解、dll加密防止反编译、dll防止反编译、dll防止被调用、dll 防止别人调用、vb.net 防止反编译、vb.net 防止破解的效果。

常见工具
壳分为压缩壳(起压缩程序体积的作用,一般保护功能较弱)和加密壳(起保护软件不被破解作用,保护功能强,但现在的保护壳同样增加了压缩功能)
具体可以这么区分:

所有压缩壳:upx、AsPacK、NSpack等,或者利用这么理解,凡是压缩壳,一般都能用常用的几种方法搞定.
初级保护壳:yC、Softsentry、Visual Protect、PESHiELD、Armadillo Standard Protection、tELock、PESpin等
中级保护壳:Armadillo CopyMem-II、ASProtect V1.X、NTkrnl Protector、PE-Armor、Dongles、SVKProtect、Obsidium等
高级保护壳:EncryptPE、Private exe Protector、Armadillo Nanomites、ASProtect V2.X、EXECryptor、StarForce、SafeDisc、VMProtect、Themida等

加密保护软件:

VMProtect

VMProtect是新一代的软件保护实用程序,具有内置的反汇编程序,可与Windows和Mac OS X可执行程序配合使用,还可以链接编译器创建的MAP文件,以快速选择代码片段进行保护。
VMProtect的基本原则:通过使应用程序代码和逻辑非常复杂以进行进一步分析和破解,从而有效保护应用程序代码免受检查。VMProtect的主要软件代码保护机制适用于:虚拟化,变异和组合保护,涉及应用程序代码的突变以及随后的虚拟化。
VMProtect与其他软件保护程序的主要区别在于:它能够使用不同的方法保护代码的不同部分:部分代码可以虚拟化,另一部分进行模糊处理,使用组合方法保护关键片段。
VMProtect中使用的虚拟化方法的关键优势:

  1. 执行虚拟化代码片段的虚拟机嵌入到受保护应用程序的结果代码中——VMProtect保护的应用程序不需要第三方库或模块来运行。
  2. VMProtect允许使用多个不同的虚拟机来保护同一应用程序的不同代码片段——黑客必须分析多个虚拟机的体系结构。

网络评价:加密的安全级别非常高,破解难度很大,但是加密数据多,需要注意系统的性能。

Themida

Themida是先进的Windows软件保护系统,它被用于满足软件开发人员对于所开发应用程序安全保护的需求,使其远离被先进的逆向工程和软件破解的危险。
通过Themida,集中在软件保护器所具有的主要弱点,从而提供了解决这些问题的完整解决方案。Themida使用SecureEngine?保护技术,当以最高优先级运行时,实施前所未见的保护技术,以保护应用程序免受高级软件破解。
Themida的主要特点:

  • 检测/欺骗任何类型的调试器的反调试器技术
  • 受保护应用程序中的加密算法和密钥不同
  • 反API扫描程序技术
  • 先进的Mutator引擎
  • 高级API-Wrapping技术
  • 适用于任何Ring3和Ring0转储器的反内存转储器技术

网络评价:用好其虚拟机保护功能,将关键敏感代码用虚拟机保护起来,能很好提高强度。

WinLicense

WinLicense是一个功能强大的保护系统,专为希望保护其应用程序免受高级逆向工程和软件破解的软件开发人员而设计。WinLicense使用SecureEngine?保护技术,该技术能够以最高优先级运行其代码,以实现前所未有的保护技术; 这可以保护任何具有最高安全级别的应用程序。
WinLicense的主要特点:

  • 保护功能:WinLicense的主要目标是涵盖软件保护中的所有当前漏洞,例如过时的保护技术、操作系统限制执行等等。
  • 试用/许可功能:WinLicense提供最广泛的选项和功能,以便为应用程序创建试用版和注册版。WinLicense还提供自动处理所有可能情况的功能,例如应用程序到期,许可证损坏等
  • WinLicense专门用于解决当前许可证管理器的一些主要缺陷。


网络评价:WinLicense主要比多了一个协议,可以设定使用时间,运行次数等功能,两者核心保护是一样的

防破解工具VMProtect与Themida对比评测

VMProtect特色功能:

  • 软件注册与授权系统

    旗舰版的 VMProtect 可以为您的软件添加注册与授权系统,支持限制自由更新时间,设置序列号的有效期限,以及授权黑名单等常见功能。

  • 虚拟机加密特性

    VMProtect 支持变形和虚拟两种代码虚拟化方式,以及内存加密、输入表加密、调试器检测等常规加密方式。

  • 序列号解码

    VMProtect 支持锁定某一段特定代码使用序列号加密,在缺少正确序列号的情况下,代码总是处于加密状态。即使输入正确的序列号,该代码仍然只在 VM 虚拟机里运行,不会被从内存转储出来。您可以利用这一特性制作软件功能限制的版本。

  • 命令行版本

    专业版和旗舰版的 VMProtect 为您提供了命令行版本,支持脚本、序列号和其它所有的功能。

  • 捆绑 DLL 文件

    这是一个非常有用的功能,您可以将软件调用的 DLL 文件封装到主程序内部,这样就可以制作绿色软件,别人也无法看到您调用了哪些 DLL 文件。

Themida特色功能:

  • 多层的加密措施来保护程式的代码和资料。
  • 黑客工具的监测。
  • 以最高优先等级来启动代码,从来都没在电脑防御技术领域出现过。
  • 扰乱程式的运行代码,资料和APIs,使软件破解者无法对程式还原成原代码 。
  • 对于反汇编器和反编译器的保护 。
  • SDK为SecureEngine®和受保护的程式提供一个双向的沟通。
  • 阻止从内存转送到磁盘上的高级技术。
  • 完全自定义的保护选项和讯息。

这两款软件的共同点:

VMProtect和Themida在软件保护的范畴内都属于软加密的一类应用软件。它们都是使用了虚拟机技术,可以用虚拟机保护关键代码,加密指定的代码,将指定的源代码转换成为在虚拟机上运行的字节码,经过这样的扰乱和转换等保护手段,使得你的程序给破解者造成了极大的难度,甚至于至今为止还未有人公开声称能将其还原的。这也是这两款加壳保护软件风靡的原因了。

不同点:

对于这两款优秀的软件来说它们又有各自不同的特点。对Themida来说,Themida的开发围绕在一般软件保护层的主要弱点上,使它可以对这些问题提供一个完全的解决方案。Themida使用SecureEngine的保护技术。当它在最高优先等级的情形下运行的时候,它对抗高级软件破解所使用的是从来都未曾出现过的防御技术。SecureEngine可以击败所有现行用来破解受保护软件的破解工具。所以,它确保你受保护的软件只在安全的环境下运作。

而VMProtect的加密不依赖系统的任何特性,加密后的软件兼容几乎所有的 Windows 平台,无论是 32 位还是 64 位操作系统,DEP 和 UAC 也没有问题。VMProtect 可以生成并验证序列号,无论是手动还是自动生成都支持。序列号可以有时间或日期限制,也可以锁定到计算机硬件。

总结:

总的来说,两款软件都是十分优秀的加壳类保护软件,在业界都获得了不少开发者的信赖和拥护。但VMProtect和Themida还是有着些许不足:VMProtect加密后会稍微影响速度,Themida使用后生成的文件过大等等。不过相对来说VMProtect对于最底层的虚拟机加密技术的应用是很多保护软件都无法比拟的,毕竟VMProtect可以随意加密你的源代码也更易上手。而Themida难度稍大但加壳后的保护强度更加强大。

/

注册授权

领导说考虑授权机,先了解下授权机大概的原理:

参考软件正版验证原理? - 牧云的回答 - 知乎

正版原理就是通过一系列效验,给予目标机器正式授权。授权方式多种多样。正版与否的核心逻辑,大多都是一个判断:

如果(相关条件成立){ /*正版部分代码*/ } 否则{ /*授权失败,序列号错误*/ }

其他经典判断方法暂不提。

正版验证的方法:

低等:提取诸如MAC地址、计算机名等,再组合加密变换,或根据用户名进行计算所得;
中等:网络验证,服务器保存key列表,用户输入正版key后连接服务器检索验证,成功则返回正确标识,以及离线的data文件等;
高等:加密狗、驱动等。
在线不是必须的,一般大型软件和游戏均会提供多种激活方式,如喜闻乐见的windows和Adobe系列软件,不然欺负我们山区没网的孩子呢。任何软件理论上都能被破解,只是时间和成本问题,网络验证的一般破解方法:
1、去除验证代码,去掉未注册的提示窗口和标识,直接跳转到相应功能函数;
2、强制修改网络返回的错误标识为正确标识;
3、修改网络验证的地址为自己服务器地址(破解后二次出售用);
4、直接跟踪、逆向算法,写出注册机;
5、偷学对方程序思路,自己仿写.
因为要求是C++的,所以找了找

英语关键词搜索 C++ Authorization

Casbin · GitHub 
https://blog.csdn.net/stpeace/article/details/41598665 
根据磁盘或网卡创建软件License约束(c++)
Using Authorization in C++ - Win32 apps | Microsoft Docs

/

根据磁盘或网卡创建软件License约束(c++)

为了保护软件成果,通常会设置在使用软件时需要进行认证、鉴权、有效期的识别:

(1)对于在线系统通常的做法是设计与部署一个认证服务,软件链接登陆服务获得认证信息(License)实现,当然也可以一旦通过验证,将License本地存储使用。

(2)离线系统一般是通过绑定软件安装的机器或者发放序列号的方式控制。如果是绑定软件安装的机器需要在license申请前采集机器指纹(含CPU、硬盘、MAC地址等一种或者几种信息的加密数据)。机器指纹的加密算法一般是采用不可逆的加密算法,如MD5等。

另外更复杂的License创建策略会将控制的功能项编码、受限使用的控制信息、使用期限等信息加密放到license中,在软件运行过程中实时检测。大多商业系统或软件会采用license发放的时候用公钥加密,软件运行时通过私钥解密等方式实现。而很多为项目或某特定行业服务的工具软件大多使用机器指纹进行私钥加密/解密实现。

下面讲述根据磁盘或网卡创建软件License的方法,其采用对称式加密,即加密和解密使用同一个密钥,加密算法是自定义的,绝大多数个人工具、项目工具的开发都可以采用,对软件工具起到一定的保护作用。

(1)获取网卡或磁盘信息
bool CLicense::Create()
{
    source_flag = false;
 
#ifdef _WIN32
if (m_nMacType == 0) // 取网卡地址 
{
    DWORD m_dwNetCardCount = 0;
    PIP_ADAPTER_INFO m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
 
    DWORD dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
    if (dwRetVal == ERROR_BUFFER_OVERFLOW)
    {
        free(m_pAdapterInfo);
        m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
        dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
    }
 
    if (dwRetVal == NO_ERROR)
    {
        PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
        while (pAdapter)
        {
            TRACE("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
            TRACE("\tAdapter Desc: \t%s\n", pAdapter->Description);
            TRACE("\tAdapter Addr: \t%ld\n", pAdapter->Address);
            TRACE("\tIP Address: \t%s\n", pAdapter->IpAddressList.IpAddress.String);
            TRACE("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);
 
            TRACE("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
            TRACE("\t***\n");
            if (pAdapter->DhcpEnabled)
            {
                TRACE("\tDHCP Enabled: Yes\n");
                TRACE("\t\tDHCP Server: \t%s\n", pAdapter->DhcpServer.IpAddress.String);
                TRACE("\tLease Obtained: %ld\n", pAdapter->LeaseObtained);
            }
            else
                TRACE("\tDHCP Enabled: No\n");
 
            if (pAdapter->HaveWins)
            {
                TRACE("\tHave Wins: Yes\n");
                TRACE("\t\tPrimary Wins Server: \t%s\n", pAdapter->PrimaryWinsServer.IpAddress.String);
                TRACE("\t\tSecondary Wins Server: \t%s\n", pAdapter->SecondaryWinsServer.IpAddress.String);
            }
            else
                TRACE("\tHave Wins: No\n");
 
            pAdapter = pAdapter->Next;
            m_dwNetCardCount++;
        }
    }
    else
    {
        free(m_pAdapterInfo);
        m_pAdapterInfo = NULL;
    }
 
    PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
    while (pAdapter)
    {
        sprintf(szMacAddress, "%02X-%02X-%02X-%02X-%02X-%02X", 
            pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], 
            pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);
 
        addr[0] = pAdapter->Address[0];
        addr[1] = pAdapter->Address[1];
        addr[2] = pAdapter->Address[2];
        addr[3] = pAdapter->Address[3];
        addr[4] = pAdapter->Address[4];
        addr[5] = pAdapter->Address[5];
 
        pAdapter = pAdapter->Next;
 
        source_flag = true;
        break;
    }
}
else // 取磁盘码 
{
    for (int i=0; i<5; i++)
    {
        memset(szMacAddress,0x00,sizeof(szMacAddress));
        if ((byMacAddrLen=GetHDSN(szMacAddress,i))>0)
        {
            source_flag = true;
            break;
        }
    }
}
#else
    /* implementation for Linux */
    int fd;
    if (m_nMacType == 0)    // 取网卡序列号
    {
        fd = socket(AF_INET, SOCK_DGRAM, 0);
        printf("socket fd is %d!\n",fd);
        if (fd == -1) {
            return source_flag;
        }
 
        char buf[1024];
        struct ifconf ifc;
        int ok = 0;
        ifc.ifc_len = sizeof(buf);
        ifc.ifc_buf = buf;
        ioctl(fd, SIOCGIFCONF, &ifc);
 
        struct ifreq *IFR = ifc.ifc_req;
        struct ifreq ifr;
 
        for (int i = ifc.ifc_len/sizeof(struct ifreq); --i >= 0; IFR++)
        {
            strcpy(ifr.ifr_name, IFR->ifr_name);
            if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) 
            {
                if (!(ifr.ifr_flags & IFF_LOOPBACK) && (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0))
                {
                    ok = 1;
                    break;
                }
            }
        }
        close(fd);
        if (ok)
        {
            bcopy(ifr.ifr_hwaddr.sa_data, addr, 6);
            source_flag = true;
        }else{
            printf("ifr.ifr_hwaddr.sa_data is NULL!\n");
        }
    }
    else    // 取磁盘码 added 2017.01.20
    {
        struct hd_driveid hd;
        int ok = 0;
        memset(szMacAddress,0x00,sizeof(szMacAddress));
        bool openf = true;
        if ((fd = open("/dev/hdc", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/hdb", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/sda", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/sdb", O_RDONLY|O_NONBLOCK)) < 0) 
        {
            printf("open /dev/hdc fail!\n");
            return source_flag;
        }
        
        if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
            //printf("Hard Disk Model: %.40s\n", hd.model);
            //printf("  Serial Number: %.20s\n", hd.serial_no);
            ok = 1;
        }
        if (ok)
        {
            sprintf(szMacAddress,"%.20s",hd.serial_no);
            byMacAddrLen = strlen(szMacAddress);
            source_flag = true;
        }else{
            printf("szMacAddress is NULL!\n");
        }
    }
#endif
    return source_flag;
}
 
// **********************************************************************************************************
// 取硬盘序列码
// **********************************************************************************************************
int CLicense::GetHDSN(char * szSN, int n) 
{
    //int done = -1;
    int ret = 0;
#ifdef _WIN32
    {
        char szHDName[512];
        sprintf_s(szHDName, "\\\\.\\PhysicalDrive%d", n);
        HANDLE hPhysicalDriveIOCTL = 0;
        hPhysicalDriveIOCTL = CreateFile (szHDName,
            GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
            NULL, OPEN_EXISTING, 0, NULL);
        if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
        {
            TRACE("\tCreateFile Ret : INVALID_HANDLE_VALUE\n");
            printf("CreateFile Return(INVALID_HANDLE_VALUE) and error(%d)\n", GetLastError());
        }
        else
        {
            GETVERSIONINPARAMS GetVersionParams;
            DWORD cbBytesReturned = 0;
            memset ((void*) & GetVersionParams, 0, sizeof(GetVersionParams));
            if ( ! DeviceIoControl (hPhysicalDriveIOCTL, SMART_GET_VERSION,
                NULL, 
                0,
                &GetVersionParams, sizeof (GETVERSIONINPARAMS),
                &cbBytesReturned, NULL) )
            {         
                ;
            }
            else
            {
                ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
                PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);
                //#define ID_CMD          0xEC            // Returns ID sector for ATA
                Command -> irDriveRegs.bCommandReg = 0xEC; //ID_CMD;
                DWORD BytesReturned = 0;
                if ( ! DeviceIoControl (hPhysicalDriveIOCTL,
                    SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
                    Command, CommandSize,
                    &BytesReturned, NULL) )
                {
                    ;
                } 
                else
                {
                    DWORD diskdata [256];
                    USHORT *pIdSector = (USHORT *)
                        /*(PIDENTIFY_DATA)*/ ((PSENDCMDOUTPARAMS) Command) -> bBuffer;
                    //printf("diskdata:\n");
                    for (int ijk = 0; ijk < 256; ijk++) {
                        diskdata[ijk] = pIdSector[ijk];
                        //printf("%ld ", diskdata[ijk]);
                    }
                    //printf("\n");
                    if(szSN)
                    {
                        int index = 0;
                        int position = 0;
                        for (index = 10; index <= 19; index++)
                        {
                            szSN [position++] = (char) (diskdata [index] / 256);
                            szSN [position++] = (char) (diskdata [index] % 256);
                        }
                        szSN[position] = '\0';
                        for (index = position - 1; index > 0 && isspace(szSN [index]); index--)
                            szSN [index] = '\0';
                    }
                    //done = TRUE;
                }
                CloseHandle (hPhysicalDriveIOCTL);
                free (Command);
                Command = NULL;
            }
        }
    }
    ret = static_cast<int>(strlen(szSN));
#else
    ;
#endif
    return ret;
}

(2)根据网卡或磁盘信息进行加密,加密算法可以自行根据需要调整,最好是不可逆的加密算法

bool CLicense::encrypt()
{
    if (!source_flag)
        return false;
    if (m_nMacType == 0) // 网卡地址加密
    {
        sprintf(szMacAddress, "%0X-%0X-%0X-%0X-%0X-%0X\n"
            , addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
        for (unsigned char b = 0; b < 6; b++) {
            addr[b] ^= 2 * (b + 1) + 0x88;
        }
 
        unsigned long dwCRC = GetLicense(&addr[0], 2) + (GetLicense(&addr[2], 4) << 16);
        sprintf(m_szLicense, "%u", dwCRC);
        for (unsigned int i = 0; i < strlen(m_szLicense); i++)
        {
            if (m_szLicense[i] <= '5') 
                m_szLicense[i] = m_szLicense[i] - '0' + 'A';
            else 
                m_szLicense[i] = m_szLicense[i] - '6' + '0';
        }
    }
    else // 硬盘序列码加密 
    {
        char buf[128] = { '\0' };
        for (int i = 0; i < byMacAddrLen && i < sizeof(m_szLicense); i++)
        {
            m_szLicense[i] = (u_char)GetLicense((u_char *)&szMacAddress[i], byMacAddrLen - i);
            if (m_szLicense[i] <= '5') 
                m_szLicense[i] = m_szLicense[i] - '0' + 'A';
            else 
                m_szLicense[i] = m_szLicense[i] - '6' + '0';
            char tmp[3] = { '\0' };
            sprintf(tmp, "%02X", (u_char)m_szLicense[i]);
            strncat(buf, tmp, strlen(tmp));
        }
        strncpy(m_szLicense, buf, (strlen(buf) >= MAX_LICENSE_SIZE) ? (MAX_LICENSE_SIZE - 1) : strlen(buf));
    }
    //printf("mac address %s ==> %s\n", szMacAddress, m_szLicense);
    return true;
};

(3)编程实现License工具,调用函数生成机器指纹(网卡信息或磁盘信息),根据机器指纹生成License

#include "License.h"
//软件License测试
int main(int argc, char *argv[])
{
    printf("Run ...\n");
    int license_mode=0;
    int encrypt_mode = 0;
    if (argc > 1)
    {
        sscanf(argv[1],"%d",&license_mode);
    }
    if (argc > 2)
    {
        sscanf(argv[2], "%d", &encrypt_mode);
    }
    printf("License mode is %s\n",(license_mode==0)?"NetCard":"Disk");
    
    CLicense sn;
    sn.SetMacAddrType(license_mode);
    switch (encrypt_mode)
    {
    case 0: //获取硬件信息
    {
        //获取
        if(!sn.Create())
            printf("CLicense Create fail!\n");
        //打印输出
        std::string strSn = sn.ToStringS();
        printf("strSn:%s\n", strSn.c_str());
        //向文件写入硬件信息
        sn.SerializeSource("sc.txt", true);
    }
        break;
    case 11: //根据硬件信息生成License
    {
        //从文件读取硬件信息
        sn.SerializeSource("sc.txt", false);
        //生成算法
        sn.encrypt();
        //打印输出
        std::string strSn = sn.ToString();
        printf("strSn:%s\n", strSn.c_str());
        //向文件写入License
        sn.Serialize("sn.txt", true);
    }
        break;
    default:
        printf("encrypt_mode is NULL\n");
        break;
    }
    return 0;
}

(4)在软件工具上进行验证,先读取License工具生成的License文件,与软件工具创建的License做校对

bool LicenseCheck()
{
    bool license_check = false;
#ifdef DEBUG //不做校对
    license_check = false;
#else
    license_check = true;
#endif
    bool bRet = !license_check;
    if (!bRet)
    {
        CLicense sn1;
        if (sn1.Serialize("sn.txt", false))
        {
            CLogger::createInstance()->Log(eTipMessage
                , "license:%s", sn1.ToString().c_str());
            CLicense sn;    // used netcard serial first
            if (sn.Create()&&sn.encrypt())
                bRet = (sn1 == sn);
            if (!bRet)
            {
                sn.SetMacAddrType(1); // used HD serial second
                if (sn.Create()&&sn.encrypt())
                    bRet = (sn1 == sn);
            }
        }
    }
 
    return bRet;
};
 
int main(int argc, char* argv[])
{
   if (!LicenseCheck()) {
        printf("license is error, please make sure software instance is right first!");
        exit(true);
    }
   //your code
}

总的来说,软件License创建就是根据机器指纹(磁盘、网卡、CPU等一种或多种信息),这些机器指纹信息具有惟一性和确定性,很好作为软件使用约束的依据,通过机器指纹生成License实现软件工具与机器绑定。如果是商用软件,最好采用不可逆的非对称式加密算法实现,即“公钥”和“私钥”配对使用。

附件给出本实例中软件License工具的全部代码,关于License的头文件及源码有些复杂,是因我还有兼顾其他用途,大家可以自行简化,希望能帮助到有需要的小伙伴。

CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (SoftWareLicense)
#
if(WIN32)
    message(STATUS "windows compiling...")
    add_definitions(-D_PLATFORM_IS_WINDOWS_)
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
else(WIN32)
    message(STATUS "linux compiling...")
    add_definitions( -D_PLATFORM_IS_LINUX_)
endif(WIN32)
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
    ${PROJECT_SOURCE_DIR}/common/License.h
    ${PROJECT_SOURCE_DIR}/common/ostype.h
  )
  
SET(source_cpp
    ${PROJECT_SOURCE_DIR}/common/License.cpp
    ${PROJECT_SOURCE_DIR}/src/main.cpp
  )
  
#头文件目录
include_directories(${PROJECT_SOURCE_DIR}/common)
# 指定生成目标
add_executable(SWL ${source_h} ${source_cpp})

src/main.cpp:

#include "License.h"
 
int main(int argc, char *argv[])
{
    printf("Run ...\n");
    int license_mode=0;
    int encrypt_mode = 0;
    if (argc > 1)
    {
        sscanf(argv[1],"%d",&license_mode);
    }
    if (argc > 2)
    {
        sscanf(argv[2], "%d", &encrypt_mode);
    }
    printf("License mode is %s\n",(license_mode==0)?"NetCard":"Disk");
    
    CLicense sn;
    sn.SetMacAddrType(license_mode);
    switch (encrypt_mode)
    {
    case 0: //获取硬件信息
    {
        //获取
        if(!sn.Create())
            printf("CLicense Create fail!\n");
        //打印输出
        std::string strSn = sn.ToStringS();
        printf("strSn:%s\n", strSn.c_str());
        //向文件写入硬件信息
        sn.SerializeSource("sc.txt", true);
    }
        break;
    case 11: //根据硬件信息生成License
    {
        //从文件读取硬件信息
        sn.SerializeSource("sc.txt", false);
        //生成算法
        sn.encrypt();
        //打印输出
        std::string strSn = sn.ToString();
        printf("strSn:%s\n", strSn.c_str());
        //向文件写入License
        sn.Serialize("sn.txt", true);
    }
        break;
    default:
        printf("encrypt_mode is NULL\n");
        break;
    }
    return 0;
}

common/License.h

#ifndef __SNFACTORY_H__
#define __SNFACTORY_H__
 
// ANSC C/C++
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
 
#define MAX_LICENSE_SIZE 32
 
class CLicense
{
public:
    CLicense();
    CLicense(const CLicense& other);
    bool operator !=(const CLicense& other);
    bool operator ==(const CLicense& other);
 
    bool Create();
    bool encrypt();
    bool SerializeSource(const char* strFile, bool bStoring);
    std::string ToStringS() const;
    bool Serialize(const char* strFile, bool bStoring);
    std::string ToString() const;
    // added 2010.11.15
    void SetMacAddrType(int mMacType){m_nMacType = mMacType;} // 设置取物理地址类型
private:
    bool string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div);
protected:
    bool source_flag;
    char szMacAddress[128];
    unsigned char addr[6];
    unsigned char byMacAddrLen;
    //
    char m_szLicense[MAX_LICENSE_SIZE];
    int GetHDSN(char * szSN, int n);
    int m_nMacType;
};
 
#endif  /*__SNFACTORY_H__*/

common/License.cpp:

#include "License.h"
 
#include "ostype.h"
 
#ifdef _WIN32
// === 增加硬盘序列码 ===
#include <Windows.h>
#include <winioctl.h>
#define SMART_GET_VERSION       CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
// ==================================
#include <Iphlpapi.h>
#pragma comment(lib, "Iphlpapi.lib")
#else
// linux
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
 
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>  // socket
#include <arpa/inet.h>
#include <sys/times.h>  // time
#include <sys/select.h> 
#include <sys/ioctl.h>
#include <net/if.h>
//#include <net/if_arp.h>
#include <linux/hdreg.h> //Drive specific defs
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdexcept>
#endif
 
//******************************************************************************************************
static unsigned short GetLicense(unsigned char* byData,unsigned short wLen)
{
    static const unsigned short crctable[256] = 
    {
        0x0000,0x365e,0x6cbc,0x5ae2,0xd978,0xef26,0xb5c4,0x839a,0xff89,0xc9d7,0x9335,0xa56b,0x26f1,0x10af,0x4a4d,0x7c13,
        0xb26b,0x8435,0xded7,0xe889,0x6b13,0x5d4d,0x07af,0x31f1,0x4de2,0x7bbc,0x215e,0x1700,0x949a,0xa2c4,0xf826,0xce78,
        0x29af,0x1ff1,0x4513,0x734d,0xf0d7,0xc689,0x9c6b,0xaa35,0xd626,0xe078,0xba9a,0x8cc4,0x0f5e,0x3900,0x63e2,0x55bc,
        0x9bc4,0xad9a,0xf778,0xc126,0x42bc,0x74e2,0x2e00,0x185e,0x644d,0x5213,0x08f1,0x3eaf,0xbd35,0x8b6b,0xd189,0xe7d7,
        0x535e,0x6500,0x3fe2,0x09bc,0x8a26,0xbc78,0xe69a,0xd0c4,0xacd7,0x9a89,0xc06b,0xf635,0x75af,0x43f1,0x1913,0x2f4d,
        0xe135,0xd76b,0x8d89,0xbbd7,0x384d,0x0e13,0x54f1,0x62af,0x1ebc,0x28e2,0x7200,0x445e,0xc7c4,0xf19a,0xab78,0x9d26,
        0x7af1,0x4caf,0x164d,0x2013,0xa389,0x95d7,0xcf35,0xf96b,0x8578,0xb326,0xe9c4,0xdf9a,0x5c00,0x6a5e,0x30bc,0x06e2,
        0xc89a,0xfec4,0xa426,0x9278,0x11e2,0x27bc,0x7d5e,0x4b00,0x3713,0x014d,0x5baf,0x6df1,0xee6b,0xd835,0x82d7,0xb489,
        0xa6bc,0x90e2,0xca00,0xfc5e,0x7fc4,0x499a,0x1378,0x2526,0x5935,0x6f6b,0x3589,0x03d7,0x804d,0xb613,0xecf1,0xdaaf,
        0x14d7,0x2289,0x786b,0x4e35,0xcdaf,0xfbf1,0xa113,0x974d,0xeb5e,0xdd00,0x87e2,0xb1bc,0x3226,0x0478,0x5e9a,0x68C4,
        0x8f13,0xb94d,0xe3af,0xd5f1,0x566b,0x6035,0x3ad7,0x0c89,0x709a,0x46c4,0x1c26,0x2a78,0xa9e2,0x9fbc,0xc55e,0xf300,
        0x3d78,0x0b26,0x51c4,0x679a,0xe400,0xd25e,0x88bc,0xbee2,0xc2f1,0xf4af,0xae4d,0x9813,0x1b89,0x2dd7,0x7735,0x416b,
        0xf5e2,0xc3bc,0x995e,0xaf00,0x2c9a,0x1ac4,0x4026,0x7678,0x0a6b,0x3c35,0x66d7,0x5089,0xd313,0xe54d,0xbfaf,0x89f1,
        0x4789,0x71d7,0x2b35,0x1d6b,0x9ef1,0xa8af,0xf24d,0xc413,0xb800,0x8e5e,0xd4bc,0xe2e2,0x6178,0x5726,0x0dc4,0x3b9a,
        0xdc4d,0xea13,0xb0f1,0x86af,0x0535,0x336b,0x6989,0x5fd7,0x23c4,0x159a,0x4f78,0x7926,0xfabc,0xcce2,0x9600,0xa05e,
        0x6e26,0x5878,0x029a,0x34c4,0xb75e,0x8100,0xdbe2,0xedbc,0x91af,0xa7f1,0xfd13,0xcb4d,0x48d7,0x7e89,0x246b,0x1235
    };
 
    unsigned short X = 0;
    for (unsigned short i = 0; i < wLen; i++)
        X = (X / 256) ^ (crctable[(X % 256) ^ byData[i]]) ;
    return (X ^ 0xffff);
}
 
//**********************************************************************************************************
CLicense::CLicense()
{
    source_flag = false;
    memset(szMacAddress, '\0', 128);
    memset(addr, '\0', 6);
    byMacAddrLen = 0;
    memset(m_szLicense, '\0', MAX_LICENSE_SIZE);
    m_nMacType = 0; // 缺省为取网卡地址
}
 
//**********************************************************************************************************
CLicense::CLicense(const CLicense& other)
{
 
}
 
//**********************************************************************************************************
bool CLicense::operator !=(const CLicense& other)
{
    bool b = strcmp(m_szLicense, other.m_szLicense) != 0;
    return b;
}
 
//**********************************************************************************************************
bool CLicense::operator ==(const CLicense& other)
{
    //printf("%s==%s\n", m_szLicense, other.m_szLicense);
    bool b = strcmp(m_szLicense, other.m_szLicense) == 0;
    return b;
}
 
//**********************************************************************************************************
bool CLicense::Create()
{
    source_flag = false;
 
#ifdef _WIN32
if (m_nMacType == 0) // 取网卡地址 
{
    DWORD m_dwNetCardCount = 0;
    PIP_ADAPTER_INFO m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
 
    DWORD dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
    if (dwRetVal == ERROR_BUFFER_OVERFLOW)
    {
        free(m_pAdapterInfo);
        m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
        dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
    }
 
    if (dwRetVal == NO_ERROR)
    {
        PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
        while (pAdapter)
        {
            TRACE("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
            TRACE("\tAdapter Desc: \t%s\n", pAdapter->Description);
            TRACE("\tAdapter Addr: \t%ld\n", pAdapter->Address);
            TRACE("\tIP Address: \t%s\n", pAdapter->IpAddressList.IpAddress.String);
            TRACE("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);
 
            TRACE("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
            TRACE("\t***\n");
            if (pAdapter->DhcpEnabled)
            {
                TRACE("\tDHCP Enabled: Yes\n");
                TRACE("\t\tDHCP Server: \t%s\n", pAdapter->DhcpServer.IpAddress.String);
                TRACE("\tLease Obtained: %ld\n", pAdapter->LeaseObtained);
            }
            else
                TRACE("\tDHCP Enabled: No\n");
 
            if (pAdapter->HaveWins)
            {
                TRACE("\tHave Wins: Yes\n");
                TRACE("\t\tPrimary Wins Server: \t%s\n", pAdapter->PrimaryWinsServer.IpAddress.String);
                TRACE("\t\tSecondary Wins Server: \t%s\n", pAdapter->SecondaryWinsServer.IpAddress.String);
            }
            else
                TRACE("\tHave Wins: No\n");
 
            pAdapter = pAdapter->Next;
            m_dwNetCardCount++;
        }
    }
    else
    {
        free(m_pAdapterInfo);
        m_pAdapterInfo = NULL;
    }
 
    PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
    while (pAdapter)
    {
        sprintf(szMacAddress, "%02X-%02X-%02X-%02X-%02X-%02X", 
            pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], 
            pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);
 
        addr[0] = pAdapter->Address[0];
        addr[1] = pAdapter->Address[1];
        addr[2] = pAdapter->Address[2];
        addr[3] = pAdapter->Address[3];
        addr[4] = pAdapter->Address[4];
        addr[5] = pAdapter->Address[5];
 
        pAdapter = pAdapter->Next;
 
        source_flag = true;
        break;
    }
}
else // 取磁盘码 
{
    for (int i=0; i<5; i++)
    {
        memset(szMacAddress,0x00,sizeof(szMacAddress));
        if ((byMacAddrLen=GetHDSN(szMacAddress,i))>0)
        {
            source_flag = true;
            break;
        }
    }
}
#else
    /* implementation for Linux */
    int fd;
    if (m_nMacType == 0)    // 取网卡序列号
    {
        fd = socket(AF_INET, SOCK_DGRAM, 0);
        printf("socket fd is %d!\n",fd);
        if (fd == -1) {
            return source_flag;
        }
 
        char buf[1024];
        struct ifconf ifc;
        int ok = 0;
        ifc.ifc_len = sizeof(buf);
        ifc.ifc_buf = buf;
        ioctl(fd, SIOCGIFCONF, &ifc);
 
        struct ifreq *IFR = ifc.ifc_req;
        struct ifreq ifr;
 
        for (int i = ifc.ifc_len/sizeof(struct ifreq); --i >= 0; IFR++)
        {
            strcpy(ifr.ifr_name, IFR->ifr_name);
            if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) 
            {
                if (!(ifr.ifr_flags & IFF_LOOPBACK) && (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0))
                {
                    ok = 1;
                    break;
                }
            }
        }
        close(fd);
        if (ok)
        {
            bcopy(ifr.ifr_hwaddr.sa_data, addr, 6);
            source_flag = true;
        }else{
            printf("ifr.ifr_hwaddr.sa_data is NULL!\n");
        }
    }
    else    // 取磁盘码
    {
        struct hd_driveid hd;
        int ok = 0;
        memset(szMacAddress,0x00,sizeof(szMacAddress));
        bool openf = true;
        if ((fd = open("/dev/hdc", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/hdb", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/sda", O_RDONLY|O_NONBLOCK)) < 0
            && (fd = open("/dev/sdb", O_RDONLY|O_NONBLOCK)) < 0) 
        {
            printf("open /dev/hdc fail!\n");
            return source_flag;
        }
        
        if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
            //printf("Hard Disk Model: %.40s\n", hd.model);
            //printf("  Serial Number: %.20s\n", hd.serial_no);
            ok = 1;
        }
        if (ok)
        {
            sprintf(szMacAddress,"%.20s",hd.serial_no);
            byMacAddrLen = strlen(szMacAddress);
            source_flag = true;
        }else{
            printf("szMacAddress is NULL!\n");
        }
    }
#endif
    return source_flag;
}
 
bool CLicense::encrypt()
{
    if (!source_flag)
        return false;
    if (m_nMacType == 0) // 网卡地址加密
    {
        sprintf(szMacAddress, "%0X-%0X-%0X-%0X-%0X-%0X\n"
            , addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
        for (unsigned char b = 0; b < 6; b++) {
            addr[b] ^= 2 * (b + 1) + 0x88;
        }
 
        unsigned long dwCRC = GetLicense(&addr[0], 2) + (GetLicense(&addr[2], 4) << 16);
        sprintf(m_szLicense, "%u", dwCRC);
        for (unsigned int i = 0; i < strlen(m_szLicense); i++)
        {
            if (m_szLicense[i] <= '5') 
                m_szLicense[i] = m_szLicense[i] - '0' + 'A';
            else 
                m_szLicense[i] = m_szLicense[i] - '6' + '0';
        }
    }
    else // 硬盘序列码加密
    {
        char buf[128] = { '\0' };
        for (int i = 0; i < byMacAddrLen && i < sizeof(m_szLicense); i++)
        {
            m_szLicense[i] = (u_char)GetLicense((u_char *)&szMacAddress[i], byMacAddrLen - i);
            if (m_szLicense[i] <= '5') 
                m_szLicense[i] = m_szLicense[i] - '0' + 'A';
            else 
                m_szLicense[i] = m_szLicense[i] - '6' + '0';
            char tmp[3] = { '\0' };
            sprintf(tmp, "%02X", (u_char)m_szLicense[i]);
            strncat(buf, tmp, strlen(tmp));
        }
        strncpy(m_szLicense, buf, (strlen(buf) >= MAX_LICENSE_SIZE) ? (MAX_LICENSE_SIZE - 1) : strlen(buf));
    }
    //printf("mac address %s ==> %s\n", szMacAddress, m_szLicense);
    return true;
};
 
bool CLicense::string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div)
{
    std::string _src = src;
    std::string::size_type _pos = _src.find(div);
    while (std::string::npos != _pos)
    {
        std::string _buf = "";
        _buf = _src.substr(0, _pos);
        _strlist.push_back(_buf);
        _src = _src.erase(0, _pos + div.size());
        _pos = _src.find(div.c_str());
    }
    if (!_src.empty()) {
        _strlist.push_back(_src);
    }
    return true;
};
 
bool CLicense::SerializeSource(const char* strFile, bool bStoring)
{
    if (bStoring)
    {
        // Save
        if (strlen(szMacAddress) > 0)
        {
            std::ofstream fLincese(strFile);
            fLincese.write(szMacAddress, strlen(szMacAddress));
            return true;
        }
    }
    else
    {
        // Read
        std::ifstream fLincese(strFile);
        fLincese.read(szMacAddress, MAX_LICENSE_SIZE);
        byMacAddrLen = static_cast<unsigned char>(strlen(szMacAddress));
        bool read_flag = byMacAddrLen > 0 ? true : false;
        bool map_flag = false;
        if (0 == m_nMacType) {
            std::vector<std::string> _strlist;
            if (string_divide(_strlist,std::string(szMacAddress),"-"))
            {
                try
                {
                    if (6 == _strlist.size()) {
                        for (int index = 0; index < 6; index++)
                        {
                            int n = 0;
                            for (int i = 0; i < 2; i++)
                            {
                                if (_strlist.at(index)[i] >= 'A'&&_strlist.at(index)[i] <= 'F')//十六进制还要判断他是不是在A-F或者a-f之间a=10。。
                                    n = _strlist.at(index)[i] - 'A' + 10;
                                else if (_strlist.at(index)[i] >= 'a'&&_strlist.at(index)[i] <= 'f')
                                    n = _strlist.at(index)[i] - 'a' + 10;
                                else
                                    n = _strlist.at(index)[i] - '0';
                                addr[index] = addr[index] * 16 + n;
                            }
                        }
                        map_flag = true;
                    }
                    else {
                        #ifdef WIN32
                        throw std::exception("MacAddress be split by \'-\' and size isn't 6");
                        #else
                        throw std::logic_error("MacAddress be split by \'-\' and size isn't 6");
                        #endif
                    }
                }
                catch (const std::exception& e)
                {
                    printf("error(%s) for SerializeSource\r\n",e.what());
                }
            }
        }
        else {
            map_flag = true;
        }
        source_flag = read_flag&&map_flag;
        return read_flag;
    }
 
    return false;
};
std::string CLicense::ToStringS() const
{
    std::string strName = szMacAddress;
    return strName;
};
 
//**********************************************************************************************************
bool CLicense::Serialize(const char* strFile, bool bStoring)
{
    if (bStoring)
    {
        // Save
        if (strlen(m_szLicense) > 0)
        {
            std::ofstream fLincese(strFile);
            fLincese.write(m_szLicense, strlen(m_szLicense));
            return true;
        }
    }
    else
    {
        // Read
        std::ifstream fLincese(strFile);
        fLincese.read(m_szLicense, MAX_LICENSE_SIZE);
        return strlen(m_szLicense) > 0;
    }
 
    return false;
}
 
//**********************************************************************************************************
std::string CLicense::ToString() const
{
    std::string strName = m_szLicense;
    return strName;
}
 
// **********************************************************************************************************
// 取硬盘序列码
// **********************************************************************************************************
int CLicense::GetHDSN(char * szSN, int n) 
{
    //int done = -1;
    int ret = 0;
#ifdef _WIN32
    {
        char szHDName[512];
        sprintf_s(szHDName, "\\\\.\\PhysicalDrive%d", n);
        HANDLE hPhysicalDriveIOCTL = 0;
        hPhysicalDriveIOCTL = CreateFile (szHDName,
            GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
            NULL, OPEN_EXISTING, 0, NULL);
        if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
        {
            TRACE("\tCreateFile Ret : INVALID_HANDLE_VALUE\n");
            printf("CreateFile Return(INVALID_HANDLE_VALUE) and error(%d)\n", GetLastError());
        }
        else
        {
            GETVERSIONINPARAMS GetVersionParams;
            DWORD cbBytesReturned = 0;
            memset ((void*) & GetVersionParams, 0, sizeof(GetVersionParams));
            if ( ! DeviceIoControl (hPhysicalDriveIOCTL, SMART_GET_VERSION,
                NULL, 
                0,
                &GetVersionParams, sizeof (GETVERSIONINPARAMS),
                &cbBytesReturned, NULL) )
            {         
                ;
            }
            else
            {
                ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
                PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);
                //#define ID_CMD          0xEC            // Returns ID sector for ATA
                Command -> irDriveRegs.bCommandReg = 0xEC; //ID_CMD;
                DWORD BytesReturned = 0;
                if ( ! DeviceIoControl (hPhysicalDriveIOCTL,
                    SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
                    Command, CommandSize,
                    &BytesReturned, NULL) )
                {
                    ;
                } 
                else
                {
                    DWORD diskdata [256];
                    USHORT *pIdSector = (USHORT *)
                        /*(PIDENTIFY_DATA)*/ ((PSENDCMDOUTPARAMS) Command) -> bBuffer;
                    //printf("diskdata:\n");
                    for (int ijk = 0; ijk < 256; ijk++) {
                        diskdata[ijk] = pIdSector[ijk];
                        //printf("%ld ", diskdata[ijk]);
                    }
                    //printf("\n");
                    if(szSN)
                    {
                        int index = 0;
                        int position = 0;
                        for (index = 10; index <= 19; index++)
                        {
                            szSN [position++] = (char) (diskdata [index] / 256);
                            szSN [position++] = (char) (diskdata [index] % 256);
                        }
                        szSN[position] = '\0';
                        for (index = position - 1; index > 0 && isspace(szSN [index]); index--)
                            szSN [index] = '\0';
                    }
                    //done = TRUE;
                }
                CloseHandle (hPhysicalDriveIOCTL);
                free (Command);
                Command = NULL;
            }
        }
    }
    ret = static_cast<int>(strlen(szSN));
#else
    ;
#endif
    return ret;
}

common/ostype.h:

#ifndef __OSTYPE_HH__
#define __OSTYPE_HH__
 
#ifdef _WIN32
#include <afx.h>
#define __WINDOWS__
#else
#define __LINUX__
#endif
 
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
 
#include <string>
#include <list>
#include <vector>
#include <queue>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <string.h>
#include <time.h>
#include <assert.h>
 
#ifdef __WINDOWS__
#include <sys/timeb.h>
#include <WinSock2.h>
#endif
 
#ifdef __LINUX__
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
 
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
//#include <sys/io.h>
#include <errno.h>
//#include <linux/if.h>
#include <net/if.h>
#define _atoi64(val) strtoll(val, NULL, 10)
#endif
 
#define _COMMONITOR
#define _BACK
 
typedef long long                INT64;
typedef unsigned long long        UINT64;
typedef unsigned char            BYTE;
typedef unsigned short            WORD;
typedef long                    LONG;
typedef unsigned long            DWORD;
typedef int                        BOOL;
typedef unsigned int            UINT;
 
#ifndef NULL
#define NULL 0
#endif
 
#ifndef TRUE
#define TRUE true
#endif
 
#ifndef FALSE
#define FALSE false
#endif
 
#ifdef UNICODE
typedef std::wstring XString;
#else
typedef std::string XString;
#endif
 
using namespace std;
 
#endif  /* __EXX_HH__ */

//

C# SDK exe dll 防止反编译相关推荐

  1. PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译

    ​ 在这里分享一些技巧和经验给大家.辛苦撰文分享,转载或引用请保留本文作者信息及文章链接. 作者的环境: win7+python3.5(anaconda3) 理论上,win7及以上的系统和python ...

  2. 超详细Pyinstaller打包exe+反编译Pyinstaller打包的exe教程+防止反编译教程

    在这里分享一些技巧和经验给大家.辛苦撰文分享,转载或引用请保留本文作者信息及文章链接. 作者的环境: win7+python3.5(anaconda3) 理论上,win7及以上的系统和python任意 ...

  3. java通过exe4j打包的exe文件的反编译

    通过exe4j打包的exe文件,在exe文件运行时,在AppData\Local\Temp目录下会生成*.jar文件,不运行exe文件时这些.jar文件是不存在的,我们可以通过对比文件来得到这些文件, ...

  4. Pyinstaller打包的exe之一键反编译py脚本与防反编译

    大家好,我是小小明,今天我将教大家如何反编译exe文件. 这次以最近写的一篇gui<Python一键自动整理归类文件,GUI窗口程序拿来即用>为例进行演示. 地址:https://blog ...

  5. 使用反编译工具反编译Dll,编译成C#

    今天刚刚开通博客,就迫不及待把今天遇到的一个问题写出来分享,呵呵! 这几天我需要对dll进行反编译,下面是我的步骤, 1 . 单击 http://xiazai.xiazaiba.com/Soft/R/ ...

  6. 初识Ildasm.exe——IL反编译的实用工具(转自Youngman)

    Ildasm.exe 概要: 一.前言: 微软的IL反编译实用程序--Ildasm.exe,可以对可执行文件(ex,经典的控制台Hello World 的 exe 可执行文件)抽取出 IL 代码,并且 ...

  7. Python反编译pyinstaller打包的exe文件 从0开始(未加密篇)

    因为pyinstaller方便.兼容性相对较好,所以我们会经常见到一些用pyinstaller打包的Python程序,在这里我们了解一下如何对这些打包好的exe文件进行反编译(即反编译出.py文件), ...

  8. jd-gui.exe反编译工具百度网盘下载

    jd-gui.exe是一个反编译工具,在没有src源码的情况下,通过它可以看到源码 链接:https://pan.baidu.com/s/1oxza0Ejp8Ku2nNHF3kZyiw  提取码:ce ...

  9. Java反编译工具JD-GUI.exe

    Java反编译工具JD-GUI.exe 以下是反编译工具下载地址 链接:https://pan.baidu.com/s/1pMe1trX 密码:pmke 一.运行JD-GUI.exe文件 二.将Jav ...

最新文章

  1. VirtualBox安装64位Linux
  2. 何恺明等人新作:效果超ResNet,利用NAS方法设计随机连接网络 | 技术头条
  3. 其实你做的大部分工作都是浪费
  4. PHP 通过随机数获得ASCII 值返回字符。
  5. 太空将成为数据中心冷却新前沿
  6. oracle10g rman备份有效性,验证RMAN备份的有效性
  7. 【STM32】 Keil介绍、下载、安装与注册
  8. 音视频技术开发周刊 | 220
  9. Android VNC Server New
  10. ansys本地的help文件_PostgreSQL本地/远程登陆配置
  11. python打包的exe反编译_python打包exe反编译源码
  12. cat3 utp是不是网线_CAT网线品种分类
  13. A870省电内核超频内核介绍及下载[七夕]
  14. 会写代码的CTO曹艳白曹总,智核创投创始人,给搜房贡献的第一个大数据方面的专利...
  15. 学习笔记:Java 并发编程①_基础知识入门
  16. 陆奇最新演讲高清PPT下载;AI 绘画20+工具体验汇总;我愿称MOSS为全球开源界最强;思否AIGC黑客马拉松北京站 | ShowMeAI日报
  17. 科大讯飞语音无限制录音、识别功能的实现:Android studio(一)
  18. android 实现刮刮乐刮奖效果
  19. css清除浮动的几种方式
  20. 头插法和尾插法的详细区别

热门文章

  1. 万拓存储数字校园存储解决方案
  2. 2022年熔化焊接与热切割考试试题及答案
  3. 【轻微课学画笔记】关于绘画中的一点透视
  4. 2022-2023级北京大学光华管理学院MBA招生简章
  5. 汽车总线系统网络学习之CAN总线入门
  6. Android 29及以上高版本获取SD外部存储器目录
  7. UnityHub使用方法教程和简介
  8. pyinstaller使用多帧ICO图标
  9. ubuntu20.04系统出现 仓库 “http://ppa.launchpad.net/fcitx-team/nightly/ubuntu xenial Release“ 没有Release文件
  10. 中国生态系统服务空间/食物生产、土壤保持、水源涵养、防风固沙、生物多样性、碳固定