playboysen 发表于 2010-1-22 13:24

Atlantis Word Processor V1.6.5算法分析

【文章标题】: 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:,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:
00495FE2    8B10            mov edx,dword ptr ds:
00495FE4    FF52 68         call dword ptr ds:
00495FE7    EB 45             jmp short Atlantis.0049602E
00495FE9    8D55 FC         lea edx,dword ptr ss:
00495FEC    8B86 9C010000   mov eax,dword ptr ds:
00495FF2    E8 71C31600       call Atlantis.00602368             ; 算出注册码长度
00495FF7    8B45 FC         mov eax,dword ptr ss:       ; 假码放入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:
00496643    E8 4C5AF7FF       call Atlantis.0040C094             ; 注册码第一次变形,把假码中的小写字母转换成大写
00496648    8B45 F0         mov eax,dword ptr ss:      ; 转换后的假码放入
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:       ; 上面的函数就是注册码的第二次变形了
数字“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:         ; 注册码放入
005DD84A    3A5C38 FF         cmp bl,byte ptr ds:   ; 假码从后往前逐位与大写字母“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:
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:       ; 经过以上两次加工后的变形假码放入EAX
00496671    8A4430 FF         mov al,byte ptr ds:   ; 注册码从后往前依次参与运算
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:
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:       ; 假码放入edx
00496695    25 FF000000       and eax,0FF
0049669A    8B15 4C7E6100   mov edx,dword ptr ds:      ; Atlantis.0061CC30
004966A0    803C02 FF         cmp byte ptr ds:,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:       ; 无连字符“-”的大写注册码放入
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:      ; Atlantis.0061CC30
指向的地址是0061CC30,我们看一下数据窗口对应位置的数值

醒目一点的估计看出来了,截图上的地址是从0061CC60开始的,为什么呢?
0049669A    8B15 4C7E6100   mov edx,dword ptr ds:      ; Atlantis.0061CC30
004966A0    803C02 FF         cmp byte ptr ds:,0FF      ; 此时eax的值就是假码中每一位字母或数字对应的十六进制值
问题就出在第二句的处,静态解释不易理解,动态跟踪一下就明白了
假设假码中其中一位字符是“8” 对应十六进制是 0x38
而edx == 0061CC30,所以 == 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:       ; 几次变形后的注册码放入
004966C6    0FB65402 FF       movzx edx,byte ptr ds:; 注册码从前往后依次运算
004966CB    8B0D 4C7E6100   mov ecx,dword ptr ds:      ; Atlantis.0061CC30
004966D1    8A1411            mov dl,byte ptr ds:
004966D4    C1E2 04         shl edx,4
004966D7    8B4D FC         mov ecx,dword ptr ss:
004966DA    0FB60401          movzx eax,byte ptr ds:
004966DE    8B0D 4C7E6100   mov ecx,dword ptr ds:      ; Atlantis.0061CC30
004966E4    021401            add dl,byte ptr ds:
004966E7    8855 FA         mov byte ptr ss:,dl         ; 可以看出,从前往后依次取出注册码的每两位进行下面的运算
004966EA    B8 58674900       mov eax,Atlantis.00496758          ; 00496758地址处有段8位的密钥参与运算
004966EF    8A4430 FF         mov al,byte ptr ds:
004966F3    C645 F9 01      mov byte ptr ss:,1          ; (这里 标志位哦)
004966F7    B3 08             mov bl,8
004966F9    E8 0AFFFFFF       call Atlantis.00496608             ; 把密钥的对应位数值做一次ror(循环右移)运算
004966FE    3A45 FA         cmp al,byte ptr ss:         ; 比较置换后的对应位注册码值是否等于ror后的密钥值
00496701    75 06             jnz short Atlantis.00496709      ; 事实证明,如果不等于,最终就提示注册码错误
00496703    C645 F9 00      mov byte ptr ss:,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位密钥,如下

5、每位密钥都进行 至少一次的ror运算,把第一次ror后得出的值与相应位置的注册码值比较,如果不相等则在第一次算出值的基础上进行第二次的ror运算,依次循环,共可循环8次--如果还不相等,就说明是错误注册码了,不再继续运算
可以004966FE处为切入点,其中al的值就是密钥ror运算出的值--可用的注册码的其中两个值。在004966FE处下断,修改00496701处的jnz跳转为NOP,F9继续运算可以很轻易地跟出可用注册码
004966FE    3A45 FA         cmp al,byte ptr ss:         ; 比较置换后的对应位注册码值是否等于ror后的密钥值
随便F9了几下
总结了几个类似A7B1-A6B4-2732-E1F27A1B6A4B72231E2F这样的值,不知道有什么用o_0
软件注册后,相关信息保存于注册表以下位置(软件没有对关键信息加密,也是一个败笔):
Windows Registry Editor Version 5.00

"RegCode"="XXXXXXXXXXXXXXXX"
"RegTo"="playboysen"

总结:
看算法的分析有很多,但最主要的验证算法只有以下几行


Mov esi,1
mov eax,00496758               //这里是预置的一个8位数组,具体参考上图
mov al,byte ptr ds:
mov bl,8
004966F9:
Ror al,1
cmp al,byte ptr ss:      //在这里添加相应代码取出al中的值转换后连接成16位的字符串即为一组注册码
dec bl
jnz004966F9
inc esi
cmp esi,9
jz XXXXX


预祝大家新的一年虎虎生威~

wgz001 发表于 2010-1-23 16:35

精品文章   沙发学习
:handshake

playboysen 发表于 2010-2-5 00:50

2010年2月4日发布V1.6.5.1
增加文件拖放处理支持 等……

算法未变

老万 发表于 2010-2-10 08:45

好文章,学习了

a5113342 发表于 2010-8-8 22:09

很难懂
页: [1]
查看完整版本: Atlantis Word Processor V1.6.5算法分析