小弟处女作,请多关照!以小弟首篇破文祝老婆生日快乐!

Hamber(hitetoshi@163.com)
软件:X-posure(骨密度计量学)
主页:http://www.pronosco.com/
说明:Pronosco X-posure  System 是多年来骨密度计量学中研究和发展的顶点。
工具:SoftICE,W32DASM
平台:Windows 2000
纯属技术交流,请勿随意散步或用于商业用途。
该软件安装后有Xposure.exe和Settings.exe两个重要文件。Xposure.exe为主程序文件,如果没有输入序列号,则在运行时会弹出对话框告知序列号错误。Settings.exe用来输入和验证序列号。

运行Settings.exe,在Serial中输入1234567890,SoftICE例行手续,不再介绍,断下后走到这里:

:004060BB 8BF1                    mov esi, ecx
:004060BD 8B842480000000          mov eax, dword ptr [esp+00000080]  //序列号串长
:004060C4 C744247000000000        mov [esp+70], 00000000
:004060CC 83F80F                  cmp eax, 0000000F
:004060CF 0F84E4000000            je 004061B9  //不跳则MessageBox

看来序列号必须为15个字符。重新输入123456789098765,再走到:
:00406E0E 8B442410                mov eax, dword ptr [esp+10]  //第1个字符
:00406E12 64892500000000          mov dword ptr fs:[00000000], esp
:00406E19 81EC9C000000            sub esp, 0000009C
:00406E1F 53                      push ebx
:00406E20 56                      push esi
:00406E21 57                      push edi
:00406E22 8BF1                    mov esi, ecx
:00406E24 50                      push eax
:00406E25 E8660E0000              call 00407C90  //关键

:00406E31 8B9424BA000000          mov edx, dword ptr [esp+000000BA]//第3个字符

:00406E3D E84E0E0000              call 00407C90

:00406E49 8B9424BB000000          mov edx, dword ptr [esp+000000BB]//第4个字符

:00406E55 E8360E0000              call 00407C90

:00406E61 8B9424BC000000          mov edx, dword ptr [esp+000000BC]//第5个字符

:00406E6D E81E0E0000              call 00407C90

:00406E79 8B9424BD000000          mov edx, dword ptr [esp+000000BD]//第6个字符

:00406E85 E8060E0000              call 00407C90
:00406E8A 8B8C24D8000000          mov ecx, dword ptr [esp+000000D8]
:00406E91 8B1DFC344100            mov ebx, dword ptr [MSVCRT!isdigit]
:00406E97 33FF                    xor edi, edi
:00406E99 8901                    mov dword ptr [ecx], eax
:00406E9B 0FBE943CBF000000        movsx edx, byte ptr [esp+edi+000000BF]//第8个字符
:00406EA3 52                      push edx
:00406EA4 FFD3                    call ebx  //是否为数字
:00406EA6 83C404                  add esp, 00000004
:00406EA9 85C0                    test eax, eax
:00406EAB 0F8434010000            je 00406FE5
:00406EB1 47                      inc edi
:00406EB2 83FF06                  cmp edi, 00000006
:00406EB5 7CE4                    jl 00406E9B  //重复6次,即依次检查第8到第13个字符
:00406EB7 8D9424BF000000          lea edx, dword ptr [esp+000000BF]
:00406EBE 52                      push edx
:00406EBF FF1500354100            Call dword ptr [MSVCRT!atoi]  //将第8-13个字符转换为数字
:00406EC5 8B8C24E0000000          mov ecx, dword ptr [esp+000000E0]
:00406ECC 8B9424CA000000          mov edx, dword ptr [esp+000000CA]
:00406ED3 83C404                  add esp, 00000004
:00406ED6 8901                    mov dword ptr [ecx], eax  //保存转换的结果

