第一篇破文,还望大家多多指教!!!!
【破解作者】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 CALL3. 以上代码,验证了注册码的前四位,以上可知注册码的第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
####################
[培训]内核驱动高级班,冲击BAT一流互联网大厂工
作,每周日13:00-18:00直播授课