标 题: EditPlus v2.12 注册过程分析
作 者: icytear
时 间: 2004-12-22,11:36
链 接: http://bbs.pediy.com/showthread.php?t=8783
第一篇破文,还望大家多多指教!!!!
【破解作者】icytear
【作者邮箱】icytear@126.com
【使用工具】SoftIce4.3.1,IDA4.5,PEiD0.92
【破解平台】WindowsXP Pro SP1.
【破解日期】2004.12.7 - 2004.12.22
【软件名称】EditPlus v2.12en
【软件大小】913,408 BYTE
【加壳方式】无壳
【下载地址】ftp://ftp.editplus.com/epp212_en.exe
【软件简介】
EditPlus是Internet时代的32位文本编辑程序,HTML编辑及程序员的Windows平台编辑器。它可以充分的替换记事本,它也提供网页作家及程序设计师许多强悍的功能。对于HTML、CSS、PHP、ASP、Perl、C/C++、Java、JavaScript及VBScript的语法突显。当然,它也可以在自定义语法文件后扩充其他的程序语言。嵌合网页浏览器作HTML页的预览,及FTP命令做本地文件上传到FTP服务器。其他功能还包含HTML工具栏、用户工具、列号、标尺、URL突显。自动完成、剪贴文本、行列选择、强大的搜索与替换、多重撤消/重做、拼写检测、自定义键盘快捷键、以及更多。
【破解声明】本文仅供技术交流、学习之用。
【破解内容】
1. 用PEiD打开editplus发现无壳。
2. 打开程序出现注册对话框,点击输入注册码,Username输入"icytear",Regcode输入"280060443",下断点
addr editplus
bpx GetWindowTextA
单击注册按钮,程序被中断,按F12退出GetWindowTextA函数,到如下位置
001B:004BFC91 PUSH DWORD PTR [ESP+08]
001B:004BFC95 PUSH DWORD PTR [ESP+08]
001B:004BFC99 PUSH DWORD PTR [ECX+1C]
001B:004BFC9C CALL [USER32!GetWindowTextA]
001B:004BFCA2 JMP 004BFCB6 ;---->按F12后到这里,goto #exit
...
001B:004BFCB6 RET 0008 ;#exit
按2次F10执行代码,程序返回到#R01
001B:0047C850 MOV EAX,[ESP+0C]
001B:0047C854 MOV ECX,[ESP+04]
001B:0047C858 PUSH ESI
001B:0047C859 MOV ESI,[ESP+0C]
001B:0047C85D PUSH EAX
001B:0047C85E PUSH ESI
001B:0047C85F CALL 004BFC8A
001B:0047C864 MOV AL,[ESI] ;#R01---->程序返回到这里
001B:0047C866 CMP AL,20 ;---->从前向后比较字符是否为空格
001B:0047C868 JZ 0047C86E ;---->为空格则跳转,继续比较下一个字符
001B:0047C86A CMP AL,09 ;---->比较这个字符是否为制表符
001B:0047C86C JNZ 0047C871 ;---->如果不为空格也不是制表符则跳转到#J01↓
001B:0047C86E INC ESI ;---->如果字符为空格或制表符则删除
001B:0047C86F JMP 0047C864 ;---->继续比较下一个字符(跳转到#R01↑)
===>:0047C871 PUSH ESI ;↑#J01---->用户名入栈
001B:0047C872 CALL [KERNEL32!lstrlen] ;---->不用说了吧,得到用户名长度
001B:0047C878 MOV ECX,[ESP+14]
001B:0047C87C TEST EAX,EAX ;---->检查是否输入了用户名
001B:0047C87E MOV [ECX],EAX ;---->把结果保存起来
001B:0047C880 JLE 0047C899
001B:0047C882 MOV EAX,[ECX]
001B:0047C884 MOV DL,[ESI+EAX-01] ;---->取出最后一个字符
001B:0047C888 CMP DL,20 ;---->比较是否为空格
001B:0047C88B JZ 0047C892
001B:0047C88D CMP DL,09
001B:0047C890 JNZ 0047C899
001B:0047C892 DEC EAX ;---->继续向前比较
001B:0047C893 TEST EAX,EAX
001B:0047C895 MOV [ECX],EAX
001B:0047C897 JG 0047C882
001B:0047C899 MOV EDX,[ECX]
001B:0047C89B MOV BYTE PTR [ESI+EDX],00 ;---->删除末尾的空格和制表符
001B:0047C89F MOV EAX,[ECX]
001B:0047C8A1 TEST EAX,EAX ;
001B:0047C8A3 JNZ 0047C8AD
001B:0047C8A5 PUSH 40
001B:0047C8A7 CALL [USER32!MessageBeep]
001B:0047C8AD MOV EAX,ESI
001B:0047C8AF POP ESI
001B:0047C8B0 RET
上面的代码大概的意思就是:检查输入的用户名开始和末尾是否为有效字符(非空格和制表符)。
然后返回到#R02:
...
001B:0047C8E1 CALL 0047C850 ;---->取输入的用户名
001B:0047C8E6 MOV EBX,EAX ;#R02---->D EAX;EAX指向的就是输入的用户名icytear
001B:0047C8E8 MOV EAX,[ESP+20] ;---->[esp+20]存的是用户名的长度
001B:0047C8EC ADD ESP,10 ;---->平衡堆栈
001B:0047C8EF TEST EAX,EAX ;---->检查输入的用用户名是否有效
001B:0047C8F1 JZ 0047C9B1
001B:0047C8F7 LEA EAX,[ESP+0C] ;---->SS:[ESP+0C] = 00000034
001B:0047C8FB LEA ECX,[ESP+14] ;---->SS:[ESP+14] = 0
001B:0047C8FF PUSH EAX
001B:0047C900 PUSH 31
001B:0047C902 LEA EDX,[ESI+5C]
001B:0047C905 PUSH ECX
001B:0047C906 PUSH EDX
001B:0047C907 CALL 0047C850 ;---->用上面同样的方法得到输入的注册码
001B:0047C90C MOV ECX,[ESP+1C] ;---->[ESP+1C]输入的注册码长度
001B:0047C910 ADD ESP,10 ;---->平衡堆栈
001B:0047C913 TEST ECX,ECX ;---->检查有效注册码长度
001B:0047C915 MOV EDI,EAX
001B:0047C917 JZ 0047C9B1
001B:0047C91D XOR EAX,EAX
001B:0047C91F TEST ECX,ECX
001B:0047C921 JLE 0047C93B
001B:0047C923 XOR ECX,ECX
001B:0047C925 MOV CL,[EDI+EAX] ;---->从输入的注册码取一个字符
001B:0047C928 INC EAX ;---->移动指针指向下一个字符
001B:0047C929 MOV DL,[ECX+00522C90] ;---->查表,把小写转换成大写
001B:0047C92F MOV [EDI+EAX-01],DL
001B:0047C933 MOV ECX,[ESP+0C]
001B:0047C937 CMP EAX,ECX
001B:0047C939 JL 0047C923
001B:0047C93B PUSH EDI ;---->把输入的注册码入栈
001B:0047C93C PUSH EBX ;---->输入的用户名入栈
001B:0047C93D CALL 0047CA60 ;#C01---->关键调用
001B:0047C942 ADD ESP,08
001B:0047C945 TEST EAX,EAX
001B:0047C947 JNZ 0047C961 ;---->注册成功的关键
001B:0047C949 PUSH FF
001B:0047C94B PUSH 10
001B:0047C94D PUSH 00005F81
001B:0047C952 CALL 004C7E94 ;---->这里就弹出错误对话框了
001B:0047C957 POP EDI
001B:0047C958 POP ESI
001B:0047C959 POP EBX
001B:0047C95A ADD ESP,00000230
001B:0047C960 RET
001B:0047C961 PUSH EDI
001B:0047C962 PUSH EBX
001B:0047C963 CALL 0047C3B0
...
进入#C01 (CALL 0047CA60)继续跟踪
001B:0047CA60 SUB ESP,0C
001B:0047CA63 PUSH EBX ;---->用户名入栈
001B:0047CA64 MOV EBX,[KERNEL32!lstrlen]
001B:0047CA6A PUSH ESI
001B:0047CA6B PUSH EDI
001B:0047CA6C MOV EDI,[ESP+1C] ;---->edi指向了用户名
001B:0047CA70 PUSH EDI
001B:0047CA71 CALL EBX ;---->call [lstrlen],得到用户名长度
001B:0047CA73 MOV ESI,EAX
001B:0047CA75 TEST ESI,ESI ;---->
001B:0047CA77 JNZ 0047CA80 ;---->跳到#C01.C1
001B:0047CA79 POP EDI
001B:0047CA7A POP ESI
001B:0047CA7B POP EBX
001B:0047CA7C ADD ESP,0C
001B:0047CA7F RET
001B:0047CA80 CALL 0047C9C0 ;#C01.C1---->跟进去
001B:0047CA85 PUSH ESI
001B:0047CA86 PUSH EDI
001B:0047CA87 PUSH 00
001B:0047CA89 CALL 0047CA10 ;#C01.C2---->
001B:0047CA8E ADD ESP,0C
001B:0047CA91 AND EAX,0000FFFF
001B:0047CA96 PUSH EAX
001B:0047CA97 LEA EAX,[ESP+10]
001B:0047CA9B PUSH 0051824C
001B:0047CAA0 PUSH EAX
001B:0047CAA1 CALL 004AEABC ;#C01.C3---->sprintf
001B:0047CAA6 MOV ESI,[ESP+2C]
001B:0047CAAA MOV AL,[ESP+18]
...
进入#C01.C1 (CALL 0047C9C0).
001B:0047C9C0 PUSH ESI
001B:0047C9C1 PUSH EDI
001B:0047C9C2 MOV ECX,00000080 ;---->计数 0x80
001B:0047C9C7 XOR EAX,EAX ;---->EAX清零
001B:0047C9C9 MOV EDI,00523410
001B:0047C9CE XOR ESI,ESI
001B:0047C9D0 REPZ STOSD ;---->从00523410~00523610清零
001B:0047C9D2 MOV EDX,00523410
001B:0047C9D7 MOV EAX,0000C0C1 ;#loop1--->第一层循环
001B:0047C9DC MOV ECX,00000001
001B:0047C9E1 TEST ESI,ECX ;#loop2--->第二层循环
001B:0047C9E3 JZ 0047C9E8
001B:0047C9E5 XOR [EDX],AX
001B:0047C9E8 ADD EAX,EAX
001B:0047C9EA SHL ECX,1
001B:0047C9EC XOR EAX,00004003
001B:0047C9F1 CMP ECX,00000100
001B:0047C9F7 JL 0047C9E1 ;---->跳转到#loop2
001B:0047C9F9 ADD EDX,02
001B:0047C9FC INC ESI
001B:0047C9FD CMP EDX,00523610
001B:0047CA03 JL 0047C9D7 ;---->跳转到#loop1
001B:0047CA05 POP EDI
001B:0047CA06 POP ESI
001B:0047CA07 RET
以上代码用C语言表示如下:
WORD list[0x80*2];
void sub_0047C9C0()
{
int i,j=0;
DWORD ieax,iecx,iesi=0;
WORD temp;
for(i=0;i<0x80*2;i++)
list[i] = 0;
do{
ieax = 0x0C0C1; //ieax = 49345
iecx = 1;
do{
if ((iesi&iecx)!=0)
{
temp = (WORD)(ieax&0x0FFFF);
list[j] = list[j]^temp;
}
ieax*=2;
iecx*=2;
ieax = ieax^0x04003;
}while(iecx<0x100);
j++;
iesi++;
}while(j<0x80*2);
}
从#C01.C1 CALL 出来
...
001B:0047CA85 PUSH ESI ;---->用户名长度
001B:0047CA86 PUSH EDI ;---->用户名指针入栈
001B:0047CA87 PUSH 00
001B:0047CA89 CALL 0047CA10 ;#C01.C2--->跟进去..
001B:0047CA8E ADD ESP,0C
...
进入#C01.C2 (CALL 0047CA10).
001B:0047CA10 MOV ECX,[ESP+08] ;---->ECX指向用户名'icytear'
001B:0047CA14 MOV EAX,[ESP+0C] ;---->EAX存用户名长度,
001B:0047CA18 PUSH ESI
001B:0047CA19 LEA ESI,[EAX+ECX] ;---->ESI指向了用户名的末尾'\0'
001B:0047CA1C CMP ECX,ESI
001B:0047CA1E JAE 0047CA4A ;---->如果大于等于则跳转#exit.
001B:0047CA20 MOV EAX,[ESP+08]
001B:0047CA24 PUSH EBX
001B:0047CA25 MOV EDX,EAX ;#loop3
001B:0047CA27 XOR EBX,EBX
001B:0047CA29 MOV BL,[ECX] ;---->开始逐个字符取用户名
001B:0047CA2B AND EDX,000000FF
001B:0047CA31 XOR EDX,EBX
001B:0047CA33 XOR EBX,EBX
001B:0047CA35 MOV BL,AH
001B:0047CA37 MOV AX,[EDX*2+00523410] ;---->(00523410~00523610) #C01.C1 CALL 生成的东东
001B:0047CA3F XOR AX,BX
001B:0047CA42 INC ECX
001B:0047CA43 CMP ECX,ESI
001B:0047CA45 JB 0047CA25 ;---->如果小于跳转倒#loop3↑
001B:0047CA47 POP EBX
001B:0047CA48 POP ESI
001B:0047CA49 RET
001B:0047CA4A MOV AX,[ESP+08] ;#exit.
001B:0047CA4F POP ESI
001B:0047CA50 RET
##C01.C2 (CALL 0047CA10) C语言代码如下:
char username[]="icytear";
int sub_0047CA10(int n,char *pname,int unamelen)
{
DWORD ieax,iebx,iedx,temp;
char *iecx;
iecx = pname;
ieax = unamelen;
if(*iecx == '\0')
return 0;
ieax = n;
do{
//MOV EDX,EAX
iedx = ieax;
//XOR EBX,EBX
iebx = 0;
//MOV BL,[ECX]
temp = *iecx;
iebx = iebx & 0xFFFFFF00;
iebx = iebx ^ temp;
//AND EDX,000000FF
iedx = iedx & 0x000000FF;
//XOR EDX,EBX
iedx = iedx ^ iebx;
//XOR EBX,EBX
iebx = 0;
//MOV BL,AH
temp = ieax;
temp = temp>>8;
temp = temp & 0x000000FF;
iebx = iebx & 0xFFFFFF00;
iebx = iebx ^ temp;
//MOV AX,[EDX*2+00523410]
temp = list[iedx];
ieax = ieax & 0xFFFF0000;
ieax = ieax ^ temp;
//XOR AX,BX
temp = iebx;
temp = temp & 0x0000FFFF;
ieax = ieax ^ temp;
iecx++;
}while(*iecx != '\0');
return ieax;
}
从#C01.C2 CALL 出来到 #C01CALL
...
001B:0047CA8E ADD ESP,0C ;---->#C01.C2 CALL 出来到这里
001B:0047CA91 AND EAX,0000FFFF ;---->AX是用用户名算出的结果
001B:0047CA96 PUSH EAX
001B:0047CA97 LEA EAX,[ESP+10]
001B:0047CA9B PUSH 0051824C ;---->;"%02X"
001B:0047CAA0 PUSH EAX ;
001B:0047CAA1 CALL 004AEABC ;---->sprintf,把用户名算出的16进制结果以字符形式保存
001B:0047CAA6 MOV ESI,[ESP+2C]
001B:0047CAAA MOV AL,[ESP+18] ;---->[ESP+18] = "5CF",由"icytear"算出的值
001B:0047CAAE ADD ESP,0C
001B:0047CAB1 MOV CL,[ESI+02] ;---->[ESI+02] 注册码的第三个字符
001B:0047CAB4 LEA EDI,[ESI+02]
001B:0047CAB7 CMP CL,AL ;---->比较,在这里比较注册码第三个字符是否为'5'
001B:0047CAB9 JZ 0047CAC4
001B:0047CABB POP EDI
001B:0047CABC POP ESI
001B:0047CABD XOR EAX,EAX
001B:0047CABF POP EBX
001B:0047CAC0 ADD ESP,0C
001B:0047CAC3 RET
001B:0047CAC4 MOV DL,[ESI+03] ;---->注册码第四个字符
001B:0047CAC7 MOV AL,[ESP+0D] ;---->"5CF"的第二个字符
001B:0047CACB CMP DL,AL ;---->比较注册码的第四个字符是否为'C'
001B:0047CACD JZ 0047CAD8
001B:0047CACF POP EDI
001B:0047CAD0 POP ESI
001B:0047CAD1 XOR EAX,EAX
001B:0047CAD3 POP EBX
001B:0047CAD4 ADD ESP,0C
001B:0047CAD7 RET
001B:0047CAD8 PUSH ESI ;---->注册码
001B:0047CAD9 CALL EBX ;---->KERNEL!lstrlen
001B:0047CADB SUB EAX,02
001B:0047CADE PUSH EAX ;---->EAX == 注册码长度 - 2;
001B:0047CADF PUSH EDI ;---->第三位以后的注册码
001B:0047CAE0 PUSH 00
001B:0047CAE2 CALL 0047CA10 ;---->前面出现过这个函数,用注册码第三为以后的字符计算出一个值
001B:0047CAE7 ADD ESP,0C
001B:0047CAEA AND EAX,0000FFFF
001B:0047CAEF PUSH EAX
001B:0047CAF0 LEA EAX,[ESP+10]
001B:0047CAF4 PUSH 0051824C ;---->"%02X"
001B:0047CAF9 PUSH EAX
001B:0047CAFA CALL 004AEABC ;---->sprintf
001B:0047CAFF MOV CL,[ESI] ;---->取注册码的第一个字符
001B:0047CB01 MOV AL,[ESP+18] ;---->由第三位以后的注册码计算出的值(第一个字符)
001B:0047CB05 ADD ESP,0C
001B:0047CB08 CMP CL,AL ;---->比较注册码的第一位
001B:0047CB0A JZ 0047CB15
001B:0047CB0C POP EDI
001B:0047CB0D POP ESI
001B:0047CB0E XOR EAX,EAX
001B:0047CB10 POP EBX
001B:0047CB11 ADD ESP,0C
001B:0047CB14 RET
001B:0047CB15 MOV DL,[ESI+01] ;---->取注册码的第二个字符
001B:0047CB18 MOV CL,[ESP+0D] ;---->由第三位以后的注册码计算出的值(第二个字符)
001B:0047CB1C XOR EAX,EAX
001B:0047CB1E CMP DL,CL ;---->比较注册码的第二位
001B:0047CB20 POP EDI
001B:0047CB21 POP ESI
001B:0047CB22 SETZ AL
001B:0047CB25 POP EBX
001B:0047CB26 ADD ESP,0C
001B:0047CB29 RET ;---->出#C01 CALL
3. 以上代码,验证了注册码的前四位,以上可知注册码的第3、4位是由用户名用sub_0047CA10(int,char*,int)函数计算出的值16进制码的字符格式的前两位, 在这里为"5C"; 注册码的第1、2位是由注册码第三位以后的字符用sub_0047CA10函数计算出的16进制码的字符格式的前两位,用"5C60443"计算的结果为"EF",所以在这时注册码应为"ef5c60443".
回到注册对话框重新输入注册码"ef5c60443",提示需要重启EditPlus激活注册码,看来第一步验证通过了.
4. 重启EditPlus,提示"Invalid registration code.",看来其它的地方还有注册码的验证过程,好我们回到程序继续跟踪...
这次跟踪注册码用"EF5C60443".
出#C01 CALL 到...
001B:0047C942 ADD ESP,08 ;---->返回到这里
001B:0047C945 TEST EAX,EAX ;---->
001B:0047C947 JNZ 0047C961 ;---->跳转则第一步注册成功
001B:0047C949 PUSH FF
001B:0047C94B PUSH 10
001B:0047C94D PUSH 00005F81
001B:0047C952 CALL 004C7E94 ;---->出错对话框,
001B:0047C957 POP EDI
001B:0047C958 POP ESI
001B:0047C959 POP EBX
001B:0047C95A ADD ESP,00000230
001B:0047C960 RET
===>:0047C961 PUSH EDI ;---->注册码
001B:0047C962 PUSH EBX ;---->用户名
001B:0047C963 CALL 0047C3B0 ;#C02---->关于注册表的动作????,跟进去看看..
001B:0047C968 ADD ESP,08
001B:0047C96B TEST EAX,EAX
001B:0047C96D JNZ 0047C986 ;--->输入"ef5c60443"时,在这里我们跳转了..
001B:0047C96F PUSH FF
001B:0047C971 PUSH EAX
001B:0047C972 PUSH 00004E7F
001B:0047C977 CALL 004C7E94 ;--->注册失败!!
001B:0047C97C POP EDI
001B:0047C97D POP ESI
001B:0047C97E POP EBX
001B:0047C97F ADD ESP,00000230
001B:0047C985 RET
===>:0047C986 MOV ECX,[ESI+000000D8]
001B:0047C98C PUSH EBX ;---->用户名
001B:0047C98D CALL 004C0367 ;---->CString::=
001B:0047C992 MOV ECX,[ESI+000000DC]
001B:0047C998 PUSH EDI ;---->注册码"EF5C60443"
001B:0047C999 CALL 004C0367 ;---->CString::=
001B:0047C99E MOV EAX,[ESI+000000E4]
001B:0047C9A4 MOV ECX,ESI
001B:0047C9A6 MOV DWORD PTR [EAX],00000000
001B:0047C9AC CALL 004BF482 ;---->CDialog::0nOK(void)
001B:0047C9B1 POP EDI
001B:0047C9B2 POP ESI
001B:0047C9B3 POP EBX
001B:0047C9B4 ADD ESP,00000230
001B:0047C9BA RET
001B:0047C9BB NOP
...
进入#C02 ...
001B:0047C3B0 SUB ESP,000000E0
001B:0047C3B6 PUSH EBX ;---->用户名(保护现场)
001B:0047C3B7 PUSH EBP
001B:0047C3B8 PUSH ESI
001B:0047C3B9 MOV ESI,[ESP+000000F0] ;---->让ESI指向用户名
001B:0047C3C0 PUSH EDI ;---->注册码(保护现场)
001B:0047C3C1 MOV EDI,[KERNEL32!lstrlen]
001B:0047C3C7 PUSH ESI ;---->用户名入栈了
001B:0047C3C8 CALL EDI ;---->得到用户名长度
001B:0047C3CA MOV EBX,EAX
001B:0047C3CC MOV EAX,[ESP+000000F8]
001B:0047C3D3 PUSH EAX ;---->EAX指向注册码
001B:0047C3D4 CALL EDI ;---->注册码长度
001B:0047C3D6 LEA EBP,[EBX+EAX+02] ;---->ebp = name_len+sn_len+2;
001B:0047C3DA MOV [ESP+14],EAX
001B:0047C3DE PUSH EBP
001B:0047C3DF CALL 004AD84D ;---->malloc(size_t)分配内存
001B:0047C3E4 MOV ECX,EBX
001B:0047C3E6 LEA EDI,[EAX+01]
001B:0047C3E9 MOV EDX,ECX
001B:0047C3EB MOV [EAX],BL ;---->把bl(用户名长度)存到新分配的空间中的第一个字节
001B:0047C3ED SHR ECX,02
001B:0047C3F0 REPZ MOVSD ;---->把用户名存到分配的空间中
001B:0047C3F2 MOV ECX,EDX
001B:0047C3F4 MOV [ESP+1C],EAX
001B:0047C3F8 AND ECX,03
001B:0047C3FB REPZ MOVSB ;---->把用户名存到分配的空间中
001B:0047C3FD MOV ECX,[ESP+18] ;---->注册码长度
001B:0047C401 MOV ESI,[ESP+000000FC] ;---->ESI指向注册码
001B:0047C408 MOV [EAX+EBX+01],CL ;---->把cl(注册码长度)存到分配的空间中
001B:0047C40C LEA EDI,[EAX+EBX+02]
001B:0047C410 MOV EAX,ECX
001B:0047C412 SHR ECX,02
001B:0047C415 REPZ MOVSD ;---->存注册码
001B:0047C417 MOV ECX,EAX
001B:0047C419 MOV EAX,51EB851F
001B:0047C41E IMUL EBP ;---->EDX:EAX=0x51eb851f * 0x12 = 5C28F5C2E
001B:0047C420 AND ECX,03
001B:0047C423 REPZ MOVSB ;---->存注册码,此时内存中的数据为"\x07icytear\x09EF5C60443"
001B:0047C425 SAR EDX,05 ;---->移位操作
001B:0047C428 MOV ECX,EDX
001B:0047C42A SHR ECX,1F
001B:0047C42D ADD EDX,ECX
001B:0047C42F LEA EDX,[EBP+EDX+0C] ;---->计算要下一个操作要分配多少空间n
001B:0047C433 PUSH EDX
001B:0047C434 MOV [ESP+18],EDX ;---->把n存下来
001B:0047C438 CALL 004AD84D ;---->malloc(size_t)分配内存
001B:0047C43D MOV EDI,[ESP+20] ;---->EDI指向"\x07icytear\x09EF5C60443"
001B:0047C441 PUSH EBP
001B:0047C442 LEA EDX,[ESP+1C] ;---->EDX指向上次分配空间大小n
001B:0047C446 MOV ESI,EAX ;---->让ESI指向最近分配的内存空间
001B:0047C448 PUSH EDI ;---->EDI指向"\x07icytear\x09EF5C60443",
001B:0047C449 PUSH EDX
001B:0047C44A PUSH ESI
001B:0047C44B MOV [ESP+38],ESI
001B:0047C44F CALL 0049F820 ;#C1---->关键,计算出一段值(size:1E),要写入注册表License,在此处按F9下一个断点
001B:0047C454 ADD ESP,18
001B:0047C457 TEST EAX,EAX
001B:0047C459 JZ 0047C477 ;---->跳转到#J1
001B:0047C45B PUSH EDI
001B:0047C45C CALL 004AD764 ;---->call????
001B:0047C461 PUSH ESI
001B:0047C462 CALL 004AD764 ;---->call????
001B:0047C467 ADD ESP,08
001B:0047C46A XOR EAX,EAX
001B:0047C46C POP EDI
001B:0047C46D POP ESI
001B:0047C46E POP EBP
001B:0047C46F POP EBX
001B:0047C470 ADD ESP,0E0
001B:0047C476 RET
===>:0047C477 MOV EAX,[ESP+10] ;#J1---->
001B:0047C47B ADD EAX,08
001B:0047C47E PUSH EAX
001B:0047C47F MOV [ESP+18],EAX
001B:0047C483 CALL 004AD84D ;---->malloc(size_t)分配内存
001B:0047C488 MOV ECX,[0051A58] ;---->[0051A58]==DWORD 0x182989DB 定值
001B:0047C48E MOV EBX,EAX
001B:0047C490 MOV [EBX],ECX ;---->write memory...
001B:0047C492 MOV EDX,[00518A58]
001B:0047C498 PUSH EDX
001B:0047C499 CALL 004AD987 ;---->void _cdecl srand(unsigned int)
001B:0047C49E CALL 004AD994 ;---->int rand(void)产生一个伪随机数
001B:0047C4A3 ADD EAX,EBP ;---->ebp == name_len+sn_len+2
001B:0047C4A5 MOV [EBX+04],AX ;---->write memory... to [ebx+4]
001B:0047C4A9 MOV EAX,[00518A58]
001B:0047C4AE INC EAX
001B:0047C4AF PUSH EAX
001B:0047C4B0 CALL 004A987 ;---->srand
001B:0047C4B5 ADD ESP,0C
001B:0047C4B8 CALL 004AD994 ;---->rand() 产生一个伪随机数
001B:0047C4BD MOV ECX,[ESP+10]
001B:0047C4C1 LEA EDI,[EBX+08]
001B:0047C4C4 ADD EAX,ECX
001B:0047C4C6 MOV [EBX+06],AX ;---->write memory... to [ebx+6] = 0xb78188+6
001B:0047C4CA MOV ECX,[ESP+10]
001B:0047C4CE MOV EDX,ECX
001B:0047C4D0 SHR ECX,02
001B:0047C4D3 REPZ MOVSD
001B:0047C4D5 MOV ECX,EDX
001B:0047C4D7 AND ECX,03
001B:0047C4DA REPZ MOVSB
...
把刚才生成的16进制码写注册表...
...
按F5运行程序,又提示重启editplus,退出程序..在这里程序被上面按F9下的那个断点中断(在#C02.#C1,001B:0047C44B),看来程序在关闭时又调用了一次#C02 Call,也就是又写了一次注册表,好我们用D edi命令查看edi指向的内存为"\x07icytear\x090F5C60443",看到区别了吗,前面我们看到的是"\x07icytear\x09EF5C60443",看来是被程序修改了,用这个再一次计算出16进制代码写入注册表,重启editplus时和第一次写得当然就不一样了,看来程序是在这里做了手脚..
我们按F12退出此次调用(CALL 0047C3B0)
...
001B:0042E691 CALL 0047C3B0
001B:0042E696 ADD ESP,08 ;---->到这里
...
我们向上查看代码,看到
...
001B:0042E661 TEST EAX,EAX
001B:0042E663 JZ 0042E69A ;---->这里有个跳转,如果跳就不能执行CALL 0047C3B0了,按F9在这里下个断点(把其它得断点可以先禁掉),如果跳转我们就可以注册成功..
重新输入注册码后退出editplus程序被中断,单步执行看看
...
001B:0042E653 MOV EAX,[ESI+B44]
001B:0042E659 MOV DWORD PTR [ESP+10],08
001B:0042E661 TEST EAX,EAX
001B:0042E663 JZ 0042E69A
001B:0042E665 MOV EAX,[ESI+0B30] ;---->D EAX,发现eax指向的还是"EF5C60443",由此判断可能是由于下面的代码改变了此字符串,我们保持此内存的窗口,继续往下执行
001B:0042E66B PUSH EDI
001B:0042E66C LEA EDI,[ESI+0B30]
001B:0042E672 MOV AL,[EAX]
001B:0042E674 CMP AL,30
001B:0042E676 JNZ 0042E67C
001B:0042E678 PUSH 31
001B:0042E67A JMP 0042E67E
001B:0042E67C PUSH 30
001B:0042E67E PUSH 00
001B:0042E680 MOV ECX,EDI
001B:0042E682 CALL 004C069E ;#C03---->执行此调用后,"EF5C60443"被改为"0F5C60443",看来我们的判断是真确的.
001B:0042E687 MOV EDI,[EDI]
001B:0042E689 MOV EAX,[ESI+B2C]
001B:0042E68F PUSH EDI
001B:0042E690 PUSH EAX
001B:0042E691 CALL 0047C3B0
...
我们再看看TEST EAX,EAX 中的EAX从那来的,向上看到MOV EAX,[ESI+B44],用D ESI+B44查看内存,显示如下
...
0023:00B7590C 01 00 00 00 .....
0023:00B7591C .......
...
那我们下一个内存断点试试,BPMD 0B7590C,再次输入注册码点击注册,OK,程序被中断在..
...
001B:0047C9A6 MOV DWORD PTR [EAX],0 ;---->这里改变内存,赋值0
001B:0047C9AC CALL 004BF482 ;---->中断在此
...
MOV DWORD PTR [EAX],0;把内存B7590C赋值0,我们要看看在那里把其改为1的,按F5执行程序,再次中断
...
001B:0047C718 MOV DWORD PTR [ECX],01 ;---->改变内存,赋值1
001B:0047C71E LEA ECX,[EDI+98] ;---->中断在此
...
我们向上看程序
001B:0047C707 MOV AL,[EAX,04] ;---->把第5位注册码存入AL
001B:0047C70A MOV CL,[ESP+10] ;---->那[esp+10]存的是什么呢?我们继续向上看程序
001B:0047C670 PUSH FF
001B:0047C672 PUSH 004E6183
001B:0047C677 MOV EAX,FS:[00000000]
001B:0047C67D PUSH EAX
001B:0047C67E MOV FS:[0],ESP
001B:0047C685 SUB ESP,10
001B:0047C688 PUSH EBP
001B:0047C689 PUSH ESI
001B:0047C68A PUSH EDI
001B:0047C68B MOV EDI,ECX
001B:0047C691 MOV DWORD PTR [EDI],004F41E0
001B:0047C697 MOV EAX,[EDI+D8]
001B:0047C69D MOV DWORD PTR [ESP+24],01
001B:0047C6A5 MOV EBP,[EAX] ;---->让EBP指向用户名"icytear"
001B:0047C6A7 MOV ESI,[EBP-08] ;---->ESI存用户名长度
001B:0047C6AA TEST ESI,ESI
001B:0047C6AC JLE 0047C71E ;---->跳过赋值1的那个指令
001B:0047C6AE XOR EAX,EAX
001B:0047C6B0 MOV ECX,01 ;---->ECX赋值1
001B:0047C6B5 TEST ESI,ESI
001B:0047C6B7 JLE 0047C6C5
===>:0047C6B9 XOR EDX,EDX ;#LOOP
001B:0047C6BB MOV DL,[EBP+EAX]
001B:0047C6BE ADD ECX,EDX
001B:0047C6C0 INC EAX
001B:0047C6C1 CMP EAX,ESI
001B:0047C6C3 JL 0047C6B9 ;---->跳到#LOOP,用户名每一位的值相加再加1;
001B:0047C6C5 LEA ECX,[ECX*8+ECX+0A]
001B:0047C6C9 MOV EAX,55555556
001B:0047C6CE IMUL ECX
001B:0047C6D0 MOV EAX,EDX
001B:0047C6D2 SHR EAX,1F
001B:0047C6D5 LEA ECX,[EAX+EDX+24]
001B:0047C6D9 AND ECX,8000000F
001B:0047C6DF JNS 0047C6E6
001B:0047C6E1 DEC ECX
001B:0047C6E2 OR ECX,-10
001B:0047C6E5 INC ECX
===>:0047C6E6 PUSH ECX
001B:0047C6E7 LEA EDX,[ESP+14]
001B:0047C6EB PUSH 0051700C ;---->"%1X"
001B:0047C6F0 PUSH EDX
001B:0047C6F1 CALL 004AEABC ;---->sprintf
001B:0047C6F6 MOV EAX,[EDI+DC]
001B:0047C6FC ADD ESP,0C
001B:0047C6FF MOV EAX,[EAX] ;---->EAX指向注册码
001B:0047C701 CMP DWORD PTR[EAX-8],05 ;---->[EAX-8]存着注册码长度,也就是说注册码长度应该大于5
001B:0047C605 JL 0047C712
001B:0047C607 MOV AL,[EAX,04] ;---->注册码第5位
001B:0047C60A MOV CL,[ESP+10] ;---->很显然是我们用用户名算出的那个值
001B:0047C60E CMP AL,CL ;---->验证第5位注册码,在这里我们计算出的是'D'
001B:0047C610 JZ 0047C71E ;---->第二次验证通过则注册成功..^_^,胜利!!
001B:0047C612 MOV ECX,[EDI+E4]
001B:0047C618 MOV DWORD PTR[ECX],01
...
5. 用我的用户名'icytear'计算出的值是'D'所以我的第5位注册码应为'D',前2位应用'5CD0443'由sub_0047CA10重新计算为'E4',重新输入注册码'E45CD0443',哈哈,注册成功!!
6. 注册机:
/******** Delete by icytear Jan 25,2005************
*
*好累,注册机大家写吧,别忘了给我发一份!!
*
**************************************************/
/******* Modify by icytear Jan 28,2005**************/
注册机
/******* Modify by icytear Jan 28,2005**************/
7.注册码:
####################
username: icytear
Regcode: E45CD0443
####################
转自:http://bbs.pediy.com/showthread.php?threadid=8783
C语言实现Editplus注册机
#include <stdio.h>
#include <windows.h>
WORD list[0x80*2];
char szUserName[256];
char szRegCode[] = "2800604434";/*add a char '4',2005.2.1*/
char *pszUserName = NULL;
int nUserNameLen;
void MakeCodeList() //sub_0047C9C0()
{
int i,j=0;
//BYTE *pList; //delete
DWORD ieax,iecx,iesi=0;
WORD temp;
//清零
for(i=0;i<0x80*2;i++)
list[i] = 0;
do{
ieax = 0x0C0C1; //ieax = 49345
iecx = 1;
do{
if ((iesi&iecx)!=0)
{
temp = (WORD)(ieax&0x0FFFF);
list[j] = list[j]^temp;
}
ieax*=2;
iecx*=2;
ieax = ieax^0x04003;
}while(iecx<0x100);
j++;
iesi++;
}while(j<0x80*2);
/* // 显示List ///
pList = (BYTE*)list;
for(i=0;i<0x80*4;i++)
{
if(i%8 == 0 && i!=0 && i%16 != 0)
printf("- ");
if(i%16 ==0 && i!=0)
printf("\n");
printf("%02X ",pList[i]);
}
/
*/
}
// sub_0047CA10(int n,char *pszUserName,int /*nUserNameLen*/)
int MakeRegCode1(int n,char *pszUserName,int /*nUserNameLen*/)
{
DWORD ieax,iebx,iedx,temp;
char *iecx;
iecx = pszUserName;
//ieax = nUserNameLen;
if(*iecx == '\0')
return 0;
ieax = n;
do{
//MOV EDX,EAX
iedx = ieax;
//XOR EBX,EBX
iebx = 0;
//MOV BL,[ECX]
temp = *iecx;
iebx = iebx & 0xFFFFFF00;
iebx = iebx ^ temp;
//AND EDX,000000FF
iedx = iedx & 0x000000FF;
//XOR EDX,EBX
iedx = iedx ^ iebx;
//XOR EBX,EBX
iebx = 0;
//MOV BL,AH
temp = ieax;
temp = temp>>8;
temp = temp & 0x000000FF;
iebx = iebx & 0xFFFFFF00;
iebx = iebx ^ temp;
//MOV AX,[EDX*2+00523410]
temp = list[iedx]; //因为我们的数组是WORD型,所以不用×2
ieax = ieax & 0xFFFF0000;
ieax = ieax ^ temp;
//XOR AX,BX
temp = iebx;
temp = temp & 0x0000FFFF;
ieax = ieax ^ temp;
iecx++;
}while(*iecx != '\0');
/* /del///
printf("\nEAX=%08X\nEDX=%08X\n",ieax,iedx);
///
*/
return ieax;
}
void CheckUserName()
{
char *p = pszUserName;
//删除用户名前面的空格和制表符
while( (*p == '\x20') || (*p == '\x9'))
{
pszUserName = ++p;
}
while( *p != '\0')
{
p++;
}
//删除用户名后面的空格和制表符
while( (*(--p) == '\x20') || (*p == '\x9'))
{
*p = '\0';
}
nUserNameLen = (int)(p - pszUserName + 1);
}
int key5()
{
DWORD key5 = 1;
for(int i=0; i<nUserNameLen; i++)
{
key5 += (DWORD)pszUserName[i];
}
__asm
{
pushad
mov ecx,key5
lea ecx,[ecx*8+ecx+0ah]
mov eax,55555556h
imul ecx
mov eax,edx
shr eax,1Fh
lea ecx,[eax+edx+24h]
and ecx,8000000Fh
jns end
dec ecx
or ecx,-10h
inc ecx
end:
mov key5,ecx
popad
}
//printf("%X",key5);
return key5;
}
int main()
{
DWORD dwReg;
char szReg[10];
printf(" =====================================\n");
printf(" * Editplus v2.12 KeyGen *\n");
printf(" * by icytear *\n");
printf(" =====================================\n\n");
printf("Please input your name for register: ");
scanf("%s",szUserName);
pszUserName = szUserName;
CheckUserName();
MakeCodeList();//sub_0047C9C0();
//生成第三,四位注册码
dwReg = MakeRegCode1(0,pszUserName,nUserNameLen);
sprintf(szReg,"%X",dwReg);
szRegCode[2] = szReg[0];
szRegCode[3] = szReg[1];
//生成第五位注册码
dwReg = key5();
sprintf(szReg,"%1X",dwReg);
szRegCode[4] = szReg[0];
//生成第一,二位注册码
dwReg = MakeRegCode1(0,&szRegCode[2],sizeof(szRegCode)-1);
sprintf(szReg,"%X",dwReg);
szRegCode[0] = szReg[0];
szRegCode[1] = szReg[1];
printf("\nYour RegCode is: %s\n\n",szRegCode);
return 0;
}