LC4注册算法分析
发表于:
2006-4-10 20:57
8749
万里长征第二步:LC4注册算法分析
解密者:冲天剑@pediy.com
工具:peid 0.94, Ollyice 1.10 0. 导言
近来本地机器系统密码丢失,为了将其破解出来,到网上下载了据说很著名
的LC4,但却要求注册,否则暴力破解功能不可用。LC4顾名思义是4代的
版本,目前据说5代都出来了,官网上肯定下不到了。可下载的页面位于:
hxxp://www.hackchina.cn/Soft/hacktools/jmjm/200511/54.html
(老规矩,要访问这个网页的请自行改成正确格式URL。) 1. 反向工程
(1) 用PEID查壳,显示为Microsoft Visual C++ 6.0。
(2) 运行程序试注册,可知注册流程是程序自己显示机器号然后要求输入序
列号的类型。机器号显示:15859a29d,输入假码1234567试注册,显示字符串:
You have entered an invalid code. Please try again.
然后Ollyice载入,查找此字串。(首次运行会遇到异常,应在调试设置选项中
忽略所有异常并将所遇到的异常添加进去,重新运行) ////////////// 以下是代码 ////////////////
00411BF3 |. 50 |push eax ; 断点
00411BF4 |. E8 B722FFFF |call 00403EB0
00411BF9 |. 8B07 |mov eax, [edi] ; 真码指针
00411BFB >|. 8D5424 28 |lea edx, [esp+28] ; 假码指针
00411BFF |. 52 |push edx
00411C00 |. 50 |push eax
00411C01 |. E8 955C0100 |call 0042789B
00411C06 |. 83C4 10 |add esp, 10
00411C09 |. 85C0 |test eax, eax
00411C0B |. 75 23 |jnz short 00411C30 ; 关键跳转
00411C0D |. 8B07 |mov eax, [edi]
00411C0F |. 50 |push eax ; /Arg3
00411C10 |. 68 50134700 |push 00471350 ; |Arg2 = 00471350 ASCII "Unlock Code"
00411C15 |. 68 5C134700 |push 0047135C ; |Arg1 = 0047135C ASCII "Registration"
00411C1A |. 8BCE |mov ecx, esi ; |
00411C1C |. 899E 3C010000 |mov [esi+13C], ebx ; |
00411C22 |. E8 9AB20300 |call 0044CEC1 ; \lc4.0044CEC1
00411C27 |. 53 |push ebx
00411C28 |. 53 |push ebx
00411C29 |. 68 34144700 |push 00471434 ; ASCII "You have successfully registered LC4."
00411C2E |. EB 07 |jmp short 00411C37
00411C30 |> 53 |push ebx ; /Arg3
00411C31 |. 53 |push ebx ; |Arg2
00411C32 |. 68 00144700 |push 00471400 ; |Arg1 = 00471400 ASCII "You have entered an invalid code. Please try again."
00411C37 |> E8 D3720300 |call 00448F0F ; \lc4.00448F0F
////////////// 以上是代码 //////////////// 这个关键跳转太显眼了!那么接下去call 0042789B应该是判断两个字符串是否相
同,而call 00403EB0应该就是算注册码的过程了吧!于是在00411BF3处下断点,
单步步过00411BF4以后,果然出现了真正注册码!而接下来的两个push指令应该
是为call 0042789B准备参数的,它们所推入的果然是真码和假码的指针!不用再
多说了,赶快跟进00403EB0这个过程里去吧。 ////////////// 以下是代码 ////////////////
00403EB0 /$ 83EC 0C sub esp, 0C ; 预留局部变量空间(dword*3)
00403EB3 |. 8B4424 10 mov eax, [esp+10] ; 指向机器码字串的指针
00403EB7 |. 6A 08 push 8
00403EB9 |. 40 inc eax ; 掐掉机器码头字符
00403EBA |. 50 push eax
00403EBB |. 8D4C24 08 lea ecx, [esp+8] ; 局部变量1的指针
00403EBF |. 51 push ecx
00403EC0 |. E8 AB1E0200 call 00425D70
00403EC5 |. 8D5424 1C lea edx, [esp+1C]
00403EC9 |. 52 push edx
00403ECA |. 8D4424 10 lea eax, [esp+10]
00403ECE |. 68 88FA4600 push 0046FA88 ; ASCII "%08x"
00403ED3 |. 50 push eax
00403ED4 |. C64424 20 00 mov byte ptr [esp+20], 0
00403ED9 |. E8 65240200 call 00426343
00403EDE |. 8B4424 28 mov eax, [esp+28]
00403EE2 |. 35 52AE376F xor eax, 6F37AE52 ; EAX=机器码后8位对应的16进位字符
00403EE7 |. 8BC8 mov ecx, eax
00403EE9 |. C1E1 1B shl ecx, 1B
00403EEC |. C1E8 05 shr eax, 5
00403EEF |. 03C8 add ecx, eax
00403EF1 |. 51 push ecx ; ECX=注册码
00403EF2 |. 894C24 2C mov [esp+2C], ecx
00403EF6 |. 8B4C24 30 mov ecx, [esp+30]
00403EFA |. 68 80FA4600 push 0046FA80 ; ASCII "%04x"
00403EFF |. 51 push ecx
00403F00 |. E8 EC230200 call 004262F1
00403F05 |. 33C0 xor eax, eax
00403F07 |. 83C4 30 add esp, 30
00403F0A \. C3 retn
////////////// 以上是代码 //////////////// 机器码现在是9个字符,去掉首字符后所剩8个字符为:5859a29d。我一开始还在
一句一句地分析指令功能,等到步过00403EDE这句时,眼前忽然一亮:
EAX 5859A29D
不会这么简单吧!跟到00403EF1查看ECX的值为79BB7066。从这个子程序返回,到
外面一看,真码就是79bb7066!捏到软柿子了!这么说来,只需要额外编写一个
16进制数值与对应的ASCII字串相互转换的函数,而注册码计算的功能完全由上面
00403EE2到00403EEF这几句所标明了。 (3)注册函数
void Hextoasc(unsigned long int uValue, char *lpTransformedBuffer)
/* 实现把uValue所对应的16进制数值转化为ASCII字符串。16进制字母采用小写 */
/* 入口参数:uValue――16进制数值
lpTransformedBuffer――用于存放转化串的缓冲区 */
/* 出口参数:lpTransformedBuffer――ASCII串的指针 */
/* 注意:对输入不作合法性检测! */
{
char i = 8, temp;
lpTransformedBuffer[i]='\0';
do{
temp = uValue % 16;
lpTransformedBuffer[i - 1] = temp + (temp < 10 ? '0': 87);
uValue = uValue >> 4;
i = i - 1;
}while(i != 0);
}
unsigned long int uAsctohex(char *lpString)
/* 实现把lpString对应的字符串转换为16进制数值。 */
/* 注意:对输入不作合法性检测! */
{
unsigned long int result = 0;
char a, i;
i = 0;
while(i < 8 && lpString[i] != '\0'){
if (lpString[i] > '9')
a = (lpString[i] & 0x1f) + 9;
else
a = lpString[i] - '0';
result = (result << 4) + a;
i = i + 1;
}
return result;
}
void KeyGen(char *lpFingerPrint, char *lpRegCodeBuffer)
/* 注册码计算程序。 */
/* 入口参数:lpFingerPrint――机器码字串
lpRegCodeBuffer――存放注册码的缓冲区 */
/* 出口参数:lpRegCodeBuffer――注册码字串 */
{
unsigned long int m;
m = uAsctohex(lpFingerPrint + 1);
m = m ^ 0x6F37AE52;
m = (m << 27) + (m >> 5);
Hextoasc(m, lpRegCodeBuffer);
}
[注意]APP应用上架合规检测服务,协助应用顺利上架!