飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 4186|回复: 2

[原创] Atlantis Word Processor V1.6.5算法分析及注册机的实现

[复制链接]
  • TA的每日心情
    难过
    2022-2-6 09:25
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2010-1-11 20:09:06 | 显示全部楼层 |阅读模式
    【文章标题】: Atlantis Word Processor V1.6.5算法分析及注册机的实现
    【文章作者】: playboysen
    【作者邮箱】: playboysen&126.com
    【软件大小】: 3.65Mb
    【下载地址】: http://www.atlantiswordprocessor.com/
    【保护方式】: 注册码
    【使用工具】: OD、Atlantis Word Processor
    【版权声明】: 版权所有,转载注明!新手参考,老鸟飞过~
    【作者声明】: 本文仅作个人学习研究之用,以探讨程序逆向方法为目的。如对软件本身有兴趣,请支持正版!
    -----------------------------------------------------------------------------------------------------------

       Atlantis Word Processor 一个独立的word处理器,支持读取并编辑*.rtf *.doc *.docx *.cod *.txt等数种格式的文档,支持命令行,软件小巧界面清爽,占用内存小,处理速度快,打开保存文件时支持全word格式的预览。(两个小小遗憾--word文档中的中文引号会显示乱码;竟不支持中文txt文件,汗。期待更新)
       试运行得知软件以用户名、注册码方式保护(其实用户名不参与运算),有出错提示,UPX弱壳。
       脱壳OD加载后,查找字符串“invalid”找到以下关键部位,以用户名playboysen,注册码HelloHenu试炼(算法分析一般都是随便输入假码后粗略跟踪几次注册码的验证流程,根据验证流程一次次地修正假码,最终得出一组可用注册码,弄清算法)
       
    00495FC7    E8 9CC31600       call Atlantis.00602368
    00495FCC    837D FC 00        cmp dword ptr ss:[ebp-4],0
    00495FD0    75 17             jnz short Atlantis.00495FE9
    00495FD2    B8 88604900       mov eax,Atlantis.00496088          ; ASCII "Please enter your registration code."
    00495FD7    E8 28E31400       call Atlantis.005E4304
    00495FDC    8B86 9C010000     mov eax,dword ptr ds:[esi+19C]
    00495FE2    8B10              mov edx,dword ptr ds:[eax]
    00495FE4    FF52 68           call dword ptr ds:[edx+68]
    00495FE7    EB 45             jmp short Atlantis.0049602E
    00495FE9    8D55 FC           lea edx,dword ptr ss:[ebp-4]
    00495FEC    8B86 9C010000     mov eax,dword ptr ds:[esi+19C]
    00495FF2    E8 71C31600       call Atlantis.00602368             ; 算出注册码长度
    00495FF7    8B45 FC           mov eax,dword ptr ss:[ebp-4]       ; 假码放入eax
    00495FFA    E8 0D060000       call Atlantis.0049660C             ; 关键处,跟进
    00495FFF    84C0              test al,al
    00496001    75 17             jnz short Atlantis.0049601A
    00496003    B8 B8604900       mov eax,Atlantis.004960B8          ; ASCII "The registration code you have specified is invalid..."

    跟进00495FFA关键call
    ......
    00496640    8B45 FC           mov eax,dword ptr ss:[ebp-4]
    00496643    E8 4C5AF7FF       call Atlantis.0040C094             ; 注册码第一次变形,把假码中的小写字母转换成大写
    00496648    8B45 F0           mov eax,dword ptr ss:[ebp-10]      ; 转换后的假码放入
    0049664B    B1 30             mov cl,30                          ; 数字“0”
    0049664D    B2 4F             mov dl,4F                          ; 大写字母“O”
    0049664F    E8 CC711400       call Atlantis.005DD820             ; 看上面入栈的参数,猜测这个函数里面有猫腻儿
    00496654    8B55 F4           mov edx,dword ptr ss:[ebp-C]       ; 上面的函数就是注册码的第二次变形了

    数字“0”、大写字符“O”和假码同时入栈,葫芦里卖的什么药?进去遛遛
    ......
    005DD83C    E8 4B5DE2FF       call Atlantis.0040358C             ; 算出注册码长度
    005DD841    83F8 01           cmp eax,1
    005DD844    7C 1D             jl short Atlantis.005DD863
    005DD846    89C7              mov edi,eax                        ; 注册码长度放入
    005DD848    8B06              mov eax,dword ptr ds:[esi]         ; 注册码放入
    005DD84A    3A5C38 FF         cmp bl,byte ptr ds:[eax+edi-1]     ; 假码从后往前逐位与大写字母“O”比较
    005DD84E    75 0E             jnz short Atlantis.005DD85E        ; 一路小跑过去,发现这里是把注册码中出现的字母“O”替换成数字“0”
    005DD850    8BC6              mov eax,esi                        ; 企图混淆视听啊
    005DD852    E8 055FE2FF       call Atlantis.0040375C

    汗,这都行?至此,我们的假码经过了两次加工,记住
    ......
    0049665F    8B45 FC           mov eax,dword ptr ss:[ebp-4]
    00496662    E8 25CFF6FF       call Atlantis.0040358C             ; 算出注册码长度
    00496667    8BF0              mov esi,eax
    00496669    83FE 01           cmp esi,1
    0049666C    7C 3D             jl short Atlantis.004966AB
    0049666E    8B45 FC           mov eax,dword ptr ss:[ebp-4]       ; 经过以上两次加工后的变形假码放入EAX
    00496671    8A4430 FF         mov al,byte ptr ds:[eax+esi-1]     ; 注册码从后往前依次参与运算
    00496675    8BD0              mov edx,eax
    00496677    80EA 20           sub dl,20                          ; 逐位比较是不是空格
    0049667A    74 05             je short Atlantis.00496681
    0049667C    80EA 0D           sub dl,0D                          ; 逐位比较是不是连字符“-”
    0049667F    75 11             jnz short Atlantis.00496692
    00496681    8D45 FC           lea eax,dword ptr ss:[ebp-4]
    00496684    B9 01000000       mov ecx,1
    00496689    8BD6              mov edx,esi
    0049668B    E8 40D1F6FF       call Atlantis.004037D0             ; 去除注册码中的“-”
    00496690    EB 14             jmp short Atlantis.004966A6
    00496692    8B55 FC           mov edx,dword ptr ss:[ebp-4]       ; 假码放入edx
    00496695    25 FF000000       and eax,0FF
    0049669A    8B15 4C7E6100     mov edx,dword ptr ds:[617E4C]      ; Atlantis.0061CC30
    004966A0    803C02 FF         cmp byte ptr ds:[edx+eax],0FF      ; 此时eax的值就是假码中每一位字母或数字的十六进制值
    004966A4    74 77             je short Atlantis.0049671D         ; 注册码中的每一位只能是 数字或a~f或A~F或字母o/O(不明白看下面的分析)
    004966A6    4E                dec esi
    004966A7    85F6              test esi,esi
    004966A9  ^ 75 C3             jnz short Atlantis.0049666E
    004966AB    8B45 FC           mov eax,dword ptr ss:[ebp-4]       ; 无连字符“-”的大写注册码放入
    004966AE    E8 D9CEF6FF       call Atlantis.0040358C             ; 求经过三次变形后的假码长度
    004966B3    83F8 10           cmp eax,10                         ; 注册码16位啊
    004966B6    75 65             jnz short Atlantis.0049671D

    上述代码的后半部分理解有些费力
    0049669A    8B15 4C7E6100     mov edx,dword ptr ds:[617E4C]      ; Atlantis.0061CC30
    [617E4C]指向的地址是0061CC30,我们看一下数据窗口对应位置的数值
    捕获1.JPG
    醒目一点的估计看出来了,截图上的地址是从0061CC60开始的,为什么呢?
    0049669A    8B15 4C7E6100     mov edx,dword ptr ds:[617E4C]      ; Atlantis.0061CC30
    004966A0    803C02 FF         cmp byte ptr ds:[edx+eax],0FF      ; 此时eax的值就是假码中每一位字母或数字对应的十六进制值
    问题就出在第二句的[edx+eax]处,静态解释不易理解,动态跟踪一下就明白了
    假设假码中其中一位字符是“8” 对应十六进制是 0x38
    而edx == 0061CC30,所以[edx+eax] == 0061CC68 这个地址对应上图可知值为0x08,并不等于0xFF,证明假码中的这一位合格

    好,跟踪至此,我们的假码可以进行修正了
    HelloHenu --> Babe-5214-0987-acef
    以上都是一些准备工作,下面就真的进入了算法核心了
    ……
    004966B8    BE 01000000       mov esi,1                          ; 核心算法开始了  esi初始值为1
    004966BD    8BC6              mov eax,esi                        ; 一个大的算法循环 开始处
    004966BF    48                dec eax
    004966C0    03C0              add eax,eax
    004966C2    40                inc eax
    004966C3    8B55 FC           mov edx,dword ptr ss:[ebp-4]       ; 几次变形后的注册码放入
    004966C6    0FB65402 FF       movzx edx,byte ptr ds:[edx+eax-1]  ; 注册码从前往后依次运算
    004966CB    8B0D 4C7E6100     mov ecx,dword ptr ds:[617E4C]      ; Atlantis.0061CC30
    004966D1    8A1411            mov dl,byte ptr ds:[ecx+edx]
    004966D4    C1E2 04           shl edx,4
    004966D7    8B4D FC           mov ecx,dword ptr ss:[ebp-4]
    004966DA    0FB60401          movzx eax,byte ptr ds:[ecx+eax]
    004966DE    8B0D 4C7E6100     mov ecx,dword ptr ds:[617E4C]      ; Atlantis.0061CC30
    004966E4    021401            add dl,byte ptr ds:[ecx+eax]
    004966E7    8855 FA           mov byte ptr ss:[ebp-6],dl         ; 可以看出,从前往后依次取出注册码的每两位进行下面的运算
    004966EA    B8 58674900       mov eax,Atlantis.00496758          ; 00496758地址处有段8位的密钥参与运算
    004966EF    8A4430 FF         mov al,byte ptr ds:[eax+esi-1]
    004966F3    C645 F9 01        mov byte ptr ss:[ebp-7],1          ; (这里 标志位哦)
    004966F7    B3 08             mov bl,8
    004966F9    E8 0AFFFFFF       call Atlantis.00496608             ; 把密钥的对应位数值做一次ror(循环右移)运算
    004966FE    3A45 FA           cmp al,byte ptr ss:[ebp-6]         ; 比较置换后的对应位注册码值是否等于ror后的密钥值
    00496701    75 06             jnz short Atlantis.00496709        ; 事实证明,如果不等于,最终就提示注册码错误
    00496703    C645 F9 00        mov byte ptr ss:[ebp-7],0
    00496707    EB 04             jmp short Atlantis.0049670D
    00496709    FECB              dec bl                             ; 对应密钥可以循环8次ror运算,**生8个值
    0049670B  ^ 75 EC             jnz short Atlantis.004966F9        ; 每次对应取出的两位注册码值必须等于上述8个结果的其中一个

    其实,软件核心的算法就是:
    1、注册码应为16位,有没有“-”连接都可以
    2、注册码中的每一位只能是 0~9或a~f或A~F或字母o/O
    3、从前往后每次取出2位注册码值,转换成一个字节的十六进制值
    如字符“a5c3” 就转换成 0xA5 0xC3
    这样十六位的注册码,就变成了占8字节的一串十六进制值
    4、程序预置8位密钥,如下
    捕获2.JPG
    5、每位密钥都进行 至少一次的ror运算,把第一次ror后得出的值与相应位置的注册码值比较,如果不相等则在第一次算出值的基础上进行第二次的ror运算,依次循环,共可循环8次--如果还不相等,就说明是错误注册码了,不再继续运算

    可以004966FE处为切入点,其中al的值就是密钥ror运算出的值--可用的注册码的其中两个值。在004966FE处下断,修改00496701处的jnz跳转为NOP,F9继续运算可以很轻易地跟出可用注册码
    004966FE    3A45 FA           cmp al,byte ptr ss:[ebp-6]         ; 比较置换后的对应位注册码值是否等于ror后的密钥值

    随便F9了几下
    总结了几个类似A7B1-A6B4-2732-E1F2  7A1B6A4B72231E2F这样的值,不知道有什么用o_0
    软件注册后,相关信息保存于注册表以下位置(软件没有对关键信息加密,也是一个败笔):
    Windows Registry Editor Version 5.00

    [HKEY_CURRENT_USER\Software\Rising Sun Solutions, Inc.\Atlantis.1_x\RegInfo]
    "RegCode"="XXXXXXXXXXXXXXXX"
    "RegTo"="playboysen"


    总结:
    看算法的分析有很多,但最主要的验证算法只有以下几行
    Mov esi,1
    mov eax,00496758               //这里是预置的一个8位数组,具体参考上图
    mov al,byte ptr ds:[eax+esi-1]
    mov bl,8
    004966F9:
    Ror al,1
    cmp al,byte ptr ss:[ebp-6]        //在这里添加相应代码取出al中的值转换后连接成16位的字符串即为一组注册码
    dec bl
    jnz  004966F9
    inc esi
    cmp esi,9
    jz XXXXX

    其实,上周就开始分析这个程序了,一路小跑几次觉得算法不难,但很繁琐,没有耐心看,搁置一周。偶尔看到kanxue十天前留下的信息,感动老大还记得我辈之余顿悟自己今年确实堕落了,莫说文章之类,就连论坛都鲜有登陆,惭愧!新入职,一切都不稳定,有些心浮气躁。
    离开几个月回来发现大家都跑去搞VM、驱动之类去了,牛X新壳如雨后春笋层出不穷,自己竟成了古董。唏嘘不已,感慨IT业发展之迅猛。也鲜有大虾写些算法分析之流的东西,自己也惧怕贻笑大方。快过年了,写篇文章凑个数,算是给自己一个交代。
    水平有限,JJ不会o_0

    提前祝大家新年里虎虎生威 早生虎仔!

    [ 本帖最后由 playboysen 于 2010-1-11 20:11 编辑 ]
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2015-8-23 23:49
  • 签到天数: 27 天

    [LV.4]偶尔看看III

    发表于 2010-1-11 20:17:51 | 显示全部楼层
    好贴,前来学习...

    [ 本帖最后由 GGLHY 于 2010-1-11 20:21 编辑 ]
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2015-8-3 23:07
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2010-1-11 21:08:21 | 显示全部楼层
    好帖,学习
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表