这是个老软件了,05年的,010Editor v2.0,程序没加壳,也没反调试,用Borland C++写的,下面开始。
载入OD以后,通过查找字符串可以找到注册相关的字符串,然后可以定位到注册部分的代码。
0046C3D1 |> \66:C745 B0 38>mov word ptr ss:[ebp-50],38 ; 上面是对注册名的完整性之类的验证,跳到这里算法才开始;
0046C3D7 |. 8D45 E4 lea eax,[local.7]
0046C3DA |. E8 B552F9FF call 010Edito.00401694 ; SEH
0046C3DF |. 8BD0 mov edx,eax
0046C3E1 |. FF45 BC inc [local.17] ; 堆栈 ss:[0012F48C]=00000001
0046C3E4 |. 8B4D 9C mov ecx,[local.25] ; ECX = 00CDC834
0046C3E7 |. 8B81 EC020000 mov eax,dword ptr ds:[ecx+2EC] ; EAX = 00CDB044
0046C3ED |. E8 0AD90D00 call 010Edito.00549CFC ; SEH?
0046C3F2 |. 8D55 E4 lea edx,[local.7] ; EDX指向注册名
0046C3F5 |. 52 push edx ; 注册名入栈
0046C3F6 |. FF35 A8275A00 push dword ptr ds:[5A27A8] ; 0入栈
0046C3FC |. E8 AF020000 call 010Edito.0046C6B0 ; 参数虽然是注册名,但是不用跟,这里不是关键
0046C401 |. 83C4 08 add esp,8
0046C404 |. FF4D BC dec [local.17]
0046C407 |. 8D45 E4 lea eax,[local.7]
0046C40A |. BA 02000000 mov edx,2
0046C40F |. E8 40381300 call 010Edito.0059FC54
0046C414 |. 66:C745 B0 44>mov word ptr ss:[ebp-50],44
0046C41A |. 8D45 E0 lea eax,[local.8]
0046C41D |. E8 7252F9FF call 010Edito.00401694
0046C422 |. 8BD0 mov edx,eax
0046C424 |. FF45 BC inc [local.17]
0046C427 |. 8B4D 9C mov ecx,[local.25]
0046C42A |. 8B81 F4020000 mov eax,dword ptr ds:[ecx+2F4]
0046C430 |. E8 D3290B00 call 010Edito.0051EE08 ; 出现假码
0046C435 |. 8D55 E0 lea edx,[local.8]
0046C438 |. 52 push edx ; 假码入栈
0046C439 |. FF35 A8275A00 push dword ptr ds:[5A27A8] ; 0入栈
0046C43F |. E8 80020000 call 010Edito.0046C6C4 ; 这里也不是关键
0046C444 |. 83C4 08 add esp,8
0046C447 |. FF4D BC dec [local.17]
0046C44A |. 8D45 E0 lea eax,[local.8]
0046C44D |. BA 02000000 mov edx,2
0046C452 |. E8 FD371300 call 010Edito.0059FC54 ; 出现假码
0046C457 |. 6A 01 push 1
0046C459 |. FF35 A8275A00 push dword ptr ds:[5A27A8] ; xiaomi入栈
0046C45F |. E8 ACE3FFFF call 010Edito.0046A810
0046C464 |. 83C4 08 add esp,8
0046C467 |. 8945 94 mov [local.27],eax
0046C46A |. 6A 01 push 1
0046C46C |. FF35 A8275A00 push dword ptr ds:[5A27A8]
0046C472 |. E8 25E3FFFF call 010Edito.0046A79C ; 关键call,跟进,看下面这个call调用完eax必须为0DB
0046C477 |. 83C4 08 add esp,8
0046C47A |. 8945 90 mov [local.28],eax
0046C47D |. 817D 90 DB000>cmp [local.28],0DB
0046C484 |. 75 35 jnz short 010Edito.0046C4BB ; eax的值与0DB比较,不相等就跳了
0046C486 |. 66:C745 B0 50>mov word ptr ss:[ebp-50],50
0046C48C |. BA 7D845C00 mov edx,010Edito.005C847D ; 注册码正确. 谢谢你购买 010 Editor!
0046A79C /$ 55 push ebp
0046A79D |. 8BEC mov ebp,esp
0046A79F |. FF75 0C push [arg.2] ; 1入栈
0046A7A2 |. FF75 08 push [arg.1] ; 注册名入栈
0046A7A5 |. E8 66000000 call 010Edito.0046A810 ; 算法call,跟进,看下面这个call调用完eax必须为2D
0046A7AA |. 83C4 08 add esp,8
0046A7AD |. 83E8 2D sub eax,2D ; eax=2D注册才能成功; Switch (cases 2D..E7)
0046A7B0 |. 74 0E je short 010Edito.0046A7C0
0046A7B2 |. 83E8 21 sub eax,21
0046A7B5 |. 74 17 je short 010Edito.0046A7CE
0046A7B7 |. 2D 99000000 sub eax,99
0046A7BC |. 74 09 je short 010Edito.0046A7C7
0046A7BE |. EB 15 jmp short 010Edito.0046A7D5
0046A7C0 |> B8 DB000000 mov eax,0DB ; switch要跳转到这里注册才会成功; Case 2D of switch
下面这个call才是真正的算法子程序,这里需要注意一下,分析的时候应该是从后面往前分析,因为我们前面已经分析出eax必须为2D,注册才能成功,所以先找关键字2D,果然在这里有一句0046AA57 > B8 2D000000 mov eax,2D。所以以此为突破口可以分析出前面的跳转哪些必须跳,哪些不能跳,把这些跳转都先注释一下,后面就好分析了。
0046A810 $ 55 push ebp
0046A811 . 8BEC mov ebp,esp
0046A813 . 83C4 C0 add esp,-40
0046A816 . B8 747D5C00 mov eax,010Edito.005C7D74
0046A81B . E8 3C651200 call 010Edito.00590D5C
0046A820 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A823 . 83C0 04 add eax,4
0046A826 . E8 35561300 call 010Edito.0059FE60
0046A82B . 84C0 test al,al ; al必须为0
0046A82D . 75 0F jnz short 010Edito.0046A83E ; 不能跳
0046A82F . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A832 . 83C0 08 add eax,8 ; eax指向假码
0046A835 . E8 26561300 call 010Edito.0059FE60
0046A83A . 84C0 test al,al ; al必须为0
0046A83C . 74 14 je short 010Edito.0046A852 ; 必须跳
0046A83E > B8 93000000 mov eax,93
0046A843 . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A846 . 64:8915 00000>mov dword ptr fs:[0],edx
0046A84D . E9 89020000 jmp 010Edito.0046AADB
0046A852 > 8D4D C4 lea ecx,dword ptr ss:[ebp-3C]
0046A855 . 51 push ecx
0046A856 . FF75 08 push dword ptr ss:[ebp+8]
0046A859 . E8 8A0A0000 call 010Edito.0046B2E8 ; 对注册码格式作检查
0046A85E . 83C4 08 add esp,8
0046A861 . 33C0 xor eax,eax
0046A863 . 8945 D4 mov dword ptr ss:[ebp-2C],eax ; 局部变量0012FE28 = 0
0046A866 > 66:C745 E8 08>mov word ptr ss:[ebp-18],8 ; 局部变量0012FE3C = 8
0046A86C . 8B55 D4 mov edx,dword ptr ss:[ebp-2C] ; edx = 0
0046A86F . 8B1495 D47B5C>mov edx,dword ptr ds:[edx*4+5C7BD4] ; 999
0046A876 . 8D45 FC lea eax,dword ptr ss:[ebp-4]
0046A879 . E8 EA511300 call 010Edito.0059FA68 ; 貌似无用
0046A87E . FF45 F4 inc dword ptr ss:[ebp-C] ; 局部变量0012FE48 ++
0046A881 . 8D55 FC lea edx,dword ptr ss:[ebp-4]
0046A884 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A887 . 83C0 04 add eax,4
0046A88A . E8 A9541300 call 010Edito.0059FD38
0046A88F . 50 push eax
0046A890 . FF4D F4 dec dword ptr ss:[ebp-C]
0046A893 . 8D45 FC lea eax,dword ptr ss:[ebp-4]
0046A896 . BA 02000000 mov edx,2
0046A89B . E8 B4531300 call 010Edito.0059FC54
0046A8A0 . 59 pop ecx
0046A8A1 . 84C9 test cl,cl ; cl必须为0
0046A8A3 . 74 14 je short 010Edito.0046A8B9 ; 这里必须跳才能注册成功
0046A8A5 . B8 E7000000 mov eax,0E7
0046A8AA . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A8AD . 64:8915 00000>mov dword ptr fs:[0],edx
0046A8B4 . E9 22020000 jmp 010Edito.0046AADB
0046A8B9 > FF45 D4 inc dword ptr ss:[ebp-2C]
0046A8BC . 837D D4 01 cmp dword ptr ss:[ebp-2C],1
0046A8C0 .^ 7C A4 jl short 010Edito.0046A866 ; 其实真正的算法从这里才开始
0046A8C2 . 807D C7 9C cmp byte ptr ss:[ebp-39],9C ; 假码的7,8位与9C比较
0046A8C6 . 0F85 83000000 jnz 010Edito.0046A94F ; 不相等就跳;这里不能跳
0046A8CC . 8A4D C4 mov cl,byte ptr ss:[ebp-3C] ; 假码的1,2位放到cl
0046A8CF . 324D CA xor cl,byte ptr ss:[ebp-36] ; 假码的1,2位与假码的13,14位异或
0046A8D2 . 884D C3 mov byte ptr ss:[ebp-3D],cl ; 异或的结果局部变量0012FE17
0046A8D5 . 8A45 C5 mov al,byte ptr ss:[ebp-3B] ; 假码的3,4位放到al
0046A8D8 . 3245 CB xor al,byte ptr ss:[ebp-35] ; 假码的3,4位与假码的15,16位异或
0046A8DB . 33D2 xor edx,edx ; 异或的结果放到dh
0046A8DD . 8AD0 mov dl,al
0046A8DF . C1E2 08 shl edx,8
0046A8E2 . 8A4D C6 mov cl,byte ptr ss:[ebp-3A] ; 假码的5,6位放到cl
0046A8E5 . 324D C9 xor cl,byte ptr ss:[ebp-37] ; 假码的5,6位与假码的11,12位异或
0046A8E8 . 33C0 xor eax,eax ; 异或的结果放到al
0046A8EA . 8AC1 mov al,cl
0046A8EC . 66:03D0 add dx,ax ; 3,4位和5,6位的结果放到了dx,3,4位在dh,5,6位在dl
0046A8EF . 66:8955 C0 mov word ptr ss:[ebp-40],dx ; 上面这个结果放到0012FE14
0046A8F3 . 8A55 C3 mov dl,byte ptr ss:[ebp-3D]
0046A8F6 . 52 push edx
0046A8F7 . E8 26130000 call 010Edito.0046BC22 ; 第三个参数是从这算的;关于这个参数见下面说明
0046A8FC . 59 pop ecx ; al保存了从1,2位假码算来的结果
0046A8FD . 33C9 xor ecx,ecx
0046A8FF . 8AC8 mov cl,al
0046A901 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A904 . 8948 18 mov dword ptr ds:[eax+18],ecx ; 1,2位的结果放到00C96D54
0046A907 . 66:8B55 C0 mov dx,word ptr ss:[ebp-40] ; 3,4,5,6位的异或结果放到dx
0046A90B . 52 push edx
0046A90C . E8 27130000 call 010Edito.0046BC38 ; 第四个参数是在这里算的
0046A911 . 59 pop ecx
0046A912 . 0FB7C8 movzx ecx,ax
0046A915 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A918 . 8948 1C mov dword ptr ds:[eax+1C],ecx
0046A91B . 8B55 08 mov edx,dword ptr ss:[ebp+8]
0046A91E . 837A 18 00 cmp dword ptr ds:[edx+18],0 ; 第三个参数不能为0
0046A922 . 74 15 je short 010Edito.0046A939 ; 不能跳
0046A924 . 8B4D 08 mov ecx,dword ptr ss:[ebp+8]
0046A927 . 8379 1C 00 cmp dword ptr ds:[ecx+1C],0
0046A92B . 74 0C je short 010Edito.0046A939 ; 不能跳
0046A92D . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A930 . 8178 1C E8030>cmp dword ptr ds:[eax+1C],3E8 ; 第四个参数必须是3E8才行
0046A937 . 76 46 jbe short 010Edito.0046A97F ; 必须跳
不好意思啊各位观众,这里我要剧透一下,不然可能会看版不懂,怎么冒出了个“第三个参数”?这其实是下面有一个函数,它根据注册名
和两个参数计算后8位注册码(注册码共16位),而这两个参数就是这个函数的第三、四个参数,其中一个参数是根据1、2位注册码与13
、14位注册码异或后,在做一系列计算来的,这个一系列计算就在上面算第三个参数的call里面。另一个参数是根据3,4,5,6位注册码与11
、12位,15、16位注册码做一系列计算来的。
这里有点麻烦了,感觉像个环,套住了,我要算后8位的注册码,必须知道第三个参数和第四个参数,从上面可以看到第四个参数必须是3E8,
但是第三个参数不确定(只知道不能为0)。而第三个参数又是1、2位注册码与15、16位注册码经过一系列运算来的,好像谁都是谁的前提,
无解。其实不是的,答案是超简单的,结论是第三个参数是可以随便定的!比如我把第三个参数确定为F2(我后面的注册机就是这么定的,
其实可以取00-FF之间任意数),那么第三、四个参数确定了,再配合注册名,后8位的注册码就算出来了,那1、2位的注册码也就算出来了。
第三、四个参数的call就不在这里贴了,跟进去看看很简单的。
这里接着上面的代码看吧
0046A939 > B8 E7000000 mov eax,0E7
0046A93E . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A941 . 64:8915 00000>mov dword ptr fs:[0],edx
0046A948 . E9 8E010000 jmp 010Edito.0046AADB
0046A94D . EB 30 jmp short 010Edito.0046A97F
0046A94F > 807D C7 FC cmp byte ptr ss:[ebp-39],0FC ; 假码的78位与0FC比较不相等就跳
0046A953 . 75 16 jnz short 010Edito.0046A96B ; 不能跳
这里又要解释一下,上面分析说了根据eax为2D分析出的跳转哪些该跳,哪些不该跳。其实这些跳转不是一条线路的,分了两条线路,上面这
个78位与0FC比较就是其中一条支线,经过我的分析,这条支线是行不通的,所以程序不应该跳到这小段代码。
0046A955 . 8B4D 08 mov ecx,dword ptr ss:[ebp+8]
0046A958 . C741 18 FF000>mov dword ptr ds:[ecx+18],0FF
0046A95F . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A962 . C740 1C 01000>mov dword ptr ds:[eax+1C],1
0046A969 . EB 14 jmp short 010Edito.0046A97F
0046A96B > B8 E7000000 mov eax,0E7
0046A970 . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A973 . 64:8915 00000>mov dword ptr fs:[0],edx
0046A97A . E9 5C010000 jmp 010Edito.0046AADB
0046A97F > 8B4D 08 mov ecx,dword ptr ss:[ebp+8]
0046A982 . FF71 1C push dword ptr ds:[ecx+1C] ; 第四个参数,由假码的5,6,7,8算来,结果必须是xxxx03E8
0046A985 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A988 . FF70 18 push dword ptr ds:[eax+18] ; 第三个参数,由假码的1,2位算来,我算的时候是F2
0046A98B . 807D C7 9C cmp byte ptr ss:[ebp-39],9C
0046A98F . 0F94C2 sete dl
0046A992 . 83E2 01 and edx,1
0046A995 . 52 push edx ; 第二个参数,索引开始号
0046A996 . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046A999 . 83C0 04 add eax,4
0046A99C . E8 2F74F9FF call 010Edito.00401DD0 ; 把注册名取到eax;这个函数的参数只有一个eax
0046A9A1 . 50 push eax ; 第一个参数,注册名
0046A9A2 . E8 D90F0000 call 010Edito.0046B980 ; 根据注册名算结果;关键call,跟进!
0046A9A7 . 83C4 10 add esp,10
0046A9AA . 8945 D0 mov dword ptr ss:[ebp-30],eax ; al必须与[ebp-38]相等
0046A9AD . 8A55 D0 mov dl,byte ptr ss:[ebp-30]
0046A9B0 . 80E2 FF and dl,0FF
0046A9B3 . 3A55 C8 cmp dl,byte ptr ss:[ebp-38] ; 根据注册名算得的结果与注册码的9,10位比较;
0046A9B6 . 74 14 je short 010Edito.0046A9CC ; 必须跳
0046A9B8 . B8 E7000000 mov eax,0E7
0046A9BD . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A9C0 . 64:8915 00000>mov dword ptr fs:[0],edx
0046A9C7 . E9 0F010000 jmp 010Edito.0046AADB
0046A9CC > 8B4D D0 mov ecx,dword ptr ss:[ebp-30]
0046A9CF . C1E9 08 shr ecx,8
0046A9D2 . 80E1 FF and cl,0FF
0046A9D5 . 3A4D C9 cmp cl,byte ptr ss:[ebp-37] ; 与注册码的11,12位比较
0046A9D8 . 74 14 je short 010Edito.0046A9EE ; 必须跳
0046A9DA . B8 E7000000 mov eax,0E7
0046A9DF . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046A9E2 . 64:8915 00000>mov dword ptr fs:[0],edx
0046A9E9 . E9 ED000000 jmp 010Edito.0046AADB
0046A9EE > 8B4D D0 mov ecx,dword ptr ss:[ebp-30]
0046A9F1 . C1E9 10 shr ecx,10
0046A9F4 . 80E1 FF and cl,0FF
0046A9F7 . 3A4D CA cmp cl,byte ptr ss:[ebp-36] ; 与注册码的13,14位比较
0046A9FA . 74 14 je short 010Edito.0046AA10 ; 必须跳
0046A9FC . B8 E7000000 mov eax,0E7
0046AA01 . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046AA04 . 64:8915 00000>mov dword ptr fs:[0],edx
0046AA0B . E9 CB000000 jmp 010Edito.0046AADB
0046AA10 > 8B4D D0 mov ecx,dword ptr ss:[ebp-30]
0046AA13 . C1E9 18 shr ecx,18
0046AA16 . 80E1 FF and cl,0FF
0046AA19 . 3A4D CB cmp cl,byte ptr ss:[ebp-35] ; 与注册码的15,16位比较
0046AA1C . 74 14 je short 010Edito.0046AA32 ; 必须跳
0046AA1E . B8 E7000000 mov eax,0E7
0046AA23 . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046AA26 . 64:8915 00000>mov dword ptr fs:[0],edx
0046AA2D . E9 A9000000 jmp 010Edito.0046AADB
0046AA32 > 807D C7 9C cmp byte ptr ss:[ebp-39],9C ; 注册码7,8位与9C比较?
0046AA36 . 75 30 jnz short 010Edito.0046AA68 ; 不能跳
0046AA38 . 8B4D 0C mov ecx,dword ptr ss:[ebp+C]
0046AA3B . 8B45 08 mov eax,dword ptr ss:[ebp+8]
0046AA3E . 3B48 18 cmp ecx,dword ptr ds:[eax+18]
0046AA41 . 76 14 jbe short 010Edito.0046AA57 ; 必须跳
0046AA43 . B8 4E000000 mov eax,4E
0046AA48 . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046AA4B . 64:8915 00000>mov dword ptr fs:[0],edx
0046AA52 . E9 84000000 jmp 010Edito.0046AADB
0046AA57 > B8 2D000000 mov eax,2D ; 跳到这里注册就成功了
0046AA5C . 8B55 D8 mov edx,dword ptr ss:[ebp-28]
0046AA5F . 64:8915 00000>mov dword ptr fs:[0],edx
0046AA66 . EB 73 jmp short 010Edito.0046AADB
----------------------0046A9A2 . E8 D90F0000 call 010Edito.0046B980 ;根据注册名算结果--------------
0046B994 |. 59 pop ecx
0046B995 |. 8945 F0 mov [local.4],eax ; 注册名长度
0046B998 |. 33D2 xor edx,edx
0046B99A |. 8955 F4 mov [local.3],edx
0046B99D |. 8B4D F4 mov ecx,[local.3]
0046B9A0 |. 3B4D F0 cmp ecx,[local.4] ; 注册名大于0?
0046B9A3 |. 0F8D 3B010000 jge 010Edito.0046BAE4
0046B9A9 |> 8B45 08 /mov eax,[arg.1]
0046B9AC |. 8B55 F4 |mov edx,[local.3]
0046B9AF |. 0FBE0C10 |movsx ecx,byte ptr ds:[eax+edx] ; 取注册名的第edx位
0046B9B3 |. 51 |push ecx
0046B9B4 |. E8 7FBB1200 |call 010Edito.00597538 ; 按位处理注册名,这里不跟进了,里面好像是用表处理的
0046B9B9 |. 59 |pop ecx
0046B9BA |. 8945 F8 |mov [local.2],eax
0046B9BD |. 837D 0C 00 |cmp [arg.2],0
0046B9C1 |. 0F84 86000000 |je 010Edito.0046BA4D
0046B9C7 |. 8B45 F8 |mov eax,[local.2]
0046B9CA |. 8B1485 2C805C>|mov edx,dword ptr ds:[eax*4+5C802C] ; 这里好像也是在查表,我注册机是按查表写的。
0046B9D1 |. 0355 FC |add edx,[local.1]
0046B9D4 |. 8B4D F8 |mov ecx,[local.2]
0046B9D7 |. 83C1 0D |add ecx,0D
0046B9DA |. 81E1 FF000000 |and ecx,0FF
0046B9E0 |. 33148D 2C805C>|xor edx,dword ptr ds:[ecx*4+5C802C]
0046B9E7 |. 8B45 F8 |mov eax,[local.2]
0046B9EA |. 83C0 2F |add eax,2F
0046B9ED |. 25 FF000000 |and eax,0FF
0046B9F2 |. 0FAF1485 2C80>|imul edx,dword ptr ds:[eax*4+5C802C]
0046B9FA |. 6B4D F4 13 |imul ecx,[local.3],13
0046B9FE |. 81E1 FF000000 |and ecx,0FF
0046BA04 |. 03148D 2C805C>|add edx,dword ptr ds:[ecx*4+5C802C]
0046BA0B |. 8B45 F4 |mov eax,[local.3]
0046BA0E |. 8D04C0 |lea eax,dword ptr ds:[eax+eax*8]
0046BA11 |. 8B4D 10 |mov ecx,[arg.3]
0046BA14 |. 8BD9 |mov ebx,ecx
0046BA16 |. C1E1 04 |shl ecx,4
0046BA19 |. 03CB |add ecx,ebx
0046BA1B |. 03C1 |add eax,ecx
0046BA1D |. 25 FF000000 |and eax,0FF
0046BA22 |. 031485 2C805C>|add edx,dword ptr ds:[eax*4+5C802C]
0046BA29 |. 6B45 F4 0D |imul eax,[local.3],0D
0046BA2D |. 8B4D 14 |mov ecx,[arg.4]
0046BA30 |. 8BD9 |mov ebx,ecx
0046BA32 |. C1E1 04 |shl ecx,4
0046BA35 |. 2BCB |sub ecx,ebx
0046BA37 |. 03C1 |add eax,ecx
0046BA39 |. 25 FF000000 |and eax,0FF
0046BA3E |. 031485 2C805C>|add edx,dword ptr ds:[eax*4+5C802C]
0046BA45 |. 8955 FC |mov [local.1],edx
0046BA48 |. E9 88000000 |jmp 010Edito.0046BAD5
0046BA4D |> 8B45 F8 |mov eax,[local.2]
0046BA50 |. 8B1485 2C805C>|mov edx,dword ptr ds:[eax*4+5C802C]
0046BA57 |. 0355 FC |add edx,[local.1]
0046BA5A |. 8B4D F8 |mov ecx,[local.2]
0046BA5D |. 83C1 3F |add ecx,3F
0046BA60 |. 81E1 FF000000 |and ecx,0FF
0046BA66 |. 33148D 2C805C>|xor edx,dword ptr ds:[ecx*4+5C802C]
0046BA6D |. 8B45 F8 |mov eax,[local.2]
0046BA70 |. 83C0 17 |add eax,17
0046BA73 |. 25 FF000000 |and eax,0FF
0046BA78 |. 0FAF1485 2C80>|imul edx,dword ptr ds:[eax*4+5C802C]
0046BA80 |. 8B4D F4 |mov ecx,[local.3]
0046BA83 |. 8BC1 |mov eax,ecx
0046BA85 |. C1E1 03 |shl ecx,3
0046BA88 |. 2BC8 |sub ecx,eax
0046BA8A |. 81E1 FF000000 |and ecx,0FF
0046BA90 |. 03148D 2C805C>|add edx,dword ptr ds:[ecx*4+5C802C]
0046BA97 |. 8B4D F4 |mov ecx,[local.3]
0046BA9A |. 8D0CC9 |lea ecx,dword ptr ds:[ecx+ecx*8]
0046BA9D |. 8B45 10 |mov eax,[arg.3]
0046BAA0 |. 8BD8 |mov ebx,eax
0046BAA2 |. C1E0 04 |shl eax,4
0046BAA5 |. 03C3 |add eax,ebx
0046BAA7 |. 03C8 |add ecx,eax
0046BAA9 |. 81E1 FF000000 |and ecx,0FF
0046BAAF |. 03148D 2C805C>|add edx,dword ptr ds:[ecx*4+5C802C]
0046BAB6 |. 6B45 F4 0D |imul eax,[local.3],0D
0046BABA |. 8B4D 14 |mov ecx,[arg.4]
0046BABD |. 8BD9 |mov ebx,ecx
0046BABF |. C1E1 04 |shl ecx,4
0046BAC2 |. 2BCB |sub ecx,ebx
0046BAC4 |. 03C1 |add eax,ecx
0046BAC6 |. 25 FF000000 |and eax,0FF
0046BACB |. 031485 2C805C>|add edx,dword ptr ds:[eax*4+5C802C]
0046BAD2 |. 8955 FC |mov [local.1],edx
0046BAD5 |> FF45 F4 |inc [local.3]
0046BAD8 |. 8B45 F4 |mov eax,[local.3]
0046BADB |. 3B45 F0 |cmp eax,[local.4]
0046BADE |.^ 0F8C C5FEFFFF \jl 010Edito.0046B9A9
0046BAE4 |> 8B45 FC mov eax,[local.1]
0046BAE7 |. 5B pop ebx
0046BAE8 |. 8BE5 mov esp,ebp
0046BAEA |. 5D pop ebp
0046BAEB \. C3 retn
----------------------0046A9A2 . E8 D90F0000 call 010Edito.0046B980 ;根据注册名算结果--------------
关于这一段算法的分析我没做过多注释,分析的时候我直接写在记事本里面了,因为要根据这段写注册机。
这段用到了四个局部变量,分别如下:
local.1存放后8位注册码临时结果(初始化为0);
local.2(当前字母ascii码);
local.3(当前字母的索引号);
local.4(注册名长度);
取出的字母ascii码为索引在5c802c表里查表,取出表中数字(一个整型)与local.1(初始化位0)相加得tmp1;
local.2加0D,结果与0FF做AND操作得tmp2,将tmp2为索引取表的结果与tmp1相异或放tmp1;
取当前字母ascii码,加上2F,结果与0FF做AND操作得tmp3,将tmp3为索引取表的结果与tmp1相乘(有符号乘)放tmp1;
当前字母索引×13(16进制)的结果与0FF做AND操作得tmp4,将tmp4为索引取表的结果与tmp1相加放tmp1;
当前字母索引×9得tmp5,取第三个参数左移4位与第三个参数相加再与tmp5相加,结果与0FF做AND操作放tmp5,将tmp5为索引取表的结果与tmp1相加放tmp1;
当前字母索引×0D得tmp6,取03E8左移4位减去03E8放tmp7,tmp6 += tmp7,and tmp7,0FF,将tmp7为索引取表的结果与tmp1相加放tmp1;
local.1 = tmp1;
迭代完注册名就OK了。
呵呵。这对着汇编码写的算法描述就好像我翻译英文一样呀,见笑了,大家凑合着看下吧。
关于对注册名的处理,那个call我没有完全搞定,经过试验,注册名是英文的话它会将它转为大写,这个过程好像不需要用到表,但是它确实是用到了表,不知道源码怎么写的。我的注册机也照样用的表,表是直接从内存窗口里面抠出来的。 注册名可以包含符号、字母和数字,但是汉字算出来的注册码还是不对,我没再搞了,大家有兴趣就试试吧。
注册机是用C写的控制台版的。
// crackCode.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "string.h"
void code2string( char* scode, int bcode, int fcode );
void halfcode2string( char* scode, int code );
int matrix[256] = {
969622712, 594890599,1593930257,1052452058,
890701766,1677293387, 394424968, 266815521,
1532978959,1211194088,2019260265, 729421127,
953225874,1117854514, 892543556,2000911200,
514538256,1400963072, 486675118,1862498216,
1136668818, 758909582,1653935295, 821063674,
888606944, 687085563, 890056597,1513495898,
365692427, 184357836, 677395407, 863045227,
818746596, 391985767,1842768403, 758385145,
1478392706,1985112985,1552765320, 746944881,
368385984,1758203153,1240817244, 660489060,
756944316,1290697955, 844453952, 288239112,
1769473626,1922176006, 826636519, 391520695,
1081548223,1069693142,1244729994, 766313326,
1101031894, 624951698,14501479,1794907983,
1460682958,1660839647,1104890686, 897721119,
1442187162, 480708164, 454443986,1064446153,
1595150448,1041527979,1145775470,1399869657,
255985995, 802693350,2005610078,1897360642,
2146073193,1538606632, 431647857, 964049561,
395138253,19164808, 856904574, 730737943,
708645054,1506870658, 933323739, 819349658,
1780571206, 236747382, 533160167,2042104933,
670325172,2040165158,1354372994, 705785180,
1669754395,1066536508,1426207888,1437950089,
741941201, 796931522,1694313338,1290302874,
1367672048,2039808424,1062939821, 954597728,
1668694488, 859122242,1369582617, 140269649,
53024683, 729221831, 816609203, 736893191,
55706320, 262747091,1629838835, 581764799,
1488480625,1607077349,1879925846,1453945819,
1521965565, 856558562,1530662365,1230847072,
1404918182,1281256849,1238970765, 272453753,
1640907491,2127893021, 350314733, 556617458,
654390256,1648581270, 531062411,1862873022,
1241517385,1471028336, 5121143,1444839026,
1183580211,1573659650,2018540230,1487873223,
234237236, 898254600,1023090193, 728843548,
2007454357,1451820833, 267351539, 302982385,
26807015, 865879122, 664886158, 195503981,
1625037691,1330347906,1742434311,1330272217,
1645368040, 542321916,1782121222, 411042851,
435386250,1176704752,1454246199,1136813916,
1707755005, 224415730, 201138891, 989750331,
1006010278,1147286905, 406860280, 840388503,
1282017578,1605698145,23396724, 862145265,
1898780916,1855549801,1571519230,2083204840,
1859876276,1602449334,1009413590, 690816450,
86131931, 345661263,1565025600, 857544170,
1329948960,1211787679, 994381573, 991984748,
1956475134,1098146294,1655714289, 659576699,
689116467,1485584392, 451884118, 255590636,
2108114754,1266252396,1589326471,2019907768,
15552498,1651075358, 614606175,1656823678,
797605325,1681594366,2005080248, 624648446,
884695971,1526931791,1595240948, 439447199,
2060396292, 680093752, 409028215, 469068267,
195583689,1791650630, 507724330,1364025102,
1094582668, 813049577,32316922,1240756058,
1176200235,2104494066, 325396055,1796606917,
1709197385, 525495836,1510101430, 735526761,
767523533,1374043776,1559389967, 567085571,
1560216161, 867042846,1001796703,1568754293,
628841972, 173812827, 379868455, 384973125
};
short int nameMatrix[256] = {
32, 32, 32, 32, 32, 32, 32, 32,
32, 40, 40, 40, 40, 40, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
72, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
132,132,132,132,132,132,132,132,
132,132, 16, 16, 16, 16, 16, 16,
16,385,385,385,385,385,385,257,
257,257,257,257,257,257,257,257,
257,257,257,257,257,257,257,257,
257,257,257, 16, 16, 16, 16, 16,
16,386,386,386,386,386,386,258,
258,258,258,258,258,258,258,258,
258,258,258,258,258,258,258,258,
258,258,258, 16, 16, 16, 16, 32
,
};
int _tmain(int argc, _TCHAR* argv[])
{
char sname[20];
scanf("%s", sname);
int bcode = 0; //注册码的后8位
int fcode = 0; //注册码的前8位
unsigned int i,k;
for ( i = 0; i < strlen(sname); i++ )
{
k = (unsigned int)sname[i];
if ( (nameMatrix[k] & 0x2) )
sname[i] -= 0x20;
}
for ( i = 0; i < strlen(sname); i++ )
{
k = (unsigned int)sname[i]; // 取当前字母ascii码
int itmp1 = matrix[k] + bcode;
unsigned int uitmp2 = (k+0x0D) & 0xFF;
itmp1 ^= matrix[uitmp2]; // 异或
uitmp2 = (k+0x2F) & 0xFF;
itmp1 *= matrix[uitmp2];
uitmp2 = (i*0x13) & 0xFF;
itmp1 += matrix[uitmp2];
uitmp2 = ( (0xF2<<4) + 0xF2 + (i*9) ) & 0xFF;
itmp1 += matrix[uitmp2];
uitmp2 = ( (0x03E8<<4) - 0x03E8 + (i*0x0D) ) & 0xFF;
itmp1 += matrix[uitmp2];
bcode = itmp1; // code 包含了后8位的注册码
}
printf("%X\n", bcode);
fcode = (bcode>>16) & 0xFF; // 注册码的1,2位等于第13,14位
fcode |= 0x9C000000; // 注册码的7,8位是9C,固定不能改
//3,4位的注册码等于注册码的15,16位与0xA9异或
fcode |= ( (bcode & 0xFF000000) ^ 0xA9000000 ) >> 16;
//5,6位的注册码等于注册码的11,12位与0x3B异或
fcode |= ( (bcode & 0x0000FF00) ^ 0x00003B00 ) << 8;
printf("%X\n", fcode);
//将code转换成注册码字符串
char scode[20];
code2string( scode, bcode, fcode );
printf("%s\n", scode);
return 0;
}
void code2string( char* scode, int bcode, int fcode )
{
halfcode2string( scode, fcode );
halfcode2string( &scode[10], bcode );
scode[19] = '\0';
}
void halfcode2string( char* scode, int code )
{
int j = 0;
for ( int i = 0; i < 4; i++ )
{
unsigned int tmpcode;
tmpcode = code >> (i*8);
char c = (char)(tmpcode>>4) & 0x0F;
if ( c < 0x0A ) // 是数字
c += 0x30;
else // 是字母
c += 0x37;
scode[j++] = c;
c = (char)tmpcode & 0x0F;
if ( c < 0x0A ) // 是数字
c += 0x30;
else // 是字母
c += 0x37;
scode[j++] = c;
if ( i == 1 || i == 3 )
scode[j++] = '-';
}
}
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。