能力值:
( LV2,RANK:10 )
|
-
-
237 楼
该题可以使用爆破,那很简单。
下面是我跟踪的算法破解思路。
该算法是利用用户名的前3个字符进行运算,获得一个中间值,然后利用这个值不停的循环运算获得注册码。
最终,注册码的字符数和用户名的长度一致。
// 这里开始是程序的主题部分
00401050 . 817C24 08 110>cmp dword ptr [esp+8], 111
00401058 . 75 74 jnz short 004010CE
0040105A . 8B4424 0C mov eax, dword ptr [esp+C]
0040105E 66:3D EA03 cmp ax, 3EA
00401062 75 42 jnz short 004010A6
00401064 . E8 C7010000 call 00401230 //最主要的破解工作在这个函数块当中。
00401069 . 85C0 test eax, eax //测试eax是否为0,eax是0x401230的返回值,为0则成功注册,否则失败。
//真正有意义的工作从这里开始
00401230 /$ 8B0D BC564000 mov ecx, dword ptr [4056BC]
00401236 |. 83EC 30 sub esp, 30
00401239 |. 8D4424 00 lea eax, dword ptr [esp]
0040123D |. 53 push ebx
0040123E |. 56 push esi
0040123F |. 8B35 94404000 mov esi, dword ptr [<&USER32.GetDlgItemTextA>; USER32.GetDlgItemTextA
00401245 |. 6A 10 push 10 ; /Count = 10 (16.)
00401247 |. 50 push eax ; |Buffer dword ptr [esp]
00401248 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
0040124D |. 51 push ecx ; |hWnd => NULL
0040124E |. 33DB xor ebx, ebx ; |将ebx清0,ebx将要用来存放注册码比较的结果的值
00401250 |. FFD6 call esi ; \GetDlgItemTextA 获得Reg Name的输入框的输入字符
00401252 |. 83F8 03 cmp eax, 3 //返回的eax为实际输入的长度
00401255 |. 73 0B jnb short 00401262 //输入的用户名长度必须>=3才能继续。
00401257 |. 5E pop esi
00401258 |. B8 01000000 mov eax, 1 //直接赋值1,返回1,则注册失败
0040125D |. 5B pop ebx
0040125E |. 83C4 30 add esp, 30 //恢复堆栈。
00401261 |. C3 retn
00401262 |> A1 BC564000 mov eax, dword ptr [4056BC]
00401267 |. 8D5424 28 lea edx, dword ptr [esp+28]
0040126B |. 6A 10 push 10 //注册码将被保留的最大长度
0040126D |. 52 push edx //注册码存放的位置 dword ptr [esp+28]
0040126E |. 68 E9030000 push 3E9 //能够输入的最大长度(理论上)
00401273 |. 50 push eax //输入框的句柄 dword ptr [4056BC]
00401274 |. FFD6 call esi //获得Reg Key 输入框的输入字符
00401276 |. 0FBE4424 08 movsx eax, byte ptr [esp+8] //取输入的用户的第一个字符放入eax
0040127B |. 0FBE4C24 09 movsx ecx, byte ptr [esp+9] //取输入的用户的第二个字符放入ecx
00401280 |. 99 cdq · //eax带符号扩展
00401281 >|. F7F9 idiv ecx //带符号除法,商放在EAX中,余数放在EDX中
00401283 |. 8BCA mov ecx, edx
00401285 |. 83C8 FF or eax, FFFFFFFF
00401288 |. 0FBE5424 0A movsx edx, byte ptr [esp+A]
0040128D |. 0FAFCA imul ecx, edx
00401290 |. 41 inc ecx
00401291 |. 33D2 xor edx, edx
00401293 |. F7F1 div ecx
00401295 |. 50 push eax
//上面这一段的意思是只取用户名的前3个字符进行如下运算: 0xFFFFFFFF/(user[0]%user[1]*user[2]+1) 取商。
//该值将被压入堆栈供后面的运算使用
00401296 |. E8 A5000000 call 00401340 //该函数实现的功能就是将eax当中的值存入0x4050AC当中
0040129B |. 83C4 04 add esp, 4 //恢复堆栈
0040129E |. 33F6 xor esi, esi //esi清0
004012A0 |> E8 A5000000 /call 0040134A //将会循环调用的算法部分
004012A5 |. 99 |cdq
004012A6 |. B9 1A000000 |mov ecx, 1A
004012AB |. F7F9 |idiv ecx
004012AD |. 80C2 41 |add dl, 41 //前面几步的算法为 eax%0x1A + 0x41 存入dl当中,可见dl当中的必为大写字母。
004012B0 |. 885434 18 |mov byte ptr [esp+esi+18], dl //将算出来的值存放到 [esp+esi+18] 地址当中。
004012B4 |. 46 |inc esi
004012B5 |. 83FE 0F |cmp esi, 0F
004012B8 |.^ 72 E6 \jb short 004012A0 //如是循环15次。
//到此,用户名和注册码的输入以及用户的注册码的运算都已完成,接下来应该是验证我们根据用户名计算的注册码是否正确。
004012BA |. 57 push edi
004012BB |. 8D7C24 0C lea edi, dword ptr [esp+C] //载入输入的用户名的地址
004012BF |. 83C9 FF or ecx, FFFFFFFF //ecx = 0xFFFFFFFF
004012C2 |. 33C0 xor eax, eax
004012C4 |. 33F6 xor esi, esi //eax=0 esi=0
004012C6 |. F2:AE repne scas byte ptr es:[edi] //重复扫描字符串,遇到CX=0或ZF=1时停止。
004012C8 |. F7D1 not ecx //获得字符串的长度。
004012CA |. 49 dec ecx //已经运行一次循环,减1
004012CB |. 74 59 je short 00401326 //如果ecx=0,则退出。
//下面的一段代码是计算正确的注册码的过程。
004012CD |> 8A4434 0C /mov al, byte ptr [esp+esi+C] //将用户名的字符赋值给al
004012D1 |. C0F8 05 |sar al, 5 // al = user[i]>>5 ,如果为小写字母,则al右移后为3,大写字母则为2,数字则为1。
004012D4 |. 0FBEC0 |movsx eax, al
004012D7 |. 8D1480 |lea edx, dword ptr [eax+eax*4] //edx = eax*5
004012DA |. 8D04D0 |lea eax, dword ptr [eax+edx*8] //eax = eax*41
004012DD |. 8D0440 |lea eax, dword ptr [eax+eax*2] //eax = eax*3
004012E0 |. 85C0 |test eax, eax //测试eax是否为0
004012E2 |. 7E 0A |jle short 004012EE 如果<=0则跳转,不进行下面的计算
004012E4 |. 8BF8 |mov edi, eax //固定的,当为大写字母循环0xF6次,小写字母循环0x171次。,数字循环0x7B次
004012E6 |> E8 5F000000 |/call 0040134A //这个循环的主要作用就是不断的修改0x4050AC当中的值
004012EB |. 4F ||dec edi
004012EC |.^ 75 F8 |\jnz short 004012E6
004012EE |> E8 57000000 |call 0040134A
004012F3 |. 99 |cdq
004012F4 |. B9 1A000000 |mov ecx, 1A
004012F9 |. 8D7C24 0C |lea edi, dword ptr [esp+C] //edx中装入用户名
004012FD |. F7F9 |idiv ecx // eax/0x1A
004012FF |. 0FBE4C34 2C |movsx ecx, byte ptr [esp+esi+2C] // ecx中存放我们输入的注册码
00401304 |. 80C2 41 |add dl, 41
00401307 |. 0FBEC2 |movsx eax, dl
0040130A |. 2BC1 |sub eax, ecx // eax = eax/0x1A + 0x41 - key[i]
0040130C |. 885434 1C |mov byte ptr [esp+esi+1C], dl // 将正确的注册码写入[esp+esi+1C]当中,至此,正确的注册码已经获得。
00401310 |. 99 |cdq
00401311 |. 33C2 |xor eax, edx //eax^edx 存放的是 ,假设注册码正确,则eax=0,eax=eax^edx=edx
00401313 |. 83C9 FF |or ecx, FFFFFFFF //exc = -1
00401316 |. 2BC2 |sub eax, edx //eax^ecx-edx 假设注册码正确,则这些运算的结果为0 。
00401318 |. 03D8 |add ebx, eax //ebx = eax + ebx
0040131A |. 33C0 |xor eax, eax //eax=0
0040131C |. 46 |inc esi //esi+1
0040131D |. F2:AE |repne scas byte ptr es:[edi] //获得用户名的长度。
0040131F |. F7D1 |not ecx
00401321 |. 49 |dec ecx
00401322 |. 3BF1 |cmp esi, ecx
00401324 |.^ 72 A7 \jb short 004012CD //重新对下一个注册码字符进行比较。
00401326 |> 5F pop edi
00401327 |. 8BC3 mov eax, ebx
00401329 |. 5E pop esi
0040132A |. 5B pop ebx
0040132B |. 83C4 30 add esp, 30
0040132E \. C3 retn //将ebx的值赋给eax返回,为0则成功注册,否则失败。
0040132F 90 nop
00401330 /$ C705 C0564000>mov dword ptr [4056C0], 1
0040133A \. C3 retn
0040133B 90 nop
0040133C 90 nop
0040133D 90 nop
0040133E 90 nop
0040133F 90 nop
00401340 /$ 8B4424 04 mov eax, dword ptr [esp+4] //取出保存的0xFFFFFFFF/(user[0]%user[1]*user[2]+1)
00401344 |. A3 AC504000 mov dword ptr [4050AC], eax 首先将该值保存到0x4050AC的位置,下次的运算需要这个值。
00401349 \. C3 retn
//这里是核心的算法部分,将前面保存的对用户名的前三个字符运算获得的值进行如下操作。
0040134A /$ A1 AC504000 mov eax, dword ptr [4050AC]
0040134F |. 69C0 FD430300 imul eax, eax, 343FD
00401355 |. 05 C39E2600 add eax, 269EC3
0040135A |. A3 AC504000 mov dword ptr [4050AC], eax
0040135F |. C1F8 10 sar eax, 10
00401362 |. 25 FF7F0000 and eax, 7FFF
00401367 \. C3 retn
//上面这一段代码的功能是: eax = [4050AC]中的值 * 0x343FD + 0x269EC3, 然后将eax重新存入 4050AC,以备下次使用
// eax = (eax >> 0x10) & 0x7FFF ,获得的eax作为返回值。
|
能力值:
( LV2,RANK:10 )
|
-
-
250 楼
97楼找到一对
用户名:raolh
注册码:BUOUCRAGFSWIZZTA
大概思路:c32asm找到有对CDialogde 调用,因此可大概下断点,点击按钮进入关键段
|