发信人: Reinhard.bbs@bbs.sjtu.edu.cn (摘星的人), 信区: cnhacker
标  题: DOS下软件解浅谈 (二) -- Alex 整理(转寄)
发信站: 饮水思源站 (Fri Apr 25 20:08:47 1997)
转信站: Lilac!ustcnews!ustcnews!sjtunews!sjtubbs
出  处: bbs.sjtu.edu.cn

发信人: kevin@SMTH (老人与海), 信区: Hacker
标  题: DOS下软件解浅谈 (二)
发信站: 水木清华  (Fri Nov 10 16:24:51 1995)
转信站: SMTH

                                DOS下软件解浅谈  (二)
| 清华大学 计算机科学与技术系  何开川                                                           
| EMAIL:hyj-dmp@mail.tsinghua.edu.cn

四、解密 = 跟踪 ?
                如果要用两个字概括解密的实质的话,那就是∶跟踪;是的,就是跟踪。
我们在调试一般程序的时候也需要跟踪,但两者的目的是不尽相同的。后者是为
了排错、而前者是为了窥探,具体地说,就是找出程序在哪儿加的密、如何加的,
从而找到"修改点",以便将其改为解密版。
                先介绍解密的几条思路∶
 1)从头至尾式∶
                        拿到一个软件,从第一条指令开始,逐条跟踪,直至找到"修改
点",这就是最基本的解密方法。但要注意,跟踪过程中应采取"先粗后细,偶
而回溯"的方针。比如下面一段程序∶
                        
                *                       *                          *
         Initialize
                    |               
           V
        Call Module1
                   |
                     V   
        Call Module2-->Call Module3 
                    |                   |
                    V                   V 
                  ...      Call Module4 -> Call  Module 5
                                                    |
|
                                                    V                        
                                              检查Password                                                             Or   ax,ax
        我们要找的修改点 ======>     jz  游戏入口
                                          jnz 显示"Password" 不对 
                                                                                                                                   ...               
                          *                     *                       *                               
  我们要找的"修改点"藏在Module 4里面,如果我们从Module1开始一条一条
跟的话,恐怕要看几千条指令,但如果我们按"先粗后细"的原则,先用P 命令,
即Step方式跟踪,当发现Step过Module2时,游戏已检查过Password,说明跟"过"
了,于是用"偶而回溯"策略,从新执行程序,这次跟入Module2, 再用P粗
线条跟踪,发现Step过Module4后又错过了"修改点",于是返回头来跟入Module4,
这次终于发现在一处由 Or  ax,ax /  jz  XXXX  产生的分支与程序是否"认
为"Password正确直接相关,不妨试着把jz  XXXX改为jmp XXXX--成功了,
游戏已正常进入主画面。这说明我们找到了"修改点",解密的主要工作也就完成
了,关于如何把这一修改"固化"下来,参见后文。

2)中途拦截式∶
        抗日影片《铁道游击队》中,机警勇敢的游击队战士在同日寇交锋时常
常不是正面进攻,而是早早地埋伏在铁路旁,等敌人的火车经过时,给它来个"
中途拦截",从而达到出其不意的制胜效果。 在软件解密的过程中亦有同样的战
术∶拿到一个软件后,先不忙着从头跟起,而是考虑一下,有没有办法跳过程序
的初始化部分,直接切入程序判断密钥的"关键点"或是"关键点"附近的部分。若
是存在这样的捷径,就可省去不少跟踪之苦。
        这里,仅以解拆游戏PASSWORD为例。让我们思考这样一个问题∶程
序何时判断PASSWORD? 如果我们知道了这个时刻,就可在恰当的时间拦截到
其完成判断功能的代码,从而解之。不失一般性,我们可以假设程序总是在我们
输入PASSWORD之后开始判断,那么通常有两种拦截方式。
        (a) 热键拦截∶
        我们在前面说过,SOFT-ICE具有很强的热键激活能力。因而我们可以
在输入PASSWORD后立即按下热键,如果运气好的话,程序可能还没有判断密
钥,那么你就可以TRACE啦。不过,这种作法随机性太大,而且还有可能受到
DOS或ROM例程的干扰(详见下文"跟踪原则")。为了避免这些缺点,我们也可
采用中断拦截方式。

        (b)中断拦截∶
        如果大家对DOS及BIOS的中断机制比较熟悉的话,现在就可以派上用
场了。我们知道,不论程序是如何输入密码的,在这段过程中都免不了调用各种
中断。因为DOS、BIOS中断之于DOS程序,就如WINDOWS API之于
WINDOWS程序一样。 如果软件在输入时用键盘,多半要调INT 16;如果用鼠
标,则要调INT  33; 即使是密码输入错误程序准备结束时,也要调INT 21 
(AH=4C),如此等等。 如果我们估计到程序在密码输入、判断过程中要调某一
中断,就可用SOFT-ICE的BPINT指令在相应中断上设一段点,从而中断到离
密码判断较近之处,而且可以避免用热键中断时断到ROM或DOS的麻烦。

