好友
阅读权限25
听众
最后登录1970-1-1
|
镇北看雪
发表于 2020-3-14 22:53
本帖最后由 镇北看雪 于 2020-3-14 23:13 编辑
工具:
———————————————————————————————————————————————————————
先运行一下程序,点击Help按钮显示帮助信息:发现其要求把按钮隐藏从而把RingZero的logo显示出来
- 随便输入用户名和注册码后点击Register按钮,程序没有任何反应
我们熟悉了程序之后接着我们用PEID查看其基本信息,得到其是Delphi编写的32位程序,无壳
- 然后我们需要了解各个按钮处做了什么处理,用E2A查看各个按钮事件的地址
发现有三个可疑的按钮事件,因为Again按钮现在被隐藏了,所以我们先对剩余两个按钮事件中的任意一个分析,那我们分析Registerz按钮吧。
根据E2A中的地址(00442f28)在OD中搜索,并再此地址处下断点,然后点击Registerz按钮程序会停在此地址处
然后我们F8单步向下执行同样注意:(判断跳转指令),因为有可能这就是成功与不成功的判断处。我们向下执行遇见了第一个判断跳转指令
此处按照我们刚才随便输入的用户名和序列号来讲其是会跳转的,因为我们刚才输入的肯定不对,那是不是不跳转其就说明我们输入的正确呢。正当我准备显式改变eip让其不跳转时(逆其道而为之),我发下在跳转指令下存在一句注释**请在代码编辑器里输入一个有效的长整数**,那意思是如果不跳转就说明我们输入的是无效的长整数。那说明我们刚才随便输入的序列号为有效的,那我们就不要改变eip了,继续F8向下执行看还有没有判断跳转指令。
刚F8两下又遇见一处跳转指令,是否这处跳转是判断序列号是否正确的关键跳转呢?
程序这里是不跳转的,因为我们输入的是错误的序列号,那是不是跳转了就说明我们序列号正确了呢。正当我准备改变eip时,又看到如果我们强制跳转其也会弹出一个消息框,内容意思为:代码得大于0。显然我们刚刚输入的111111是大于0的说明我们输入的合法。这样我们就不需要强制跳转继续往下执行看还有没有判断跳转指令?
刚F8几下我们又遇见了判断跳转指令,
此处按照输入的错误的序列号来讲其是需要跳转的,那是不是不跳转就说明我们的序列号正确呢,我们显式改变eip试一下(即让他不跳转,逆其道而为之)。
强制改变完eip后我们运行一下程序,发现Register按钮消失,同时Again按钮出现
既然again按钮出现了,我们不妨就来分析一下again按钮。
同样打开E2A查看again按钮事件地址,并在OD中搜索并下断点。点击Again按钮后程序将停在此地址处(004430bc)
我们发现此处的处理逻辑和Register按钮一样,所以我们按照上面的方法在走一遍后发现again按钮也消失,ringzero图标出现。(爆破思路就是这)
下面我们开始注册算法的分析:
打开OD重新运行程序,为了方便我们还输入和爆破时一样的用户名和注册码。
- 点击Register按钮后我们程序停在此按钮事件处理地址处
- 接着我们F8来到刚才我们强制改变eip的判断跳转指令前。
我们需要分析如何才能让程序自主实现不跳转(而不需要我们强制改变eip)
此跳转处的代码为
[Asm] 纯文本查看 复制代码 00442FB9 E8 EAF9FFFF call aLoNg3x_.004429A8
00442FBE 84C0 test al,al
00442FC0 74 30 je XaLoNg3x_.00442FF2
所以要想不跳转,需要让al不为0,而关键就在aLoNg3x_.004429A8函数
我们F7单步进入此关键函数分析。
[Asm] 纯文本查看 复制代码 004429A8 /$ 55 push ebp
004429A9 |. 8BEC mov ebp,esp
004429AB |. 83C4 F4 add esp,-0xC
004429AE |. 53 push ebx
004429AF |. 56 push esi
004429B0 |. 57 push edi
004429B1 |. 894D F8 mov [local.2],ecx ; 局部变量1:用户名
004429B4 |. 8955 FC mov [local.1],edx ; 局部变量2:未知?
004429B7 |. 8BF8 mov edi,eax
004429B9 |. 8B45 F8 mov eax,[local.2]
004429BC |. E8 2712FCFF call aLoNg3x_.00403BE8
004429C1 |. 33C0 xor eax,eax
004429C3 |. 55 push ebp
004429C4 |. 68 7A2A4400 push aLoNg3x_.00442A7A
004429C9 |. 64:FF30 push dword ptr fs:[eax]
004429CC |. 64:8920 mov dword ptr fs:[eax],esp
004429CF |. 8B45 F8 mov eax,[local.2]
004429D2 |. E8 5D10FCFF call aLoNg3x_.00403A34 ; 求用户名长度
004429D7 |. 83F8 04 cmp eax,0x4 (必须大于4)
004429DA |. 0F8E 82000000 jle aLoNg3x_.00442A62
004429E0 |. 33DB xor ebx,ebx
004429E2 |. 8B45 F8 mov eax,[local.2]
004429E5 |. E8 4A10FCFF call aLoNg3x_.00403A34 ; 求用户名长度
004429EA |. 85C0 test eax,eax
004429EC |. 7E 38 jle XaLoNg3x_.00442A26
004429EE |. 8945 F4 mov [local.3],eax ; 局部变量3:用户名长度
004429F1 |. BE 01000000 mov esi,0x1
004429F6 |> 8B45 F8 /mov eax,[local.2] ; 此为双循环
004429F9 |. E8 3610FCFF |call aLoNg3x_.00403A34
004429FE |. 83F8 01 |cmp eax,0x1
00442A01 |. 7C 1D |jl XaLoNg3x_.00442A20
00442A03 |> 8B55 F8 |/mov edx,[local.2]
00442A06 |. 0FB65432 FF ||movzx edx,byte ptr ds:[edx+esi-0x1]
00442A0B |. 8B4D F8 ||mov ecx,[local.2]
00442A0E |. 0FB64C01 FF ||movzx ecx,byte ptr ds:[ecx+eax-0x1]
00442A13 |. 0FAFD1 ||imul edx,ecx ; esi指针所指的字符 * eax指针所指字符
00442A16 |. 0FAFD7 ||imul edx,edi ; 然后在与edx相乘
00442A19 |. 03DA ||add ebx,edx ; 所得的结果累加到ebx中
00442A1B |. 48 ||dec eax ; 内层循环每循环一次改变一次eax指针(eax指针分别指向用户名的每一个字符)
00442A1C |. 85C0 ||test eax,eax
00442A1E |.^ 75 E3 |\jnz XaLoNg3x_.00442A03
00442A20 |> 46 |inc esi ; 外层循环每循环一次改变一次esi指针(esi也是指向用户名的每一个字符)
00442A21 |. FF4D F4 |dec [local.3]
00442A24 |.^ 75 D0 \jnz XaLoNg3x_.004429F6
00442A26 |> \8BC3 mov eax,ebx ;把累加和ebx除以0xA2C2A,得到的余数在传给ebx
00442A28 |. 99 cdq
00442A29 |. 33C2 xor eax,edx
00442A2B |. 2BC2 sub eax,edx
00442A2D |. B9 2A2C0A00 mov ecx,0xA2C2A
00442A32 |. 99 cdq
00442A33 |. F7F9 idiv ecx
00442A35 |. 8BDA mov ebx,edx
[/b]
[b]00442A37 |. 8B45 FC mov eax,[local.1] ; 把局部变量1传给eax
00442A3A |. B9 59000000 mov ecx,0x59
00442A3F |. 99 cdq
00442A40 |. F7F9 idiv ecx ; ecx = 局部变量1 / 0x59
00442A42 |. 8BC8 mov ecx,eax
00442A44 |. 8B45 FC mov eax,[local.1]
00442A47 |. BE 50000000 mov esi,0x50
00442A4C |. 99 cdq
00442A4D |. F7FE idiv esi ; ecx = ecx + (局部变量1 % 0x50)
00442A4F |. 03CA add ecx,edx
00442A51 |. 41 inc ecx
00442A52 |. 894D FC mov [local.1],ecx ; 局部变量1 = ecx
00442A55 |. 3B5D FC cmp ebx,[local.1] ; if(ebx == 局部变量1) 则不跳转,否则跳转
00442A58 |. 75 04 jnz XaLoNg3x_.00442A5E
00442A5A |. B3 01 mov bl,0x1
00442A5C |. EB 06 jmp XaLoNg3x_.00442A64
00442A5E |> 33DB xor ebx,ebx
00442A60 |. EB 02 jmp XaLoNg3x_.00442A64
00442A62 |> 33DB xor ebx,ebx
00442A64 |> 33C0 xor eax,eax
00442A66 |. 5A pop edx
00442A67 |. 59 pop ecx
00442A68 |. 59 pop ecx
00442A69 |. 64:8910 mov dword ptr fs:[eax],edx
00442A6C |. 68 812A4400 push aLoNg3x_.00442A81
00442A71 |> 8D45 F8 lea eax,[local.2]
00442A74 |. E8 3F0DFCFF call aLoNg3x_.004037B8
00442A79 \. C3 retn
00442A7A .^ E9 F907FCFF jmp aLoNg3x_.00403278
00442A7F .^ EB F0 jmp XaLoNg3x_.00442A71
00442A81 . 8BC3 mov eax,ebx
00442A83 . 5F pop edi
00442A84 . 5E pop esi
00442A85 . 5B pop ebx
00442A86 . 8BE5 mov esp,ebp
00442A88 . 5D pop ebp
00442A89 . C3 retn
到此为止其算法就是:
char 用户名[len];
if(len > 4)
{
for(int i = 0; i <= len - 1; i++)
for(int x = 0; x <=len - 1; x++)
{
ebx += (用户名 * 用户名[x] * edi);
}
ebx = ebx % 0xA2C2A
ecx = 局部变量1 / 0x59
ecx = ecx + (局部变量1 % 0x50)
局部变量1 = ecx
if(ebx == 局部变量1)
eax = 1;
else
eax = 0;
}
else
eax = 0;
因为只有当eax不为0时才能让关键函数跳转处实现不跳转,从而让Register按钮消失,让Again按钮出现。
只要eax最后等于1,就可以让关键函数处的跳转不跳转,从而让Register按钮消失,让Again按钮出现。
然而 edi 与 局部变量1 我们都不知道是如何得到的
我们需要分析 edi 和 局部变量1 是如何得到的,我们先分析局部变量1是怎么得到的。
在关键函数的开始部分我们发现
局部变量1是由edx赋值得到的,所以我们需要知道edx的值是怎么得到的,继续往上分析发现到达关键函数头部,说明edx应该是以参数的形式传给关键函数的,所以我们需要到关键函数外部的上方分析edx是怎么产生的。
(重新运行程序,然后点击Register按钮)F8向下运行来到关键函数附近
我们由代码mov edx,esi,而上方会测试esi的值总而判断所输入的序列号是否大于0(因为小于0其会跳转,并弹出消息框提示:输入的序列号应大于0)难道esi是序列号的十进制形式,半信半疑我们就试试:从堆栈中我们看到esi的值为0001b207,用十进制表示正好111111(即我们输入的序列号),所以我们得知局部变量1为我们输入的序列号所对应的十进制数值。
(由经验可得其上方肯定有函数来将序列号转化为对应的十进制值,既然我们已经知道了局部变量1的含义,我们就不往上面分析了)
下面我们就来分析一下edi是如何产生的
接着我们在进入关键函数中分析edi是怎么得到的
在关键函数头部我们看到 mov edi,eax,所以我们要知道eax值是怎么得到的。在往上分析发现到达关键函数头部,所以eax的值也是也是以参数的形式传给关键函数的,看来还得往关键函数外上方分析eax是如何得到的。
(运行程序,点击Register按钮),F8向下执行来到关键函数上方
可以看到eax的值是由0x445830地址处的值赋值得到的,所以我们需要在数据窗口跟踪0x445830地址处的值是怎么产生的。
在数据窗口搜索0x445830
现在其值为0,所以eax = 0,而eax又会赋给edx,所以edx = 0
现在我们知道局部变量1 = 输入序列号对应的十进制值,edx = 0
char 用户名[len];
if(len > 4)
{
for(int i = 0; i <= len - 1; i++)
for(int x = 0; x <=len - 1; x++)
{
ebx += (用户名 * 用户名[x] * edi);
}
ebx = ebx % 0xA2C2A
ecx = 局部变量1 / 0x59
ecx = ecx + (局部变量1 % 0x50)
局部变量1 = ecx
if(ebx == 局部变量1)
eax = 1;
else
eax = 0;
}
else
eax = 0;
我们由关键函数的算法得:
如果edi为0则ebx最后也为0(因为其每次都有edi相乘),
那么这处算法就一点意义都没有,因为无论用户名是什么,其计算的ebx都为0 .那么eax就无法等于1
所以edi不能为0,也就是地址0x445830处的值不能为0
————————————————————————
所以我们往关键函数上分析
我们又看到了那就唯一能明显能改变0x445830地址处数据的指令,但是执行此代码块需要输入无效的注册码,作者不会这莫坑吧!
(难道是先输入无效的注册码改变00445830地址处的数据后,在输入正确的序列号),不管怎样我们先试一试再说。
我们运行程序,然后改变序列号:我们需要输入无效的序列号让其执行上图的代码块,我们也不知道无效的序列号的规范,那就随便输入一堆序列号把,然后点击Register按钮
然后我们F8往下执行看看是不是无效的序列号,从而让其执行能改变00445830地址处数据的代码块,
我们输入还真是无效的序列号,弹出消息框提醒我们输入的序列号无效。然后我们继续向下F8,执行那句给00445830地址处的数据赋值的语句,看其能不能使此地址处的数据发生变化,
果然执行完`mov dword ptr ds:[0x445830],eax
`00445838地址处的数据不再是0了,关键函数处的算法有意义了(也就是有机会满足条件了),
现在我们知道了要想在关键函数处让eax = 1,从而让Register按钮消失。
需要先输入一个无效的序列号改变0x445830地址的值(让其不为零才有机会使后面的算法成立),然后再输入一个有效的序列号进行关键算法计算。
我们现在需要解决两个问题
第一:什么样的序列号有效,什么样的序列号无效(及有效序列号的规范)
第二:输入无效序列号会改变 0x445830地址值,其生成算法是什么。
——————————————————————————————————————————————————
下面我们先解决第一个问题:
(重新运行程序,随便输入序列号111111a)我们来到判断序列号是否有效的关键判断处,找到关键函数。F7进入
[Asm] 纯文本查看 复制代码 00402958 /$ 53 push ebx
00402959 |. 56 push esi
0040295A |. 57 push edi
0040295B |. 89C6 mov esi,eax
0040295D |. 50 push eax
0040295E |. 85C0 test eax,eax
00402960 |. 74 73 je XaLoNg3x_.004029D5
00402962 |. 31C0 xor eax,eax
00402964 |. 31DB xor ebx,ebx
00402966 |. BF CCCCCC0C mov edi,0xCCCCCCC
0040296B |> 8A1E /mov bl,byte ptr ds:[esi] ; Case 20 (' ') of switch 0040296E
0040296D |. 46 |inc esi
0040296E |. 80FB 20 |cmp bl,0x20 ; Switch (cases 20..78)
00402971 |.^ 74 F8 \je XaLoNg3x_.0040296B ; 得到输入的注册码里第一个不是空格的字符
00402973 |. B5 00 mov ch,0x0
00402975 |. 80FB 2D cmp bl,0x2D
00402978 |. 74 69 je XaLoNg3x_.004029E3
0040297A |. 80FB 2B cmp bl,0x2B
0040297D |. 74 66 je XaLoNg3x_.004029E5
0040297F |. 80FB 24 cmp bl,0x24
00402982 |. 74 66 je XaLoNg3x_.004029EA
00402984 |. 80FB 78 cmp bl,0x78
00402987 |. 74 61 je XaLoNg3x_.004029EA
00402989 |. 80FB 58 cmp bl,0x58
0040298C |. 74 5C je XaLoNg3x_.004029EA
0040298E |. 80FB 30 cmp bl,0x30
00402991 |. 75 13 jnz XaLoNg3x_.004029A6
00402993 |. 8A1E mov bl,byte ptr ds:[esi] ; Case 30 ('0') of switch 0040296E
00402995 |. 46 inc esi
00402996 |. 80FB 78 cmp bl,0x78
00402999 |. 74 4F je XaLoNg3x_.004029EA
0040299B |. 80FB 58 cmp bl,0x58
0040299E |. 74 4A je XaLoNg3x_.004029EA
004029A0 |. 84DB test bl,bl ; 如果没有第二个字符则跳转
004029A2 |. 74 20 je XaLoNg3x_.004029C4
004029A4 |. EB 04 jmp XaLoNg3x_.004029AA
004029A6 |> 84DB test bl,bl ; Default case of switch 0040296E
004029A8 |. 74 34 je XaLoNg3x_.004029DE ; 如果一个字符也没就跳转
004029AA |> 80EB 30 /sub bl,0x30
004029AD |. 80FB 09 |cmp bl,0x9
004029B0 |. 77 2C |ja XaLoNg3x_.004029DE
004029B2 |. 39F8 |cmp eax,edi ; 转换得到的数最大不能超过214748364
004029B4 |. 77 28 |ja XaLoNg3x_.004029DE
004029B6 |. 8D0480 |lea eax,dword ptr ds:[eax+eax*4]
004029B9 |. 01C0 |add eax,eax ; eax = eax*10
004029BB |. 01D8 |add eax,ebx
004029BD |. 8A1E |mov bl,byte ptr ds:[esi]
004029BF |. 46 |inc esi
004029C0 |. 84DB |test bl,bl
004029C2 |.^ 75 E6 \jnz XaLoNg3x_.004029AA
004029C4 |> FECD dec ch
004029C6 |. 74 10 je XaLoNg3x_.004029D8
004029C8 |. 85C0 test eax,eax
004029CA |. 7C 12 jl XaLoNg3x_.004029DE
004029CC |> 59 pop ecx
004029CD |. 31F6 xor esi,esi
004029CF |> 8932 mov dword ptr ds:[edx],esi
004029D1 |. 5F pop edi
004029D2 |. 5E pop esi
004029D3 |. 5B pop ebx
004029D4 |. C3 retn
004029D5 |> 46 inc esi
004029D6 |. EB 06 jmp XaLoNg3x_.004029DE
004029D8 |> F7D8 neg eax
004029DA |.^ 7E F0 jle XaLoNg3x_.004029CC
004029DC |.^ 78 EE js XaLoNg3x_.004029CC
004029DE |> 5B pop ebx ; Default case of switch 004029FE
004029DF |. 29DE sub esi,ebx
004029E1 |.^ EB EC jmp XaLoNg3x_.004029CF
004029E3 |> FEC5 inc ch ; Case 2D ('-') of switch 0040296E
004029E5 |> 8A1E mov bl,byte ptr ds:[esi] ; Case 2B ('+') of switch 0040296E
004029E7 |. 46 inc esi
004029E8 |.^ EB BC jmp XaLoNg3x_.004029A6
004029EA |> BF FFFFFF0F mov edi,0xFFFFFFF ; Cases 24 ('$'),58 ('X'),78 ('x') of switch 0040296E
004029EF |. 8A1E mov bl,byte ptr ds:[esi]
004029F1 |. 46 inc esi
004029F2 |. 84DB test bl,bl ; 如果是十六进制形式:则转换为其对应的十进制值
004029F4 |.^ 74 DF je XaLoNg3x_.004029D5
004029F6 |> 80FB 61 /cmp bl,0x61
004029F9 |. 72 03 |jb XaLoNg3x_.004029FE
004029FB |. 80EB 20 |sub bl,0x20
004029FE |> 80EB 30 |sub bl,0x30 ; Switch (cases 30..46)
00402A01 |. 80FB 09 |cmp bl,0x9
00402A04 |. 76 0B |jbe XaLoNg3x_.00402A11
00402A06 |. 80EB 11 |sub bl,0x11
00402A09 |. 80FB 05 |cmp bl,0x5
00402A0C |.^ 77 D0 |ja XaLoNg3x_.004029DE
00402A0E |. 80C3 0A |add bl,0xA ; Cases 41 ('A'),42 ('B'),43 ('C'),44 ('D'),45 ('E'),46 ('F') of switch 004029FE
00402A11 |> 39F8 |cmp eax,edi ; Cases 30 ('0'),31 ('1'),32 ('2'),33 ('3'),34 ('4'),35 ('5'),36 ('6'),37 ('7'),38 ('8'),39 ('9') of switch 004029FE
00402A13 |.^ 77 C9 |ja XaLoNg3x_.004029DE
00402A15 |. C1E0 04 |shl eax,0x4
00402A18 |. 01D8 |add eax,ebx
00402A1A |. 8A1E |mov bl,byte ptr ds:[esi]
00402A1C |. 46 |inc esi
00402A1D |. 84DB |test bl,bl
00402A1F |.^ 75 D5 \jnz XaLoNg3x_.004029F6
00402A21 \.^ EB A9 jmp XaLoNg3x_.004029CC
我们发现此处代码类似C语言中的itoa函数 (即把输入的字符串按格式转换为其对应的数值,不符合转换格式就返回0)
由关键判断处得如果局部变量1(也就是地址0019f730 的值)为0则序列号有效
所以关键函数(itoa函数)的算法有效序列号满足:
- 输入的序列号前面可以有多个空格
- 从第一个不为空格的字符开始,如果是以0-9的数字开头则序列号后不能有不是0-9的其他字符(意思是其就为一串由0-9组成的字符串),然后会将其转化为对应的十进制值存到eax中(我们上面分析的时候说过一定会有一个把序列号转化为其对应十进制值的函数的,猜想没错),把0019f730处的数据变为0表示此序列号为有效的
- 从第一个不为空格的字符开始,如果是以0x,0X,0$开头的序列号那么其后面所跟的字符只能是0-9,a-f(即把其看成是一个十六进制数值),然后会将其转化为对应的十进制值存到eax中,把0019f730处的数据变为0表示此序列号为有效的。
然后我们知道**有效序列号**满足这些条件也就知道**无效序列号**满足什么条件了。
——————————————————————————————————————————————————————
而我们刚才输入的是11111a其为无效的序列号正好我们看看当输入无效序列号后是怎么改变00445830地址处的数的
下面我们可以接着分析第二个问题:00445830地址处的值的产生算法
我们F8单步走出此分析序列号是否有效的函数,然后F7向下执行。其会弹出序列号无效的窗口,接着我们继续F7向下
然后找到改变00445830地址数据的关键函数F8执行到它,再F7进入分析数据产生的算法,
[Asm] 纯文本查看 复制代码
00442A8C /$ 55 push ebp
00442A8D |. 8BEC mov ebp,esp
00442A8F |. 51 push ecx
00442A90 |. 53 push ebx
00442A91 |. 56 push esi
00442A92 |. 57 push edi
00442A93 |. 8945 FC mov [local.1],eax
00442A96 |. 8B45 FC mov eax,[local.1]
00442A99 |. E8 4A11FCFF call aLoNg3x_.00403BE8
00442A9E |. 33C0 xor eax,eax
00442AA0 |. 55 push ebp
00442AA1 |. 68 212B4400 push aLoNg3x_.00442B21
00442AA6 |. 64:FF30 push dword ptr fs:[eax]
00442AA9 |. 64:8920 mov dword ptr fs:[eax],esp
00442AAC |. 8B45 FC mov eax,[local.1]
00442AAF |. E8 800FFCFF call aLoNg3x_.00403A34 ; 计算所输入注册码的长度
00442AB4 |. 83F8 05 cmp eax,0x5 ; 无效序列号长度大于5
00442AB7 |. 7E 3D jle XaLoNg3x_.00442AF6
00442AB9 |. BE 7B030000 mov esi,0x37B ; esi = 0x37b
00442ABE |. 8B45 FC mov eax,[local.1]
00442AC1 |. E8 6E0FFCFF call aLoNg3x_.00403A34
00442AC6 |. 8BD8 mov ebx,eax
00442AC8 |. 4B dec ebx
00442AC9 |. 85DB test ebx,ebx
00442ACB |. 7E 2B jle XaLoNg3x_.00442AF8
00442ACD |. B9 01000000 mov ecx,0x1
00442AD2 |> 8B45 FC /mov eax,[local.1] ; 此循环将我们输入的无效的序列号 用两个指针来指向第一个字符和第二个字符
00442AD5 |. 0FB60408 |movzx eax,byte ptr ds:[eax+ecx] ; esi +=( (第一个指针所指字符 % 0x11 + 1) * 第二个指针所指字符)
00442AD9 |. BF 11000000 |mov edi,0x11 ; 第一个指针后移,第二个指针也后移,直到第二个指针指向序列号最后一个字符
00442ADE |. 33D2 |xor edx,edx
00442AE0 |. F7F7 |div edi
00442AE2 |. 42 |inc edx
00442AE3 |. 8B45 FC |mov eax,[local.1]
00442AE6 |. 0FB64408 FF |movzx eax,byte ptr ds:[eax+ecx-0x1]
00442AEB |. 0FAFD0 |imul edx,eax
00442AEE |. 03F2 |add esi,edx
00442AF0 |. 41 |inc ecx
00442AF1 |. 4B |dec ebx
00442AF2 |.^ 75 DE \jnz XaLoNg3x_.00442AD2
00442AF4 |. EB 02 jmp XaLoNg3x_.00442AF8
00442AF6 |> 33F6 xor esi,esi
00442AF8 |> 8BC6 mov eax,esi
00442AFA |. B9 48710000 mov ecx,0x7148
00442AFF |. 99 cdq
00442B00 |. F7F9 idiv ecx ; eax = esi % 0x7148
00442B02 |. 8BC2 mov eax,edx
00442B04 |. 99 cdq
00442B05 |. 33C2 xor eax,edx
00442B07 |. 2BC2 sub eax,edx
00442B09 |. 8BD8 mov ebx,eax
00442B0B |. 33C0 xor eax,eax
00442B0D |. 5A pop edx
00442B0E |. 59 pop ecx
00442B0F |. 59 pop ecx
00442B10 |. 64:8910 mov dword ptr fs:[eax],edx
00442B13 |. 68 282B4400 push aLoNg3x_.00442B28
00442B18 |> 8D45 FC lea eax,[local.1]
00442B1B |. E8 980CFCFF call aLoNg3x_.004037B8
00442B20 \. C3 retn
00442B21 .^ E9 5207FCFF jmp aLoNg3x_.00403278
00442B26 .^ EB F0 jmp XaLoNg3x_.00442B18
00442B28 . 8BC3 mov eax,ebx
00442B2A . 5F pop edi
00442B2B . 5E pop esi
00442B2C . 5B pop ebx
00442B2D . 59 pop ecx
00442B2E . 5D pop ebp
00442B2F . C3 retn
char 无效序列号[len];
esi = 0x37b;
if(len > 5)
{
for(int i = 0; i <= len-2; i++)
{
esi += 无效序列号 * 无效序列号[i+1];
}
eax = esi % 0x7148;
}
else
eax = 0;
而eax的值又会赋给0x00445830,我们知道了0x00445830地址的值是怎么产生的了,
现在我们可以总结一下如何让Register按钮消失,同时让让Again按钮出现。
- 先输入一个无效的序列号点击Reginster按钮(序列号长度大于5)
- 再输入一个有效的序列号点击Reginster按钮。
当有效序列号和用户名(长度必须大于4)满足关键算法后则Reginster按钮消失。
正确序列号算法为:
[Asm] 纯文本查看 复制代码 #include <iostream>
using namespace std;
int main()
{
char str1[100]; //无效序列号
cout<<"请输入一个无效序列号:";
cin>>str1;
char str2[100] ; //用户名
cout<<endl<<"请输入有效有户名:";
cin>>str2;
int len = strlen(str1); //无效序列号长度
int esi = 0x37b;
int eax = 0;
int edx;
for(int i = 1; i <= len - 1; i++)
{
edx = str1[i] % 0x11;
edx++;
edx = str1[i - 1] * edx;
esi = edx + esi;
}
eax = esi % 0x7148;
eax = eax ^ 0;
eax = eax - 0;
int ebx = 0;
int len2 = strlen(str2); //用户名长度
for(int i = 0; i <= len2 - 1; i++)
for(int x = 0; x <= len2 - 1; x++)
{
ebx += (str2[i] * str2[x] * eax );
}
ebx = ebx % 0xA2C2A;
int a,b,c;
a = 0;
while(1)
{
b = a/0x59;
c = a%0x50;
b = b+c+1;
if(b == ebx)
{
cout<<endl<<"序列号的十进制形式为:"<<a;
break;
}
else
a++;
}
}
|
免费评分
-
查看全部评分
|