RPN 动态注册模型






4.45/5 (5投票s)
一篇关于在Pocket PC应用程序中实现RPN的文章。
引言
在为移动社区开发和营销软件时,最常用的注册模型是RPN(逆波兰表示法)或动态注册。如何实现这一点有时会令人困惑,所以我想把它简化。简而言之,逆波兰表示法使用一种您提供给分销商的字符串形式的公式。当客户购买您的应用程序时,他们会向分销商提供要安装该应用程序的设备的C/DUI。C/DUI是唯一的设备标识符,它因平台而异。
- Pocket PC:所有者的名字和姓氏,或类似形式。
- Symbian OS:IMEI,格式如下,包含连字符:350443-61-001241-9。
- Palm OS:Palm用户名。
在本文中,我们将只讨论此注册模型的Pocket PC应用程序。
关于模型
您提供给分销商的RPN字符串看起来像这样
"i 0 == m_nVariant * key + c 5 * +"
m_nVariant
是您用来使结果与其他使用相同公式的任何人区分开的数字。在示例中,我们将使用111作为变体。
"i 0 == 111 * key + c 2 * +"
RPN字符串中只允许三个变量:key
、i
和c
。RPN字符串长度没有变量。
动态注册码生成使用32位有符号整数完成,最终结果转换为16位无符号整数。通过屏蔽掉除最低16位以外的所有位,将32位有符号整数结果转换为16位无符号整数。例如,如果最终结果是-3 (0xFFFFFFFD),那么最后或最低16位将是0xFFFD HEX,即无符号十进制65533。变量c
被视为一个8位无符号整数。最小可能的注册码是0,最大可能的注册码是2^16 - 1 = 65535。如果注册码少于五位数,则在前面添加0以使其成为五位数。所以,763变成00763。由于动态注册码生成只使用整数,所以763 / 10 = 76,而不是76.3。因此,小数从不会出现在动态注册码中。
此外,处理RPN字符串的程序对处理的字符数有限制。如果手持设备ID超过10个字符,将只使用前五个和后五个字符来生成解锁码。
Don Laverdure有13个字母(包括空格),所以使用前5个和后5个:“**Don Lrdure**”。
非累积运算从左到右求值,所以7 3 - = 4(不是-4)。
目前,此过程不支持16位字符,如日文、中文、希腊文或希伯来文,因为变量c
被视为8位无符号整数。
我们将C/DUI的每个字符转换为ASCII值。例如,“**Will P**”
W = 87 decimal
i = 105 decimal
l = 108 decimal
l = 108 decimal
[space] = 32 decimal
P = 80 decimal
我们将RPN字符串应用于C/DUI中每个字符的ASCII值。在公式中,'i
'是字符在C/DUI中的位置,从0开始,'c
'是字符在C/DUI中的ASCII值。
对于“Will P”
87 + 105 + 108 + 108 + 32 + 80 = 520; 520 * 2 = 1040;
1040 + 111 = 1151
RPN字符串“i 0 == 111 * key + c 3 * +”将加总C/DUI中所有字符的ASCII值。将其乘以3,然后再加上111。
所以,对于“Will P”
520*3=1560; 1560 + 111 = 1671
RPN字符串“i 0 == 987 * key + c +”将加总C/DUI中所有字符的ASCII值,然后再加上987。
所以对于“Will P”
520 + 987 = 1507
RPN字符串可以比这复杂得多。几乎任何运算符都允许使用。
- 逻辑运算符,如 &&、||、!、==、>=
- 位运算符,如 <<(左移)、>>(右移)、~(反转)、&(AND)、|(OR)
- 算术运算符,如 +、-、*、/、%(模)
使用代码
首先,我们需要从Pocket PC获取C/DUI。所有者名称存储在注册表项*HKEY_CURRENT_USER\ControlPanel\Owner*中。
//Many Registry classes can be found elsewhere on //the code project CString OwnerName; // This will hold the C/DUI DWORD dwR2; unsigned char Owner[255]; if (!reg.Open(HKEY_CURRENT_USER, _T("ControlPanel\\Owner"),false)) { AfxMessageBox(_T("Can't find Owner, ") _T("error detected, Attempting to correct.")); // Error handling for no // registry key present goes here } if(reg.GetLength(_T("Owner"),dwR2)) { reg.Read(_T("Owner"),Owner,dwR2); OwnerName.Format(_T("%s"),&Owner); } //
一旦我们有了C/DUI,通常在项目初始化期间,我们会将其与RPN进行比较,以查看应用程序是否已注册。
当用户输入从分销商处获得的RPN时,将其写入注册表或ini文件,以便在应用程序每次启动时都可以检索。
CString m_strMyKey; m_strMyKey=pApp->GetProfileString(_T("Initialize"), _T("Key")); CString RPNString; // Run the owner's name through the RPN // evaluation and assign the 5 digit result. RPNString.Format(_T("%-.5d"), (int)EvaluateRPN(OwnerName,111)); if(RPNString.Find(m_strMyKey)==0) // Compare the C/DUI RPN to the RPN in the registry { Registered=TRUE; } else { AfxMessageBox(_T("Unregistered")); Registered=FALSE; }
评估如下进行
double CMyApplication::EvaluateRPN(CString strRPN, double m_nVariant) { // RPN = "i 0 == m_nVariant * key + c 5 * +" CString m_strRPN; double m_nStringValue=0; int StringPos=0; if(strRPN.GetLength()>10) { m_strRPN=strRPN.Left(5) + strRPN.Right(5); } else m_strRPN=strRPN; do { m_nStringValue += (double)m_strRPN.GetAt(StringPos); StringPos++; }while(StringPos <= m_strRPN.GetLength()); m_nStringValue=m_nStringValue*5; // c5* m_nStringValue+=m_nVariant; return m_nStringValue; } // This code evaluates the string using // the sample formula, more complex formulas // will require more complex evaluation code.
关注点
动态注册保护了您,作者,因为用户必须输入的解锁应用程序的动态注册码取决于他们手持设备上的C/DUI。由于不同的用户为某些手持设备选择了不同的C/DUI,一个能在某台手持设备上解锁您的应用程序的动态注册码可能在另一台手持设备上不起作用。同一个动态注册码在两台不同的手持设备上起作用的唯一方法是,这两台手持设备具有相同的C/DUI。正如您所见,这有助于防止盗版,因为盗版者要从朋友那里复制您的软件的唯一方法是确保他手持设备上的C/DUI与他朋友手持设备上的C/DUI相同。对于盗版者来说,每次他想运行不同的应用程序时都要更改他的C/DUI变得更加麻烦和不切实际。
打击黑客对某些人来说是全职工作,正如他们所说,“锁只挡住诚实的人”,所以这种易于实现的编码将“让诚实的人购买您的应用程序”,而您无需花费更多时间来保护您的应用程序而不是编写它。
历史
- 2006年2月28日 - 文章首次发布。