从上面可以看出,第8到第13个字符必须为数字,00407C90这个位置也比较关键,跟进去看下:
:00407C90 6AFF                    push FFFFFFFF
:00407C92 68421E4100              push 00411E42
:00407C97 64A100000000            mov eax, dword ptr fs:[00000000]
:00407C9D 50                      push eax
:00407C9E 64892500000000          mov dword ptr fs:[00000000], esp
:00407CA5 83EC4C                  sub esp, 0000004C
:00407CA8 8A44245C                mov al, byte ptr [esp+5C]  //当前字符
:00407CAC 53                      push ebx
:00407CAD 88442460                mov byte ptr [esp+60], al  //当前字符
:00407CB1 33DB                    xor ebx, ebx
:00407CB3 0FBEC0                  movsx eax, al
:00407CB6 50                      push eax
:00407CB7 885C2465                mov byte ptr [esp+65], bl
:00407CBB FF15FC344100            Call dword ptr [MSVCRT!isdigit]  //是否为数字
:00407CC1 83C404                  add esp, 00000004
:00407CC4 85C0                    test eax, eax
:00407CC6 7420                    je 00407CE8        //跳则MessageBox
:00407CC8 8D4C2460                lea ecx, dword ptr [esp+60]  //当前字符
:00407CCC 51                      push ecx
:00407CCD FF1500354100            Call dword ptr [MSVCRT!atoi]    //转为数字
:00407CD3 8B4C2454                mov ecx, dword ptr [esp+54]
:00407CD7 83C404                  add esp, 00000004
:00407CDA 64890D00000000          mov dword ptr fs:[00000000], ecx
:00407CE1 5B                      pop ebx
:00407CE2 83C458                  add esp, 00000058
:00407CE5 C20400                  ret 0004

由此可见,第1,3,4,5,6个字符必须为数字。再来到这里:
:00406EE9 8A8C24B9000000          mov cl, byte ptr [esp+000000B9]  //第2个字符
:00406EF0 B02D                    mov al, 2D    //’-‘
:00406EF2 3AC8                    cmp cl, al
:00406EF4 0F8488010000            je 00407082    //不跳则MessageBox
…|
:00407082 388424BE000000          cmp byte ptr [esp+000000BE], al  //第7个字符
:00407089 0F84EB000000            je 0040717A  //不跳则MessageBox

:0040717A 388424C5000000          cmp byte ptr [esp+000000C5], al  //第14个字符
:00407181 0F84EE000000            je 00407275    //不跳则MessageBox

根据上面的分析,可以得出序列号的完整形式:A-BCDE-FGHIJK-L,其中的A-L必须全部为10进制数字。在Seril中输入1-2345-678987-6,继续,来到这里:
:00407290 64A100000000            mov eax, dword ptr fs:[00000000]
:00407296 8B542404                mov edx, dword ptr [esp+04]  //A(这里A即代表数字1,下同)
:0040729A 6AFF                    push FFFFFFFF
:0040729C 68321D4100              push 00411D32
:004072A1 50                      push eax
:004072A2 8B442414                mov eax, dword ptr [esp+14]  //B
:004072A6 64892500000000          mov dword ptr fs:[00000000], esp
:004072AD 83EC4C                  sub esp, 0000004C
:004072B0 03D0                    add edx, eax    //A+B
:004072B2 8B442464                mov eax, dword ptr [esp+64]  //C
:004072B6 53                      push ebx
:004072B7 8B5C2470                mov ebx, dword ptr [esp+70]  //E
:004072BB 55                      push ebp
:004072BC 8B6C2470                mov ebp, dword ptr [esp+70]  //D
:004072C0 03D0                    add edx, eax    //A+B+C
:004072C2 57                      push edi
:004072C3 8B7C247C                mov edi, dword ptr [esp+7C]  //FGHIJK(678987)
:004072C7 03D5                    add edx, ebp    //A+B+C+D
:004072C9 03D3                    add edx, ebx    //A+B+C+D+E
:004072CB 03D7                    add edx, edi    //A+B+C+D+E+FGHIJK
:004072CD 52                      push edx
:004072CE E87D090000              call 00407C50  //关键
:004072D3 39842480000000          cmp dword ptr [esp+00000080], eax与L比较
:004072DA 0F84BD000000            je 0040739D  //不跳则MessageBox