3)迂回前行式∶
        对一般软件,前两种方法已是足够,但一味套用终有碰壁的时候。其实
加密、解密本没有固定的方法,最高明的方法也许就是"没有方法",即随机应变、
具体问题具体分析,解密的过程实际上就是想出一个新方法的过程,当你沿着一
条思路憋住的时候,不妨换个角度,说不定就柳暗花明了呢。 比如说你从头跟
踪理不出头续,就可以中途拦截试试嘛,中途拦截进去还是一头雾水,那就把从
头跟踪得到的结果与中途拦截的结果对照一下,来个"两头加击",没准就能看出
端倪。总之,跟踪的过程常常不是一条"直线",而是一条左折右回的"曲线",我
们就把这最后一条思路称为"迂回前行式"吧。

                也许看到这里,你已经跃跃于试了,但真地一跟踪还是一团乱麻,别急,
下面让我们再来谈谈解密跟踪时的几条原则∶

 1) 瞄准判转语句∶
        因为我们解密的手段从本质上讲是修改软件"密码判断"之后的走向。因
而在程序判断密吗的段落附近,任何与"判断"有关的语句都应得到重视。不过,
要注意,"判断"语句未必都是 "CMP  AX,0001", 象下面这些语句都可肩负"
判转"的任务∶
   (1)    OR       AX,AX
          JZ    XXXX
   (2)    MOV   SI,0100H
          MOV       DI,0200h
          MOV           CX,0FH
          REPNZ   CMPSB
          JZ            ENTER_GAME
          JMP           EXIT_GAME
   (3)    TEST  AL,0FFH
          JNE           DEAD_OUT
          JMP           CORRECT_BRANCH
   (4)    SUB           AX,0001H
          JZ       XXXX
   (5)    ADD           AL,0FFH        (等价于: CMP AL,01H 
          JC            ALL_RIGHT                 JZ   ALL_RIGHT)       
           ....................
 2) 逃离循环体∶
        跟踪时最怕掉入一个与"目标"无关的循环体中而白白浪费时间。所以一 
旦感到在某几段代码间兜圈圈,要马上找到循环出口"逃离"掉。
 3) 注意错误分支∶
        当你瞎蒙PASSWORD 时多半会进入错误分支,但要注意一点∶错误分
支的反面可能就是正确分支。
 4)  KEEP  AWAY--ROM代码∶
        如果你是用热键断入的,很可能掉入ROM代码中,判断的方法很简单,
只要看当前段址是否为 F000-FFFF之间。这时,不用仔细看了,找一个IRET语
句返回即可。
        还有一种可能是掉如DOS或其它驻留内存程序的代码段,判断的方法也
不难, 看看当前地址是否在最后常驻的程序所占内存块之后(用MEM /C/P可在
DOS下查看常驻程序占用的内存块),若在之后则说明没有,否则即是掉了进去,
解决的方法同样是尽快返回。
5)  注意选择"单步"和"步进"∶
        用单步可以仔细跟踪每一个子程序,用步进则可节省时间、不至陷入毫
无意义的细节。
6)  善于对跟踪过程的"关键点"作记录∶
        跟踪是一件辛苦的工作,每发现一个"可疑"之处都应该作简要记录,免
得最后跟出来了却忘记了跟踪的"路径"。
7)   大处着眼、小处落手∶
        有可能的话,要把握程序的整体脉络,"体会"作者的思路,不要只见树
木不见森林,只看到一条一条的机器代码。
                
        应该说跟踪过程还有很多经验可循,但难以一一列出,解密者只有通过
大量的实践才能切身体会到其中的规律。              
                                                                        
        
五  修改∶
        如果按照前面所讲的思路跟出了"关键点"、找到了动态将其改动、解密
的方法,那么下一步就是通过静态修改软件的运行文件把这一解密"成果"固定下
来,方法很简单∶
        比如我们通过动态分析发现把程序某处的一条JZ 100改为JNZ 100即可
实现解密,那么我们可以记录下来包括JZ 100在内的 JZ100附近的几条汇编指
令的机器代码,以及修改后的相应代码,如∶10 FF 2A 74 2A (修改前),10 FF 2A  
75 2A(修改后),然后用PCTOOLS之类有代码串替换功能的工具把该软件的运行
程序作SEARCH/REPLACE即可,上例中即∶把串 10 FF 2A 74 2A替换为 10 FF 
2A 75 2A。

                                                              [未完待续]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   \ | /    .---   *** Soft Art Is the True Art*** 
   { . .}  |    ]    
    \ - | . .  /      He  Kaichuan  //// Email:hyj-dmp@mail.tsinghua.edu.cn
     ===      !    
              O                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`

--


                                                    沉默的人
                                                 Reinhard Young

※ 来源:·饮水思源站 bbs.sjtu.edu.cn·[FROM: 202.96.212.29]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.421毫秒