软件使用权的控制---C/C++代码的实现

         有时候, 自己写了一个软件, 放到网上, 大家都可以使用。但是, 如果要控制别人的使用权, 该怎么办呢?  在本文中, 我们用一个极其简单的例子来说明控制机制。 当然, 如果你的软件写得够好, 有很大的客户需求, 搞一个使用权的控制机制, 说不定可以小小地赚一笔钱呢大笑

 

         我们把这个软件的名称定为Beauty.exe吧, 其源码是(下面的程序只是为了示意, 为了简便起见, 魔鬼数字我就不替换成宏了, 也没有过多考虑空指针等健壮性问题):

 

#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// 获取Beauty.exe所在路径
void getExePath(char *path, int size)
{
	char szBuf[1025] = {0};   
	GetModuleFileName(NULL, szBuf, sizeof(szBuf));
	char *p = strrchr(szBuf, '\\');
	*p = '\0'; 

	strncpy(path, szBuf, size - 1);
	path[size - 1] = '\0';
}

// 私有转化算法(不能公开)
void privateConvert(char *pStr)
{
	int len = strlen(pStr);
	int i = 0;
	for(i = 0; i < len; i++)
	{
		pStr[i] = pStr[i] * pStr[i] % 128; // 爱咋写咋写
		if('\0' == pStr[i])
		{
			pStr[i] = 1;
		}
	}
}


// Beauty.exe的开始部分
int main()
{
	/* Beauty.exe软件的认证部分, 如果不通过, 则不可以用Beauty.exe */


	// 获取Beauty.exe所在目录下的license.txt文件的第一行
	char szLicenseFile[2049] = {0};
	getExePath(szLicenseFile, sizeof(szLicenseFile));
	strcat(szLicenseFile, "\\license.txt"); // strcat不安全哈

	// 校验license.txt文件是否存在
	ifstream in(szLicenseFile);
	if(!in)
	{
		cout << "无license.txt文件, 认证失败" << endl;
		while(1);
		return -1;
	}

	// 获取并校验license.txt文件第一行
	string line;
	getline(in, line);
	if(line == string(""))
	{
		cout << "license.txt文件错误" << endl;
		while(1);
		return -1;
	}

	// 获取license.txt文件指纹
	char szLine[1025] = {0};
	strncpy(szLine, line.c_str(), sizeof(szLine) - 1);


	// 获取运行Beauty.exe的PC的指纹
	char szPC_ID[1025] = "004201EAC230"; // 获取运行Beauty.exe的PC所特有的一个值,假设为004201EAC230(每台PC都不同)
    char szFingerPrint[1025] = "DFEE6B250591BAD1AA7EFA7D0ACB235F"; // szPC_ID的md5值
	cout << szFingerPrint << endl;    // 显示szFingerPrint,让Beauty.exe用户可见, 便于提供给权限控制者(Beauty.exe的开发者) 
	
	// 私有变换
	privateConvert(szFingerPrint);

	
	
	// 判断license.txe文件指纹和PC指纹是否一致
	if(0 != strcmp(szLine, szFingerPrint))
	{
		cout << "license.txt文件认证失败" << endl;
		while(1);
		return -1;
	}


	// 软件的功能部分, 此处略去10000行功能性语句
	cout << "欢迎使用本软件" << endl;

	while(1);

	return 0;
}

       当用户用上面的Beauty.exe软件后, 会在自己的机器上自动生成该机器特有的DFEE6B250591BAD1AA7EFA7D0ACB235F串。 如果用户要真正使用这个软件的功能, 则需要把这个特有的串提供给软件的开发者, 比如你,我。

 



       软件开发者收到这个串之后, 根据下面的代码来制作证书, LicenseGenerator.exe的代码如下:

 

#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// 获取LicenseGenerator.exe所在路径
void getExePath(char *path, int size)
{
	char   szBuf[1025] = {0};   
	GetModuleFileName(NULL, szBuf, sizeof(szBuf));
	char *p = strrchr(szBuf, '\\'); 
	*p = '\0'; 

	strncpy(path, szBuf, size - 1);
	path[size - 1] = '\0';
}

// 私有转化算法(不能公开, 且与Beauty.exe中的函数必须一致)
void privateConvert(char *pStr)
{
	int len = strlen(pStr);
	int i = 0;
	for(i = 0; i < len; i++)
	{
		pStr[i] = pStr[i] * pStr[i] % 128; // 爱咋写咋写
		if('\0' == pStr[i])
		{
			pStr[i] = 1;
		}
	}
}