由于00407C70这个CALL后有个关键的跳转,跟进去看看,果然有重大发现:
:00407C50 8B4C2404                mov ecx, dword ptr [esp+04]  //得到的和
:00407C54 56                      push esi
:00407C55 33F6                    xor esi, esi
:00407C57 85C9                    test ecx, ecx
:00407C59 7E20                    jle 00407C7B  //为0则MessageBox
:00407C5B B867666666              mov eax, 66666667
:00407C60 F7E9                    imul ecx    //乘个0x66666667
:00407C62 C1FA02                  sar edx, 02    //积高为算术右移2位(除个4)
:00407C65 8BC2                    mov eax, edx
:00407C67 C1E81F                  shr eax, 1F    //逻辑右移1F(只要是无符号的数,除这么多,应该为0了吧)
:00407C6A 03D0                    add edx, eax  //右移前与右移后相加
:00407C6C 8D0492                  lea eax, dword ptr [edx+4*edx]  //做个简单的运算
:00407C6F D1E0                    shl eax, 1    //左移1位(乘个2)
:00407C71 2BC8                    sub ecx, eax    //原来的和减去得到的结果
:00407C73 03F1                    add esi, ecx
:00407C75 8BCA                    mov ecx, edx
:00407C77 85D2                    test edx, edx
:00407C79 7FE0                    jg 00407C5B  //直到相减的结果为0
:00407C7B 83FE09                  cmp esi, 00000009
:00407C7E 8BCE                    mov ecx, esi
:00407C80 7FD3                    jg 00407C55  //如果ESI大于9则重来
:00407C82 8BC6                    mov eax, esi  //返回最后的ESI
:00407C84 5E                      pop esi
:00407C85 C20400                  ret 0004

在这里,ESI充当了一个计数器的作用。最后用汉语翻译一下(C语言麻烦):
1:A+B+C+D+E+FGHIJK=M,设一计数器COUNT=0。
2:M*0x66666667,高双字为N。
3:将N算术右移2位(N/4)得P。
4:将P逻辑右移0x1F(应该得0吧)得Q。
5:P+Q=R。
6:R*4+R=S。
7:S逻辑左移1位(S*2)得T。
8:M-T=U;计数器COUNT+=U。
9:M=R,若R不为0,则转到第2步。
10:若COUNT>9,则COUNT=0并转到第2步。
最后根据前面分析的要求,COUNT必须等于L。

用这段代码算个合适的序列号出来,还是MessageBox,继续往下:

:0040646F E84C0F0000              call 004073C0  //这个CALL过不去

进去004073C0看看:
:004073C0 64A100000000            mov eax, dword ptr fs:[00000000]
:004073C6 6AFF                    push FFFFFFFF
:004073C8 68181E4100              push 00411E18
:004073CD 50                      push eax
:004073CE 8B442410                mov eax, dword ptr [esp+10]  //A
:004073D2 64892500000000          mov dword ptr fs:[00000000], esp
:004073D9 81EC80010000            sub esp, 00000180
:004073DF 53                      push ebx
:004073E0 56                      push esi
:004073E1 BE02000000              mov esi, 00000002
:004073E6 57                      push edi
:004073E7 2BC6                    sub eax, esi
:004073E9 0F84A3000000            je 00407492    //不跳则MessageBox(A必须为2)

:00407499 893520A14100            mov dword ptr [0041A120], esi  //C
:0040749F 85C0                    test eax, eax
:004074A1 0F8EBD060000            jle 00407B64  //跳则MessageBox(C不为0)
:004074A7 3BC6                    cmp eax, esi
:004074A9 0F8FB5060000            jg 00407B64  //跳则MessageBox(C必须小于等于2)
:004074AF A328A14100              mov dword ptr [0041A128], eax
:004074B4 8B8424A0010000          mov eax, dword ptr [esp+000001A0]    //B
:004074BB 85C0                    test eax, eax  
:004074BD 0F8EFE050000            jle 00407AC1  //跳则MessageBox(B不为0)
:004074C3 3BC6                    cmp eax, esi
:004074C5 0F8FF6050000            jg 00407AC1  //跳则MessageBox(B必须小于等于2)
:004074CB A324A14100              mov dword ptr [0041A124], eax
:004074D0 8B8424A8010000          mov eax, dword ptr [esp+000001A8]  //D
:004074D7 48                      dec eax
:004074D8 0F84E8020000            je 004077C6
:004074DE 48                      dec eax
:004074DF 0F8412020000            je 004076F7
:004074E5 48                      dec eax
:004074E6 0F8403010000            je 004075EF
…                  //后面是MessageBox之路,因此D必须小于等于3且大于0。

