【9小组】【中华灯谜】【算法分析】
本帖最后由 月之精灵 于 2010-6-2 18:13 编辑【破文标题】【PYG学员】【9小组】【中华灯谜】【算法分析】
【破文作者】sohd
【作者邮箱】[email protected]
【作者主页】
【破解工具】OD
【破解平台】win2003
【软件名称】中华灯谜 2008 build 12.15
【软件大小】2.87M
【原版下载】http://www.onlinedown.net/softdown/863_2.htm
【保护方式】aspack
【软件简介】〖中华灯谜〗软件是目前国产最好的灯谜软件,软件受到数十家刊物的特别撰文推荐。
【破解声明】只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
------------------------------------------------------------------------
【破解过程】第一次完整分析这个注册代码,有误之处还请见谅。我简单说一下几个重要的代码。
首先来到关键处
0054EF06 |.8B85 6CFFFFFF mov eax, dword ptr
0054EF0C |.50 push eax
0054EF0D |.8D95 64FFFFFF lea edx, dword ptr
0054EF13 |.8B83 C0030000 mov eax, dword ptr
0054EF19 |.E8 6A8CEFFF call <GetRegInfo> ;获取定单号GetRegInfo 这个是我做的标签。
0054EF1E |.8B85 64FFFFFF mov eax, dword ptr
0054EF24 |.E8 DBA6EBFF call <C_Compute1> ; 把序号的数*10再相加这里进去看看看下面的C_Compute1处代码
0054EF29 |.B9 3A000000 mov ecx, 3A
0054EF2E |.99 cdq
0054EF2F |.F7F9 idiv ecx ; 把上面算出来的数,除3A 取余数给 eax
0054EF31 |.8BC2 mov eax, edx
0054EF33 |.8D95 68FFFFFF lea edx, dword ptr ; 一个局部地址 一会会把算到的注册码前几个字符串地址写到这里。
0054EF39 |.E8 62A6EBFF call 004095A0 ; 获取注册码的前几个字符。。这个函数有点绕这里进去看看看下面的004095A0 处代码
0054EF3E |.8D85 68FFFFFF lea eax, dword ptr
0054EF44 |.50 push eax
0054EF45 |.8D95 58FFFFFF lea edx, dword ptr
0054EF4B |.8B83 C0030000 mov eax, dword ptr
0054EF51 |.E8 328CEFFF call <GetRegInfo> ;获取定单号GetRegInfo 这个是我做的标签。
0054EF56 |.8B85 58FFFFFF mov eax, dword ptr
0054EF5C |.E8 A3A6EBFF call <C_Compute1> ;把序号的数*10再相加这里进去看看看下面的C_Compute1处代码
0054EF61 |.8D95 5CFFFFFF lea edx, dword ptr
0054EF67 |.E8 80DCFFFF call 0054CBEC ;进去一个计算。这里进去看看看下面的0054CBEC 处代码
0054EF6C |.8B85 5CFFFFFF mov eax, dword ptr
0054EF72 |.E8 8DA6EBFF call <C_Compute1>
0054EF77 |.8D95 60FFFFFF lea edx, dword ptr
0054EF7D |.E8 4ADDFFFF call <Compute2> ;出来一串注册码 进去看看 看下面的Compute2 处代码
0054EF82 |.8B95 60FFFFFF mov edx, dword ptr ; |
0054EF88 |.58 pop eax ; |
0054EF89 |.E8 E25CEBFF call <strcat> ; \strcat
0054EF8E |.8B95 68FFFFFF mov edx, dword ptr
0054EF94 |.58 pop eax
0054EF95 |.E8 125EEBFF call 00404DAC
0054EF9A |.0F85 8F000000 jnz 0054F02F
0054EFA0 |.B8 F4F05400 mov eax, 0054F0F4 ;注册成功,谢谢你的注册!
0054EFA5 |.E8 D21DEFFF call 00440D7C
0054EFAA |.BA 18F15400 mov edx, 0054F118 ;本软件已注册
0054EFAF |.8B83 B0030000 mov eax, dword ptr
0054EFB5 |.E8 FE8BEFFF call 00447BB8
0054EFBA |.8D85 54FFFFFF lea eax, dword ptr
0054EFC0 |.B9 30F15400 mov ecx, 0054F130 ;\dc0n.dll
0054EFC5 |.8B55 FC mov edx, dword ptr
0054EFC8 |.E8 E75CEBFF call 00404CB4
0054EFCD |.8B8D 54FFFFFF mov ecx, dword ptr
0054EFD3 |.B2 01 mov dl, 1
0054EFD5 |.A1 B8184700 mov eax, dword ptr
0054EFDA |.E8 8929F2FF call 00471968
0054EFDF |.8BF0 mov esi, eax
0054EFE1 |.8D95 50FFFFFF lea edx, dword ptr
0054EFE7 |.8B83 C0030000 mov eax, dword ptr
0054EFED |.E8 968BEFFF call <GetRegInfo>
0054EFF2 |.8B85 50FFFFFF mov eax, dword ptr
0054EFF8 |.50 push eax
0054EFF9 |.B9 44F15400 mov ecx, 0054F144 ;sepop
0054EFFE |.BA 54F15400 mov edx, 0054F154 ;syssetup
0054F003 |.8BC6 mov eax, esi
0054F005 |.8B18 mov ebx, dword ptr
0054F007 |.FF53 04 call dword ptr
0054F00A |.8D85 4CFFFFFF lea eax, dword ptr
0054F010 |.B9 30F15400 mov ecx, 0054F130 ;\dc0n.dll
0054F015 |.8B55 FC mov edx, dword ptr
0054F018 |.E8 975CEBFF call 00404CB4
0054F01D |.8B85 4CFFFFFF mov eax, dword ptr
0054F023 |.BA 02000000 mov edx, 2
0054F028 |.E8 03A9EBFF call 00409930
0054F02D |.EB 17 jmp short 0054F046
0054F02F |>B8 68F15400 mov eax, 0054F168 ;注册码错误,请重新输入!
0054F034 |.E8 431DEFFF call 00440D7C
C_Compute1 代码如下(只贴关键代码):
004033B6 |>80EB 30 /sub bl, 30
004033B9 |. |80FB 09 |cmp bl, 9 ;必须为数字。
004033BC |. |77 25 |ja short 004033E3 ;不是数字就跳走了。
004033BE |. |39F8 |cmp eax, edi
004033C0 |. |77 21 |ja short 004033E3
004033C2 |. |8D0480 |lea eax, dword ptr ;EAX第一次是0 ------------------------
004033C5 |. |01C0 |add eax, eax ; 这断在循环的把数字相加
004033C7 |. |01D8 |add eax, ebx
004033C9 |. |8A1E |mov bl, byte ptr ; eai为字符串首地址
004033CB |. |46 |inc esi
004033CC |. |84DB |test bl, bl
004033CE |.^\75 E6 \jnz short 004033B6 ;-------------------------------------
转换成C++代码为:
char* pszOrderID = "358588"; // 假如这个就是定单号。
DWORD dwNum = 0;
while (*pszOrderID != 0)
{
dwNum = dwNum*10;
dwNum += (*pszOrderID-0x30);
pszOrderID++;
}
return dwNum;
以上就是 C_Compute1 函数大概作用。。当然函数的其它代码可能还有别的作用。暂不深入看了。。
0054CBEC 代码如下(只贴关键代码):
0054CC09 |.81F3 F1250B00 xor ebx, 0B25F1 ;ebx就是前面算出来的数和 0B25F1 xor
0054CC0F |.8BC3 mov eax, ebx
0054CC11 |.33D2 xor edx, edx
0054CC13 |.52 push edx ; |format => NULL
0054CC14 |.50 push eax ; |s
0054CC15 |.8D45 FC lea eax, dword ptr ; |
0054CC18 |.E8 B3C9EBFF call <sprintf> ; \%d 到一个内存里。 sprintf我定义的标签 只能说是近似函数
0054CC1D |.8B45 FC mov eax, dword ptr
0054CC20 |.0FB600 movzx eax, byte ptr ;10进制数的第一个
0054CC23 |.8B55 FC mov edx, dword ptr
0054CC26 |.0FB652 01 movzx edx, byte ptr ;10进制数的第2个
0054CC2A |.03C2 add eax, edx ;相加
0054CC2C |.B9 05000000 mov ecx, 5
0054CC31 |.99 cdq
0054CC32 |.F7F9 idiv ecx ;除5
0054CC34 |.80C2 34 add dl, 34 ;余数+34
0054CC37 |.8855 F8 mov byte ptr , dl ; 第一个数值 保存
0054CC3A |.8B45 FC mov eax, dword ptr
0054CC3D |.0FB640 02 movzx eax, byte ptr
0054CC41 |.8B55 FC mov edx, dword ptr
0054CC44 |.0FB652 03 movzx edx, byte ptr
0054CC48 |.03C2 add eax, edx
0054CC4A |.B9 05000000 mov ecx, 5
0054CC4F |.99 cdq
0054CC50 |.F7F9 idiv ecx
0054CC52 |.8BDA mov ebx, edx
0054CC54 |.80C3 33 add bl, 33
0054CC57 |.885D F9 mov byte ptr , bl ; 第2个数值 保存
0054CC5A |.8D45 F4 lea eax, dword ptr
0054CC5D |.8A55 F8 mov dl, byte ptr
0054CC60 |.E8 2B7FEBFF call <new_copy> ;这函数会先new一个空间,再把数值copy到新空间。
0054CC65 |.8B45 F4 mov eax, dword ptr
0054CC68 |.8D55 FC lea edx, dword ptr
0054CC6B |.B9 1B000000 mov ecx, 1B
0054CC70 |.E8 D382EBFF call <strInsert> ; 这个就是字符串插入函数1B是要插入的位置一般我们的定单号算出来的不会有1B长。所以 都是直接把数值往后插
0054CC75 |.8D45 F0 lea eax, dword ptr
0054CC78 |.8BD3 mov edx, ebx
0054CC7A |.E8 117FEBFF call <new_copy> ; 同上
0054CC7F |.8B45 F0 mov eax, dword ptr
0054CC82 |.8D55 FC lea edx, dword ptr
0054CC85 |.B9 19000000 mov ecx, 19
0054CC8A |.E8 B982EBFF call <strInsert> ; 同上
转换成C++代码为:
dwNum ^= 0x0B25F1;
char szNum = {0};
sprintf(szNum, "%d", dwNum);
char szTemp = {0};
szTemp = (*(szNum) + *(szNum+1))%5 + 0x34;
szTemp = (*(szNum+2) + *(szNum+3))%5 + 0x33;
strcat(szNum, szTemp);
004095A0 代码如下(只贴关键代码):
下面这段代码并非 004095A0 函数的是子函数内的。调用过程中的代码就不贴了,
00409E80 > \895D DC mov dword ptr , ebx
00409E83 .8975 D8 mov dword ptr , esi
00409E86 .51 push ecx
00409E87 .52 push edx
00409E88 .E8 95000000 call 00409F22 ;这里改变了ESI 进去
00409F22 代码如下(只贴关键代码):
0040A076 |$B9 0A000000 mov ecx, 0A ;Case 55 ('U') of switch 0040A04A
0040A07B |>8D75 9F lea esi, dword ptr
0040A07E |>31D2 /xor edx, edx
0040A080 |.F7F1 |div ecx
0040A082 |.80C2 30 |add dl, 30 ;这块是算注册码 前面的几个字串
0040A085 |.80FA 3A |cmp dl, 3A
0040A088 |.72 03 |jb short 0040A08D
0040A08A |.80C2 07 |add dl, 7
0040A08D |>4E |dec esi
0040A08E |.8816 |mov byte ptr , dl
0040A090 |.09C0 |or eax, eax ; 商不为0 就继续。
0040A092 |.^ 75 EA \jnz short 0040A07E
上面这一块就是核心代码了。算出来前N位字符
转换成C++代码为:
CString strRegCode;
int nNum = 0;
nNum = dwNum%0x3A;
int n1, n2, nTemp;
n1 = nNum;
do
{
nTemp = n1;
n1 = n1/0x0A; // 商
n2 = nTemp%0x0A; // 余数
n2 += 0x30;
strRegCode.Insert(0, (char*)&n2);
} while (n1);
Compute2 代码如下(只贴关键代码):
0054CCEB |.81F3 8776FBDD xor ebx, DDFB7687 ;ebx前面代码计算出来的值 和DDFB7687 xor
0054CCF1 |.8BC3 mov eax, ebx
0054CCF3 |.33D2 xor edx, edx
0054CCF5 |.52 push edx ; |format => NULL
0054CCF6 |.50 push eax ; |s
0054CCF7 |.8D45 FC lea eax, dword ptr ; |
0054CCFA |.E8 D1C8EBFF call <sprintf> ; \sprintf 格式化为十进制数
0054CCFF |.8B45 FC mov eax, dword ptr
0054CD02 |.0FB600 movzx eax, byte ptr ;第一个数
0054CD05 |.8B55 FC mov edx, dword ptr
0054CD08 |.0FB652 01 movzx edx, byte ptr ;第2个数
0054CD0C |.03C2 add eax, edx
0054CD0E |.B9 05000000 mov ecx, 5
0054CD13 |.99 cdq
0054CD14 |.F7F9 idiv ecx ;除5
0054CD16 |.80C2 66 add dl, 66 ;余数+66
0054CD19 |.8855 F8 mov byte ptr , dl ; 保存第一个值。
0054CD1C |.8B45 FC mov eax, dword ptr
0054CD1F |.0FB640 02 movzx eax, byte ptr
0054CD23 |.8B55 FC mov edx, dword ptr
0054CD26 |.0FB652 03 movzx edx, byte ptr
0054CD2A |.03C2 add eax, edx
0054CD2C |.B9 05000000 mov ecx, 5
0054CD31 |.99 cdq
0054CD32 |.F7F9 idiv ecx
0054CD34 |.80C2 75 add dl, 75
0054CD37 |.8855 F9 mov byte ptr , dl ; 保存第2个值。
0054CD3A |.8B45 FC mov eax, dword ptr
0054CD3D |.0FB640 04 movzx eax, byte ptr
0054CD41 |.8B55 FC mov edx, dword ptr
0054CD44 |.0FB652 05 movzx edx, byte ptr
0054CD48 |.03C2 add eax, edx
0054CD4A |.B9 05000000 mov ecx, 5
0054CD4F |.99 cdq
0054CD50 |.F7F9 idiv ecx
0054CD52 |.80C2 7A add dl, 7A
0054CD55 |.8855 FA mov byte ptr , dl ; 保存第3个值。
0054CD58 |.8B45 FC mov eax, dword ptr
0054CD5B |.0FB640 06 movzx eax, byte ptr
0054CD5F |.8B55 FC mov edx, dword ptr
0054CD62 |.0FB652 07 movzx edx, byte ptr
0054CD66 |.03C2 add eax, edx
0054CD68 |.8B55 FC mov edx, dword ptr
0054CD6B |.0FB652 08 movzx edx, byte ptr
0054CD6F |.03C2 add eax, edx
0054CD71 |.B9 05000000 mov ecx, 5
0054CD76 |.99 cdq
0054CD77 |.F7F9 idiv ecx
0054CD79 |.80C2 69 add dl, 69
0054CD7C |.8855 FB mov byte ptr , dl; 保存第4个值。
0054CD7F |.8D45 F4 lea eax, dword ptr
0054CD82 |.8A55 F8 mov dl, byte ptr
0054CD85 |.E8 067EEBFF call <new_copy> ;这函数会先new一个空间,再把数值copy到新空间。
0054CD8A |.8B45 F4 mov eax, dword ptr
0054CD8D |.8D55 FC lea edx, dword ptr
0054CD90 |.B9 07000000 mov ecx, 7
0054CD95 |.E8 AE81EBFF call <strInsert> ; 这个就是字符串插入函数7是要插入的位置
0054CD9A |.8D45 F0 lea eax, dword ptr
0054CD9D |.8A55 FB mov dl, byte ptr
0054CDA0 |.E8 EB7DEBFF call <new_copy> ;同上
0054CDA5 |.8B45 F0 mov eax, dword ptr
0054CDA8 |.8D55 FC lea edx, dword ptr
0054CDAB |.B9 03000000 mov ecx, 3
0054CDB0 |.E8 9381EBFF call <strInsert> ;同上
0054CDB5 |.8D45 EC lea eax, dword ptr
0054CDB8 |.8A55 F9 mov dl, byte ptr
0054CDBB |.E8 D07DEBFF call <new_copy> ;同上
0054CDC0 |.8B45 EC mov eax, dword ptr
0054CDC3 |.8D55 FC lea edx, dword ptr
0054CDC6 |.B9 05000000 mov ecx, 5
0054CDCB |.E8 7881EBFF call <strInsert> ;同上
0054CDD0 |.8D45 E8 lea eax, dword ptr
0054CDD3 |.8A55 FA mov dl, byte ptr
0054CDD6 |.E8 B57DEBFF call <new_copy> ;同上
0054CDDB |.8B45 E8 mov eax, dword ptr
0054CDDE |.8D55 FC lea edx, dword ptr
0054CDE1 |.B9 09000000 mov ecx, 9
0054CDE6 |.E8 5D81EBFF call <strInsert> ;同上
转换成C++代码为:
dwNum ^= 0xDDFB7687;
memset(szNum, 0, sizeof(szNum));
sprintf(szNum, "%lu", dwNum);
szTemp = (*(szNum) + *(szNum+1))%5 + 0x66;
szTemp = (*(szNum+2) + *(szNum+3))%5 + 0x75;
szTemp = (*(szNum+4) + *(szNum+5))%5 + 0x7A;
szTemp = (*(szNum+6) + *(szNum+7) + *(szNum+8))%5 + 0x69;
CString strTemp(szNum);
strTemp.Insert(7-1, szTemp);
strTemp.Insert(3-1, szTemp);
strTemp.Insert(5-1, szTemp);
strTemp.Insert(9-1, szTemp);
下面是注册的整体代码:
CString strOrderID;
GetDlgItemText(EDT_DDH, strOrderID); // 获取到定单号
char* pszOrderID = strOrderID.GetBuffer(0);
strOrderID.ReleaseBuffer();
DWORD dwNum = 0;
while (*pszOrderID != 0)
{
dwNum = dwNum*10;
dwNum += (*pszOrderID-0x30);
pszOrderID++;
}
CString strRegCode;
int nNum = 0;
nNum = dwNum%0x3A;
int n1, n2, nTemp;
n1 = nNum;
do
{
nTemp = n1;
n1 = n1/0x0A; // 商
n2 = nTemp%0x0A; // 余数
n2 += 0x30;
strRegCode.Insert(0, (char*)&n2);
} while (n1);
dwNum ^= 0x0B25F1;
char szNum = {0};
sprintf(szNum, "%d", dwNum);
char szTemp = {0};
szTemp = (*(szNum) + *(szNum+1))%5 + 0x34;
szTemp = (*(szNum+2) + *(szNum+3))%5 + 0x33;
strcat(szNum, szTemp);
char* pszNum = szNum;
dwNum = 0;
while (*pszNum != 0)
{
dwNum = dwNum*10;
dwNum += (*pszNum-0x30);
pszNum++;
}
dwNum ^= 0xDDFB7687;
memset(szNum, 0, sizeof(szNum));
sprintf(szNum, "%lu", dwNum);
szTemp = (*(szNum) + *(szNum+1))%5 + 0x66;
szTemp = (*(szNum+2) + *(szNum+3))%5 + 0x75;
szTemp = (*(szNum+4) + *(szNum+5))%5 + 0x7A;
szTemp = (*(szNum+6) + *(szNum+7) + *(szNum+8))%5 + 0x69;
CString strTemp(szNum);
strTemp.Insert(7-1, szTemp);
strTemp.Insert(3-1, szTemp);
strTemp.Insert(5-1, szTemp);
strTemp.Insert(9-1, szTemp);
strRegCode += strTemp;
SetDlgItemText(EDT_REGCODE, strRegCode);// 最终注册码。
------------------------------------------------------------------------
【破解总结】
------------------------------------------------------------------------
【版权声明】 学习了,谢谢楼主分享 学习了露珠的大作 本来想破这个,结果没搞定,进来学习下哈 我是来学习下的 牛人呀,谢谢 宋宋好强 这个不错,对着学习,我就不信学不会
页:
[1]