第一篇破文,还望大家多多指教!!!!
【破解作者】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
####################
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)