先看D为1的情况:
:004077C6 E865CEFFFF              call 00404630
:004077CB 84C0                    test al, al
:004077CD 0F85A3000000            jne 00407876
…                //下面是MessageBox之路
                  
看看这个00404630
:00404630 B001                    mov al, 01
:00404632 C3                      ret
所以004077CD是肯定会跳的,进去00407876看看:
:00407876 B901000000              mov ecx, 00000001
:0040787B 8B8424AC010000          mov eax, dword ptr [esp+000001AC]  //E
:00407882 890D2CA14100            mov dword ptr [0041A12C], ecx
:00407888 85C0                    test eax, eax
:0040788A 0F8E40010000            jle 004079D0  //跳则MessageBox(E不为0)
:00407890 3BC6                    cmp eax, esi
:00407892 0F8F38010000            jg 004079D0    //跳则MessageBox(E必须小于等于2)
:00407898 A330A14100              mov dword ptr [0041A130], eax
:0040789D 0F85FA000000            jne 0040799D
:004078A3 83F903                  cmp ecx, 00000003
:004078A6 0F85F1000000            jne 0040799D

再看看D为2的情况:
:004076F7 E834CFFFFF              call 00404630
:004076FC 84C0                    test al, al
:004076FE 0F85BB000000            jne 004077BF
在004077BF处:
:004077BF 8BCE                    mov ecx, esi
:004077C1 E9B5000000              jmp 0040787B

来到0040787B:
:0040787B 8B8424AC010000          mov eax, dword ptr [esp+000001AC]  //E
:00407882 890D2CA14100            mov dword ptr [0041A12C], ecx
:00407888 85C0                    test eax, eax
:0040788A 0F8E40010000            jle 004079D0  //跳则MessageBox(E不为0)
:00407890 3BC6                    cmp eax, esi
:00407892 0F8F38010000            jg 004079D0    //跳则MessageBox(E必须小于等于2)
:00407898 A330A14100              mov dword ptr [0041A130], eax
:0040789D 0F85FA000000            jne 0040799D
:004078A3 83F903                  cmp ecx, 00000003
:004078A6 0F85F1000000            jne 0040799D  //不跳则MessageBox

最后看看D为3的情况:
:004075EF E83CD0FFFF              call 00404630
:004075F4 84C0                    test al, al
:004075F6 0F85F1000000            jne 004076ED

来到004076ED:
:004076ED B903000000              mov ecx, 00000003
:004076F2 E984010000              jmp 0040787B
还是来到0040787B,但此时ecx已经为3了,故D不能为3。

到此打完收工,总结一下。序列号的形式如:A-BCDE-FGHIJK-L(所有字母代表10进制数字)。A==2;0<B<=2;0<C<=2;0<D<=2;0<E<=2;最后根据前面讲述的方法计算出L。
一个有效的序列号的例子:2-1212-678987-8

弄到这里,满以为大功告成,输入序列号,运行Xposure.exe,居然弹出MessageBox,说:The X-posure Card was not found. Please check that the X_posure Card is inseted correctly. Contact your distributor if the problem persists. 用暴破法绕过SmartCard的检查,满以为大功告成,居然又弹出MessageBox,说:Please insert a valid card in the reader.
唉,留到以后的作业。

附:新用户注册后要24小时才能发贴,利用这个时间把Xposure.exe也弄出来了,暴破的,没有一点技术含量,不提也罢。
最后发现有意思的,如果序列号的B为2,那么XPosure运行的是Demo版,为1才是正式版。