// LicenseGenerator.exe的开始部分
int main()
{
    char szFingerPrint[1025] = "DFEE6B250591BAD1AA7EFA7D0ACB235F"; // 用户提供的串
	privateConvert(szFingerPrint);

	char szLicenseFile[2049] = {0};
	getExePath(szLicenseFile, sizeof(szLicenseFile));
	strcat(szLicenseFile, "//license.txt"); // strcat不安全哈
	ofstream out(szLicenseFile);
	out << szFingerPrint << endl;

	cout << "制作证书成功" << endl;
	while(1);

	return 0;
}

         当软件的开发者利用LicenseGenerator.exe制作好证书后, 就可以把这个license.txt发给Beauty.exe软件的使用者, 使用者把这个证书放到Beauty.exe所在目录下, 下次运行Beauty.exe的时候, 就通过了校验。

 

 

         上述只是控制机制的一个非常简单的模型, 我们可以看到, 没有证书不行, 证书错误也不行。 这样, 对于每个证书, 只有一台PC可用, 其他人不可用。 实际上还可以控制用户使用的时间, 我就不赘述了。 有兴趣的朋友们, 赶快试一下吧。

 

         最后强调一点, 私有加密算法和LicenseGenerator.exe绝对不能泄露, 否则, 使用权控制的机制形同虚设。 当然啦, 要想更安全, 那就需要在私有加密算法上大作文章。

 

 

       

  • 11
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
你的程序加密过OD MD5值支持二次开发使用 防破解验证也可实现一机一码 VC++ 开发 STARTUPINFO startup; PROCESS_INFORMATION process; CString g_strCompanyName1 = ""; CString g_strCompanyName2 = ""; CString g_strCompanyName3 = ""; CString g_strCompanyName = "**"; BOOL CTaiShanApp::InitInstance() { AfxEnableControlContainer(); //#ifdef ZJH m_gMessageID = ::RegisterWindowMessage("WsSendMessageHqData"); CFileFind fnd; if(S_OK != ::CoInitialize (NULL)) return FALSE; // ReadDiskIDPartCwd(); // if(!FyRegister::IsValidUser()) // return FALSE; memset( &startup, 0, sizeof( startup ) ); startup.cb = sizeof( startup ); memset( &process, 0, sizeof( process ) ); if(fnd.FindFile ("WsSendMessageShare.exe")) { m_gbUseExe = true; } hAppMutex=::CreateMutex(NULL,TRUE,m_pszExeName); if(GetLastError() == ERROR_ALREADY_EXISTS) { CWnd *pPrevWnd = CWnd::GetDesktopWindow()->GetWindow(GW_CHILD); while(pPrevWnd) { if(::GetProp(pPrevWnd->GetSafeHwnd(),m_pszExeName)) { if(pPrevWnd->IsIconic()) pPrevWnd->ShowWindow(SW_RESTORE); pPrevWnd->SetForegroundWindow(); pPrevWnd->GetLastActivePopup()->SetForegroundWindow(); return false; } pPrevWnd = pPrevWnd->GetWindow(GW_HWNDNEXT); } return false; } //#endif #ifndef _NET_AUTHEN HMODULE hModule; hModule = LoadLibrary("ide21201.dll"); if (hModule==NULL) { AfxMessageBox("Can't find ide21201.dll"); return FALSE; } char *(WINAPI * GetIdeSerial)(); GetIdeSerial = (char *(WINAPI *)())GetProcAddress(hModule, "GetIdeSerial"); if (GetIdeSerial==NULL) { AfxMessageBox("Can't find GetIdeSerial in ide21201.dll"); return FALSE; } CString strSerialNumber;// = SERIAL_NUMBER; strSerialNumber = GetIdeSerial(); strSerialNumber.TrimLeft(" "); if (strSerialNumber.Compare(SERIAL_NUMBER)!=0) { AfxMessageBox("序列号错误"); return FALSE; } #else CDlgLogin dlgLogin; int nResponse = dlgLogin.DoModal(); if (nResponse!=1) return FALSE; #endif /* CDialogShowInformation dlg; dlg.DoModal();*/ int nResult; m_bAppAuthorized=TRUE; // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. CTaiTestSplash *m_splash; BOOL SplashOpen=FALSE; m_splash = new CTaiTestSplash; SplashOpen=m_splash->Create(); if( SplashOpen ) m_splash->ShowWindow(SW_SHOW); DWORD Currenttime=GetTickCount(); BeginWaitCursor(); #ifdef TEST_USER1 t = CTime::GetCurrentTime(); CTime t2 = g_timeUseEnd; if(t >= t2) { // AfxMessageBox("试用期已过,若想继续使用,请购买正式版!",MB_OK | MB_ICONSTOP); return false; } else 以上为部分代码
### 回答1: Android C 高级编程是指在Android开发中使用C语言进行高级编程的技术。而使用NDK(Native Development Kit)可以使开发者在Android应用中使用C/C++等本地语言进行编程。 NDK是一个工具集,它允许开发者在Android应用中嵌入本地代码,并且提供了一系列的开发工具和库,以便开发者能够在Android应用中使用C/C++进行高级编程。使用NDK可以提供更高的性能和更低的内存占用,适用于需要处理大量数据和高性能计算的应用场景。 在使用NDK进行Android C高级编程时,可以使用PDF(Portable Document Format)作为文档格式,以便对代码和项目进行更好的管理和文档化。在NDK的开发过程中,可以使用PDF文档记录关键的设计思路、代码逻辑、接口定义等信息,以方便团队协作和后续的维护。 使用NDK进行Android C高级编程的步骤大致如下: 1. 准备开发环境:安装NDK并配置好开发环境,包括设置NDK的路径和编译器等。 2. 创建新项目:使用Android Studio创建一个新的Android项目,并在项目中引入NDK的支持。 3. 编写C代码:使用C/C++语言编写需要调用的函数、算法或者数据结构等代码,并将其保存在适当的目录下。 4. 编写JNI接口:在生成的Java代码中,使用JNI(Java Native Interface)定义对应C代码的接口,以便在Java层调用C代码。 5. 编译和构建:使用NDK的工具集进行编译和构建,将C代码编译成适合Android平台使用的库文件(.so文件)。 6. 在Java代码中调用C代码:在需要调用C代码的地方,使用JNI接口调用对应的C函数,以实现和C代码的交互和调用。 使用PDF文档进行文档化可以帮助开发者更好地组织和管理代码、接口和设计文档等,方便后续的代码维护和项目协作。同时,也可以作为项目的参考文档,方便其他开发人员了解和使用项目。 ### 回答2: Android C 高级编程是针对使用NDK(Native Development Kit)的一种高级编程技术。NDK是Android开发工具包中的一个工具,允许开发者使用C、C++或其他本地编程语言编写Android应用程序的部分或全部代码。 使用NDK进行Android C高级编程有许多优点。首先,NDK提供了更高的性能和更好的控制权,特别是在处理图形、音频和计算密集型任务时。通过使用本地编程语言,开发者能够更好地利用底层系统资源,提高应用程序的执行效率和速度。 其次,NDK还提供了对现有C和C++库的支持。这意味着开发者可以使用许多已经存在的库和功能来加快开发进程。无需重新编写现有的代码,直接使用NDK与这些库进行集成即可。 在使用NDK进行Android C高级编程时,一种常见的用途是开发游戏。使用C或C++编写游戏代码可以获得更好的性能和更低的延迟,这对于游戏的流畅运行至关重要。 此外,开发者还可以使用NDK为现有的Java应用程序添加本地本地扩展。这样可以通过使用C或C++编写某些关键组件,以改进应用程序的性能或添加新的功能。 总的来说,通过使用NDK进行Android C高级编程,开发者可以获得更高的性能、更好的控制权和更好的资源利用。无论是开发游戏还是优化应用程序,使用NDK都是提高性能和扩展功能的好方法。通过阅读相关的PDF文档,开发者可以更深入地了解如何使用NDK进行Android C高级编程。 ### 回答3: Android NDK (Native Development Kit) 是一个用于开发 Android 应用程序的工具集,它使开发者能够使用 C 或 C++ 编写原生代码,并将其与 Java 编写的 Android 应用程序一起使用。使用 NDK 可以达到增加性能、复用现有的 C/C++ 代码以及访问底层硬件等目的。 在 Android C 高级编程中,使用 NDK 商用 PDF 库可以实现在 Android 应用程序中处理 PDF 文件的功能。PDF 文件是一种常见的电子文档格式,使用 PDF 库可以读取、编辑和生成 PDF 文件。 使用 NDK 进行 PDF 处理的一般步骤如下: 1. 集成 PDF 库:首先,需要将商用的 PDF 库 (.so 文件) 集成到 Android 项目中。可以通过在 Android.mk 文件中添加相关配置,确保 .so 文件正确地被编译和链接到应用程序中。 2. 创建 JNI 接口:为了在 Java 层与 C/C++ 层之间进行通信,需要创建 JNI (Java Native Interface) 接口。可以在创建 JNI 方法时使用 JNAerator 或者手动编写 JNI 代码,以便在 Java 层调用 C/C++ 的功能。 3. 对 PDF 文件进行处理:在 C/C++ 层,可以使用 PDF 库提供的功能来处理 PDF 文件。例如,可以使用库提供的函数来解析、渲染、添加标注、提取内容等。 4. 将数据返回给 Java 层:在 C/C++ 层处理完之后,可以通过 JNI 接口将处理后的数据返回给 Java 层。这样就可以在 Android 应用程序中显示或者存储处理后的 PDF 文件。 需要注意的是,在使用商用 PDF 库时,需要遵循相关的许可协议,并确保在开发和分发过程中合法使用该库。 总之,通过使用 NDK 和商用 PDF 库,可以使 Android 应用程序具有处理 PDF 文件的高级编程能力。同时,开发者需要具备 C/C++ 编程和 JNI 接口的使用经验,以便顺利地进行开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值