【文章标题】: PsmPlayer的算法分析
【文章作者】: Pants
【作者邮箱】: 20323497@qq.com
【作者QQ号】: 20323497
【软件名称】: PsmPlayer 5.1 简体中文版
【软件大小】: 165 KB
【下载地址】: 自己搜索下载
【加壳方式】: nPack
【保护方式】: Name/Serial
【编写语言】: Borland C++
【使用工具】: OD、Filemon、PEiD
【软件介绍】: 可将 MIDI、WAV 转换为 MMF 格式的和弦铃声
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  PsmPlayer是一个小巧的手机和弦转换工具,未注册版本有功能限制。
  本人没¥买铃声,只能自己做了传入手机,为了得到“淡入淡出”功能,不得已拿起了屠刀……
  
  这个软件有点怪怪的,软件本身的界面上没有输入注册名和注册码的地方。(也许是我下的版本的问题)
  那它怎么注册呢?
  可能是读取某个文件的内容,或是某个注册表项吧。
  用Filemon发现程序读取了"C:\WINDOWS\psmplay.ini",打开后看到:
  
  [section]
  regist=0
  username=
  
  可以想到第一行就是注册码,第二行就是注册名了。
  我输入了
  regist=12345678
  username=Pants
  保存退出。
  
  打开OD,载入PsmPlayer,发现有加壳,用PEiD查看,EP段为".nPack"。
  
  00478280 >  833D 408F4700 0>cmp     dword ptr [478F40], 0            ; 检测标志
  00478287    75 05           jnz     short 0047828E                   ; 标志是0的话就退出程序
  00478289    E9 01000000     jmp     0047828F
  0047828E    C3              retn
  0047828F    E8 41000000     call    004782D5                         ; 内存空间申请
  00478294    B8 80824700     mov     eax, offset <模块入口点>
  00478299    2B05 088E4700   sub     eax, dword ptr [478E08]
  0047829F    A3 3C8F4700     mov     dword ptr [478F3C], eax
  004782A4    E8 5E000000     call    00478307                         ; 解码
  004782A9    E8 EC010000     call    0047849A                         ; dll加载
  004782AE    E8 F8060000     call    004789AB                         ; iat地址填充
  004782B3    E8 03060000     call    004788BB                         ; 重定位处理
  004782B8    A1 3C8F4700     mov     eax, dword ptr [478F3C]          ; 计算oep
  004782BD    C705 408F4700 0>mov     dword ptr [478F40], 1
  004782C7    0105 008E4700   add     dword ptr [478E00], eax
  004782CD    FF35 008E4700   push    dword ptr [478E00]
  004782D3    C3              retn                                     ; 返回程序的真正入口
  
  然后到达
  
  00401000      A1            db      A1
  00401001      5A            db      5A                               ;  CHAR 'Z'
  00401002      70            db      70                               ;  CHAR 'p'
  00401003      43            db      43                               ;  CHAR 'C'
  00401004      00            db      00
  
  光标停在[00401000]处时,用OD插件OllyDump脱壳。
  
  载入脱壳后的PsmPlayer,用OD字符串查找插件找username和regist,找到username后双击来到这里
  
  004070CC  |> \68 99774300   push    00437799                         ; /psmplay.ini; Case 15F of switch 00404472
  004070D1  |.  6A 0A         push    0A                               ; |BufSize = A (10.)
  004070D3  |.  68 30134400   push    00441330                         ; |ReturnBuffer = PsmPlaye.00441330
  004070D8  |.  68 98774300   push    00437798                         ; |Default = ""
  004070DD  |.  68 8F774300   push    0043778F                         ; |username           *停在这行,下断,F9
  004070E2  |.  68 87774300   push    00437787                         ; |section
  004070E7  |.  E8 D2F00200   call    <jmp.&kernel32.GetPrivateProfile>; \GetPrivateProfileStringA  *取注册名
  004070EC  |.  68 B4774300   push    004377B4                         ; /psmplay.ini
  004070F1  |.  6A 00         push    0                                ; |Default = 0
  004070F3  |.  68 AD774300   push    004377AD                         ; |regist
  004070F8  |.  68 A5774300   push    004377A5                         ; |section
  004070FD  |.  E8 9CEF0200   call    <jmp.&kernel32.GetPrivateProfile>; \GetPrivateProfileIntA  *取注册码
  00407102  |.  66:A3 2E13440>mov     word ptr [44132E], ax
  00407108  |.  66:8B15 2E134>mov     dx, word ptr [44132E]
  0040710F  |.  52            push    edx                              ; /Arg1
  00407110  |.  E8 C6B3FFFF   call    004024DB                         ; \PsmPlaye.004024DB  *这里是关键了
  00407115  |.  59            pop     ecx
  00407116  |.  66:A3 2C13440>mov     word ptr [44132C], ax
  
  跟进[00407110]的call
  
  004024DB  /$  55            push    ebp
  004024DC  |.  8BEC          mov     ebp, esp
  004024DE  |.  53            push    ebx
  004024DF  |.  56            push    esi
  004024E0  |.  8B5D 08       mov     ebx, dword ptr [ebp+8]
  004024E3  |.  68 30134400   push    00441330                         ; /String = "Pants"
  004024E8  |.  E8 3B3C0300   call    <jmp.&kernel32.lstrlen>          ; \lstrlenA
  004024ED  |.  8BF0          mov     esi, eax
  004024EF  |.  0FBFC6        movsx   eax, si
  004024F2  |.  50            push    eax                              ; /Arg2 = 00000005
  004024F3  |.  68 30134400   push    00441330                         ; |Arg1 = 00441330 ASCII "Pants"
  004024F8  |.  E8 490F0100   call    00413446                         ; \PsmPlaye.00413446
  
  要对注册名进行运算了,跟进
  
  00413446  /$  55            push    ebp
  00413447  |.  8BEC          mov     ebp, esp
  00413449  |.  53            push    ebx
  0041344A  |.  8B5D 08       mov     ebx, dword ptr [ebp+8]
  0041344D  |.  66:B8 FFFF    mov     ax, 0FFFF                        ;  将十六进制数FFFF放入ax中
  00413451  |.  33C9          xor     ecx, ecx
  00413453  |.  3B4D 0C       cmp     ecx, dword ptr [ebp+C]           ;  判断注册名是否为空
  00413456  |.  7D 28         jge     short 00413480                   ;  为空就玩完了
  00413458  |>  33D2          /xor     edx, edx                        ;  edx置零
  0041345A  |.  8A140B        |mov     dl, byte ptr [ebx+ecx]          ;  取注册名的一个字符
  0041345D  |.  C1E2 08       |shl     edx, 8                          ;  左移8位
  00413460  |.  66:33C2       |xor     ax, dx                          ;  与OxFFFF异或
  00413463  |.  33D2          |xor     edx, edx                        ;  edx置零
  00413465  |>  F6C4 80       |/test    ah, 80                         ;  ax中的高8位ah与0x80进行与运算
  00413468  |.  74 08         ||je      short 00413472                 ;  ah的最高位为1就跳
  0041346A  |.  03C0          ||add     eax, eax                       ;  自加一次
  0041346C  |.  66:35 2110    ||xor     ax, 1021                       ;  ax与0x1021异或
  00413470  |.  EB 02         ||jmp     short 00413474
  00413472  |>  03C0          ||add     eax, eax                       ;  自加一次
  00413474  |>  42            ||inc     edx                            ;  计数器加1
  00413475  |.  83FA 08       ||cmp     edx, 8                         ;  循环8次
  00413478  |.^ 7C EB         |\jl      short 00413465
  0041347A  |.  41            |inc     ecx                             ;  计数器加1
  0041347B  |.  3B4D 0C       |cmp     ecx, dword ptr [ebp+C]          ;  与注册名长度比较
  0041347E  |.^ 7C D8         \jl      short 00413458
  00413480  |>  66:F7D0       not     ax                               ;  ax中数据取反
  00413483  |.  66:25 FFFF    and     ax, 0FFFF                        ;  再与0xFFFF进行与运算
  00413487  |.  5B            pop     ebx
  00413488  |.  5D            pop     ebp
  00413489  \.  C3            retn
  
  出来后到
  
  004024FD  |.  83C4 08       add     esp, 8
  00402500  |.  0FB7C0        movzx   eax, ax                          ;  eax中为前面算出的值
  00402503  |.  B9 F0580000   mov     ecx, 58F0
  00402508  |.  99            cdq
  00402509  |.  F7F9          idiv    ecx                              ;  eax的值除以0x58F0
  0040250B  |.  8BC2          mov     eax, edx                         ;  将余数放入eax
  0040250D  |.  66:81FB 9D00  cmp     bx, 9D
  00402512  |.  75 05         jnz     short 00402519
  00402514  |.  83C8 FF       or      eax, FFFFFFFF
  00402517  |.  EB 71         jmp     short 0040258A
  00402519  |>  66:83FB 74    cmp     bx, 74
  0040251D  |.  75 05         jnz     short 00402524
  0040251F  |.  83C8 FF       or      eax, FFFFFFFF
  00402522  |.  EB 66         jmp     short 0040258A
  00402524  |>  66:83FB 68    cmp     bx, 68
  00402528  |.  75 05         jnz     short 0040252F
  0040252A  |.  83C8 FF       or      eax, FFFFFFFF
  0040252D  |.  EB 5B         jmp     short 0040258A
  0040252F  |>  66:83FB 71    cmp     bx, 71
  00402533  |.  75 05         jnz     short 0040253A
  00402535  |.  83C8 FF       or      eax, FFFFFFFF
  00402538  |.  EB 50         jmp     short 0040258A
  0040253A  |>  66:81FB B100  cmp     bx, 0B1
  0040253F  |.  75 05         jnz     short 00402546
  00402541  |.  83C8 FF       or      eax, FFFFFFFF
  00402544  |.  EB 44         jmp     short 0040258A
  00402546  |>  66:81FB BA00  cmp     bx, 0BA
  0040254B  |.  75 06         jnz     short 00402553
  0040254D  |.  66:B8 0100    mov     ax, 1
  00402551  |.  EB 37         jmp     short 0040258A
  00402553  |>  66:81FB 8211  cmp     bx, 1182
  00402558  |.  75 06         jnz     short 00402560
  0040255A  |.  66:B8 0500    mov     ax, 5
  0040255E  |.  EB 2A         jmp     short 0040258A
  00402560  |>  0FB7D3        movzx   edx, bx                          ;  取注册码转为十六进制数后的低8位
  00402563  |.  0FBFC8        movsx   ecx, ax                          ;  取注册名经过运算后的低8位
  00402566  |.  81C1 10270000 add     ecx, 2710                        ;  余数加上0x2710
  0040256C  |.  3BD1          cmp     edx, ecx                         ;  ①比较是否相等
  0040256E  |.  0F94C0        sete    al
  00402571  |.  83E0 01       and     eax, 1
  00402574  |.  66:83FE 06    cmp     si, 6                            ;  ②注册名不能少于6个字符
  00402578  |.  0F9DC2        setge   dl
  0040257B  |.  83E2 01       and     edx, 1
  0040257E  |.  23C2          and     eax, edx                         ;  ①②同时满足,注册成功
  00402580  |.  74 06         je      short 00402588
  00402582  |.  66:B8 0700    mov     ax, 7
  00402586  |.  EB 02         jmp     short 0040258A
  00402588  |>  33C0          xor     eax, eax
  0040258A  |>  5E            pop     esi
  0040258B  |.  5B            pop     ebx
  0040258C  |.  5D            pop     ebp
  0040258D  \.  C3            retn
  
  
  一组可用的注册码
  regist=22765
  username=PantsT
  
  注册成功后,“关于”里面显示 Special User。

  本小鸟第一次发帖,如果分析过程有问题,请各位大侠指正。谢谢!  

--------------------------------------------------------------------------------
【经验总结】

  贴上 C 编写的注册机。
  本人编程习惯不是太好,代码没优化,望各位看客多多包涵。
  
  
  #include<stdio.h>
  #include<string.h>
  
  main()
  {
  char name[20];
  unsigned int serial=0xffff;
  unsigned int i,j,temp;
  
  re: printf("Name:\t");
  gets(name);
  
  if(strlen(name)<6)
    {
    printf("Error!\n\n");
    goto re;
    }
  
  for(i=0;i<strlen(name);i++)
    {
    temp=name[i];
    temp<<=8;
    serial^=temp;
    for(j=0;j<8;j++)
      {
      if(serial>>15)
        {
         serial+=serial;
         serial^=0x1021;
        }
      else serial+=serial;
      }
    }
  
  serial=~serial;
  serial&=0xffff;
  serial%=0x58f0;
  serial+=0x2710;
  
  printf("Serial:\t%d\n",serial);
  getchar();
  }
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年10月24日 下午 9:49:12