登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

DOS编程技术

讨论在纯DOS下的编程技术

 
 
 

日志

 
 
关于我

1984年大学毕业,1985年底有机会开始接触PC机,1986年开始在PC机上做开发工作,曾接触过MS-DOS、CP/M、UNIX、VMS、LINUX、iRMX等众多的操作系统并在上面从事技术开发,擅长做底层与硬件相关的软件开发,目前主要在DOS和LINUX平台下工作,主要从事软件,在硬件开发上也有一定造诣,亦有在8051系列、6502系列(凌阳)、z80系列、ARM、X86等各类平台下开发软硬件的经历。更详细情况可以参考http://resume.whowin.net

DOSUSB 2.0 免费版的限制原理  

2011-07-12 23:17:25|  分类: USB系列 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
    两年前,我在写USB的文章时,多次提到了DOSUSB这个东东,这两年也没有关注这方面的变化,最近,有机会重新进入DOSUSB的官方网站(www.dosusb.net)(2017年3月15日注:很高兴这个链接还健在),欣喜地发现,这个网站不仅依然存在,而且还有所发展,相继推出了DOSUSB 2.0和DOSUSB3.0,但是不再免费(以前,DOSUSB的二进制代码是免费的,但源代码收费),USB 3.0还不怎么常用(至少在运行DOS的机器上),所以,本文仅对DOSUSB 2.0的免费版做了一个简单的分析,介绍其限制方法,并提出了一个非常简单的破解方法。
    题外话,我觉着DOSUSB的收费稍微贵了点,一个单机授权要收取65欧元,无限量版本收费550欧元,源代码收费高达1000欧元。
    整个二进制文件长度为34211字节,也不是很大,所以反编译跟踪并不是十分困难。

    先要学习一下DOSUSB的文档,关于免费版的限制,有如下说明:
The free version for download on the internet is a demo version of DOSUSB. This version will stop working after 20 minutes of operation. Calls by an application program will be unsuccessful then after that period. DOSUSB can also be unloaded and loaded again for five times only. After that the PC has to be booted again before loading DOSUSB.
    按照文档说明,免费版有两种限制方式,其一:只能用20分钟;其二:20分钟后如果你还想用,可以卸载DOSUSB,然后再加载DOSUSB,但是这种做法只能重复5次,之后,你必须重新启动DOS。
    其实,他只有一条限制,就是第一条,如果能让DOSUSB不受20分钟的限制,也就不存在第二条限制了。
    DOSUSB是通过一个软中断来提供服务的,缺省是int 65h,就是说,当运行DOSUSB 20分钟以后,再调用int 65h时会失败,所以,这个20分钟的限制主要应该在中断程序中,而且应该在中断程序的开始部分;但是,要比较时间,DOSUSB在启动时肯定要记录启动时的时间,这部分程序应该在DOSUSB的初始化程序中。
    综合起来说,DOSUSB在启动时,首先记录启动时间,然后在中断程序中,读取当前时间,并与启动时间进行比较,从而决定是否继续执行中断程序,大致就是这么一个原理,很简单。
    下面准备进入实战,DOSUSB实际上只有一个可执行文件:dosusb.com,我们使用DEBUG这个最常用的调试程序来反汇编dosusb.com,但是由于这个文件中有大量的32位代码,而dos 6.22配的debug程序是16位的,所以好多代码反汇编不了,在实际过程中我是在DR-DOS下使用debug完成反汇编的,因为DR-DOS下的DEBUG是32位的,不过这个程序也是可以在DOS6.22下运行的,如果你没有这个程序也懒得下载DR-DOS,可以在下面地址下载这个debug程序,为了和dos 6.22下的debug区别,我把它叫做debug32。
    http://blog.whowin.net/software/debug32.rar(2017年3月15日注:这个链接刚刚经过修复)
    整个反编译工作实在虚拟机下完成的,当然也可以在一般的运行DOS的机器上完成。另外,我发现DOSUSB在Virsual Box下不能运行,会出现虚拟机崩溃的现象,没有研究其原因,也许就是有个中断冲突等小问题,所以,所有的运行试验都是在一个运行DOS的机器上完成的,实际环境为DOS 6.22。
    我们先来看一下启动DOSUSB时的实际情况:
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图1
 
    在最上面的信息中,非常明确地指出,这是一个没有注册的版本,是有时间限制的Demo版本。
    然后,我们运行一下随DOSUSB一起发行的usbview程序,在我的机器上运行结果如下:
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图2
 
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图3
 
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图4
 
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图5
 
    运行这个程序是为了说明DOSUSB是可以使用的,可以和20分钟后DOSUSB禁止使用时做比较。
    我们再看一下20分钟后,DOSUSB不能使用时的情况,我们再次运行usbview程序:
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图6
 
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图7

    两个令人厌恶的提示信息,实际上在告诉我们,DOSUSB已经罢工了。

    现在我们开始用debug反汇编dosusb.com这个程序
    在dos提示符下输入:debug dosusb.com(也许是debug32 dosusb.com)
    下面是在我的虚拟机下反汇编出来的部分汇编代码,我们只选择了一些和这篇文章话题相关的代码,重要的地方都做了详细的注释,很多的子程序并没有列在这里,但注释中说明了其功能,为了说明方便,都加了行号:
行号 内存地址  二进制码      反汇编指令                    注释
------------------------------------------------------------------------------------------------
001  3760:0100 E93D05        JMP     0640
002  ......(这里是一块数据区)
003  3760:0640 BBA386        MOV     BX,86A3               ; 新分配的段落块(16字节)数量
004  3760:0643 C1EB04        SHR     BX,04                 ; ES=内存块段地址
005  3760:0646 43            INC     BX
006  3760:0647 B44A          MOV     AH,4A
007  3760:0649 CD21          INT     21                    ; 修改分配的内存块
008  3760:064B B8626B        MOV     AX,6B62
009  3760:064E 050008        ADD     AX,0800               ; 重新设置堆栈,栈底在6b62h
010  3760:0651 8BE0          MOV     SP,AX                 ; 堆栈长度为800h
011  3760:0653 E8DE72        CALL    7934                  ; 判断运行环境,设置内存策略
012  ............(这里省略若干行代码)
013  3760:069B E82673        CALL    79C4                  ; 显示DOSUSB的版本信息
014  3760:069E BEBD5E        MOV     SI,5EBD               ; 指向字符串:Time restricted Demo Version
015  3760:06A1 E83223        CALL    29D6                  ; 显示字符串
016  3760:06A4 60            PUSHA   
017  3760:06A5 B42C          MOV     AH,2C                 ; DOS功能:取时间
018  3760:06A7 CD21          INT     21      (DOS)
019  3760:06A9 890E0360      MOV     [6003],CX             ; CH=小时,CL=分钟
020  3760:06AD 61            POPA    
021  3760:06AE 60            PUSHA   
022  3760:06AF 8B0E0360      MOV     CX,[6003]
023  3760:06B3 33C0          XOR     AX,AX
024  3760:06B5 8AC5          MOV     AL,CH                 ; 小时(0--23)
025  3760:06B7 B33C          MOV     BL,3C                 ; 3ch=60,把小时数换算成分钟数
026  3760:06B9 F6E3          MUL     BL                    ; AX中为当前时间的小时部分转换的分钟数
027  3760:06BB B500          MOV     CH,00
028  3760:06BD 03C1          ADD     AX,CX                 ; 加上当前时间的分钟数,为相对于凌晨的分钟数
029  3760:06BF A30F79        MOV     [790F],AX             ; word [790fh]存储启动程序时的分钟数
030  3760:06C2 1E            PUSH    DS
031  3760:06C3 33C0          XOR     AX,AX
032  3760:06C5 8ED8          MOV     DS,AX
033  3760:06C7 A0FE04        MOV     AL,[04FE]             ; 0:04feh在BIOS数据区,用这个位置记录程序的启动次数
034  3760:06CA 3C0A          CMP     AL,0A                 ; 当启动次数达到10次时,将不能再次启动,需要重新启动计算机
035  3760:06CC 7214          JB      06E2                  ; <10次启动,可以运行
036  3760:06CE 90            NOP     
037  3760:06CF 90            NOP     
038  3760:06D0 1F            POP     DS
039  3760:06D1 BEE55E        MOV     SI,5EE5               ; Terminal Demo Version!
040  3760:06D4 E8FF22        CALL    29D6                  ; 显示一个以\0结尾的字符串
041  3760:06D7 BEE15F        MOV     SI,5FE1               ; 回车,换行
042  3760:06DA E8F922        CALL    29D6                  ; 显示一个以\0结尾的字符串
043  3760:06DD 61            POPA    
044  3760:06DE B44C          MOV     AH,4C                 ; DOS功能,退出应用程序
045  3760:06E0 CD21          INT     21      (DOS) 
046  3760:06E2 FEC0          INC     AL                    ; 将启动次数+1后存回0:04feh的位置
047  3760:06E4 A2FE04        MOV     [04FE],AL
048  3760:06E7 1F            POP     DS
049  3760:06E8 61            POPA    
050  3760:06E9 E9947C        JMP     8380                  ; 继续进行初始化

1、从001--012行,与我们本文的话题没有什么联系,总之,dosusb.com的初始化过程最后要执行到从013行开始的这段程序。
2、013行调用了位于794ch处的子程序,这段子程序显示出了图1中的第一行信息:DOSUSB driver by ......
3、014、015行,显示信息:Time restricted Demo Version,也就是图1中,第二行的信息。
4、017、018行执行DOS功能,得到系统时间,CH=小时,CL=分钟,暂时存放在位于[6003h]的两个字节中
5、024-028,计算把当前时间的小时数 X 60 + 分钟数,得出的数值应该是当前时间相对于当前00:00的分钟数
6、029行把上面计算得到的分钟数存放在位于[790fh]的两个字节中,790fh这个地址很重要,后面还要用到
7、031-033行把位于0:04FEh位置的一个字节放在AL中,实际上,dosusb.com程序使用0:04FEh这个位置来存放程序的启动次数
8、034行比较启动次数,如果小于10,则转到046行(035行),把启动次数+1后存回0:04FEh这个位置
9、如果启动次数大于等于10,则执行036-045行这段程序,显示一些错误信息后退出应用程序。

    现在我们总结一下上面这段程序:
1、dosusb.com启动时间相对于当天0点的分钟时存在起始地址为790Fh的两个字节(一个word)中
2、启动次数存在地址为0:04FEh的一个字节中,这个区域位于BIOS数据区,所以,如果不重新启动DOS,存放的数值不会变化
3、dosusb.com允许重新加载10次,而不是其文档中说的5次
4、可以断定int 65h中的某个位置会使用地址为790Fh中存放的dosusb.com的启动时间

    下面我们的问题是,如何找到dosusb.com启动后int 65h的入口地址呢?当然,我们可以继续反编译dosusb.com,然后认真地分析器初始化部分,不过,那样做真的是太累了(当然,你可以去试一下),我们有更简单的办法。
    思路是,在DOS下启动dosusb.com,然后在debug下用dos的35h号功能写上2行代码,执行一下读出int 65h的地址,我们看到的那个偏移地址,应该和我们用debug反编译dosusb.com时的偏移地址一致,这样,我们就可以定位dosusb.com中int 65h代码的具体位置了。
    下面是实际操作时的截屏:
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图8
 
    在上面屏幕上,我们看到的执行结果中BX中的值就是我们想要的偏移地址,我们现在再回到用debug反编译dosusb.com里面,看看这个偏移地址下的程序是啥东西。
行号 内存地址  二进制码      反汇编指令                    注释
------------------------------------------------------------------------------------------------
001  3760:06EC EB09          JMP     06F7
002  3760:06EE  44 4F 53 55 53 42 0A 03-18 2E        DOSUSB....
003  3760:06F7 2E            CS:
004  3760:06F8 803E3E6B00    CMP     BYTE PTR [6B3E],00
005  3760:06FD 740E          JZ      070D
006  3760:06FF 90            NOP     
007  3760:0700 90            NOP     
008  3760:0701 EA00000000    JMP     0000:0000
009  3760:0706 2E            CS:
010  3760:0707 80263E6B00    AND     BYTE PTR [6B3E],00
011  3760:070C CB            RETF    
012  3760:070D 2E            CS:
013  3760:070E 800E3E6B01    OR      BYTE PTR [6B3E],01
014  3760:0713 60            PUSHA   
015  3760:0714 06            PUSH    ES
016  3760:0715 1E            PUSH    DS
017  3760:0716 52            PUSH    DX
018  3760:0717 1E            PUSH    DS
019  3760:0718 0E            PUSH    CS
020  3760:0719 0E            PUSH    CS
021  3760:071A 1F            POP     DS
022  3760:071B 07            POP     ES
023  3760:071C BF426B        MOV     DI,6B42
024  3760:071F A30D60        MOV     [600D],AX
025  3760:0722 1F            POP     DS
026  3760:0723 8BF2          MOV     SI,DX
027  3760:0725 FC            CLD     
028  3760:0726 B92000        MOV     CX,0020
029  3760:0729 F3            REPZ
030  3760:072A A4            MOVSB   
031  3760:072B 0E            PUSH    CS
032  3760:072C 1F            POP     DS
033  3760:072D 60            PUSHA   
034  3760:072E 1E            PUSH    DS
035  3760:072F 0E            PUSH    CS
036  3760:0730 1F            POP     DS
037  3760:0731 F8            CLC     
038  3760:0732 B402          MOV     AH,02                 ; 取CMOS时间
039  3760:0734 CD1A          INT     1A      (BIOS Clock)
040  3760:0736 7308          JNB     0740                  ; 执行BIOS成功
041  3760:0738 90            NOP     
042  3760:0739 90            NOP     
043  3760:073A 1F            POP     DS
044  3760:073B 61            POPA    
045  3760:073C 7251          JB      078F
046  3760:073E 90            NOP     
047  3760:073F 90            NOP     
048  3760:0740 53            PUSH    BX
049  3760:0741 8AC5          MOV     AL,CH                 ; 时间的小时部分
050  3760:0743 E85523        CALL    2A9B                  ; 将小时的BCD码转换成十进制数
051  3760:0746 8AF8          MOV     BH,AL
052  3760:0748 8AC1          MOV     AL,CL                 ; 时间的分钟部分
053  3760:074A E84E23        CALL    2A9B                  ; 将分钟的BCD码转换成十进制数
054  3760:074D 8AD8          MOV     BL,AL
055  3760:074F 8BCB          MOV     CX,BX
056  3760:0751 5B            POP     BX
057  3760:0752 33C0          XOR     AX,AX
058  3760:0754 8AC5          MOV     AL,CH                 ; 时间的小时数
059  3760:0756 B33C          MOV     BL,3C                 ; 60,
060  3760:0758 F6E3          MUL     BL                    ; 将小时换算成分钟数
061  3760:075A B500          MOV     CH,00
062  3760:075C 03C1          ADD     AX,CX                 ; AX=时间的分钟数
063  3760:075E 2E            CS:
064  3760:075F 2B060F79      SUB     AX,[790F]             ; [790Fh]存着程序启动时时间的分钟数
065  3760:0763 3D1400        CMP     AX,0014               ; 20分钟
066  3760:0766 1F            POP     DS
067  3760:0767 61            POPA    
068  3760:0768 7225          JB      078F                  ; 启动不到20分钟
069  3760:076A 90            NOP     
070  3760:076B 90            NOP     
071  3760:076C 60            PUSHA   
072  3760:076D BEE55E        MOV     SI,5EE5               ; 指向字符串:Terminate Demo Version
073  3760:0770 E86322        CALL    29D6                  ; 显示字符串
074  3760:0773 BE015F        MOV     SI,5F01               ; 指向字符串:please unload DOSUSB
075  3760:0776 E85D22        CALL    29D6                  ; 显示字符串
076  3760:0779 BEE15F        MOV     SI,5FE1               ; 指向一个仅有回车换行的字符串
077  3760:077C E85722        CALL    29D6                  ; 显示回车换行
078  3760:077F B8E803        MOV     AX,03E8               ; 1000
079  3760:0782 E8F521        CALL    297A                  ; 该子程序根据AX的值,延迟若干毫秒。延迟1秒
080  3760:0785 61            POPA    
081  3760:0786 C606476B42    MOV     BYTE PTR [6B47],42
082  3760:078B 90            NOP     
083  3760:078C E9E905        JMP     0D78
084  ............
085  3760:0D78 8B1EA061      MOV     BX,[61A0]
086  3760:0D7C 83FB00        CMP     BX,+00
087  3760:0D7F 7406          JZ      0D87
088  3760:0D81 90            NOP     
089  3760:0D82 90            NOP     
090  3760:0D83 B43E          MOV     AH,3E
091  3760:0D85 CD21          INT     21      (DOS)
092  3760:0D87 2E            CS:
093  3760:0D88 80263E6B00    AND     BYTE PTR [6B3E],00
094  3760:0D8D BE426B        MOV     SI,6B42
095  3760:0D90 1E            PUSH    DS
096  3760:0D91 58            POP     AX
097  3760:0D92 5A            POP     DX
098  3760:0D93 1F            POP     DS
099  3760:0D94 1E            PUSH    DS
100  3760:0D95 07            POP     ES
101  3760:0D96 50            PUSH    AX
102  3760:0D97 1F            POP     DS
103  3760:0D98 8BFA          MOV     DI,DX
104  3760:0D9A FC            CLD     
105  3760:0D9B B92000        MOV     CX,0020
106  3760:0D9E F3            REPZ
107  3760:0D9F A4            MOVSB   
108  3760:0DA0 06            PUSH    ES
109  3760:0DA1 1F            POP     DS
110  3760:0DA2 07            POP     ES
111  3760:0DA3 61            POPA    
112  3760:0DA4 CF            IRET

    这段程序,我们的注释要少一些,因为大多和本文话题不相干。
1、003-005行,比较[6b3eh]的值是否为0,肯定要为0,所以会转到012行,去执行;如果不为0,执行008行的代码会导致死机。
2、[6b3eh]就是一个标志,012-013行会把这个标志的bit 0置1,使其不为0,如果中断可以正常退出,该标志会被清0,如果不为0,表明上一次的中断时非正常退出的,这时,就会产生死机。
3、038-039行是我们期待的,调用了一个BIOS功能,取得了系统实时时钟的当前时间。
4、049-062行,同样把取得的时间换算成了相对于当天0点的分钟数,以便和当初dosusb.com启动时取得的时间进行对比。
5、064-065行,判断当前时间与程序启动时间只差是否小于20分钟,如果小于20分钟则继续处理中断(068行),如果大于20分钟,则执行069-083行。
6、069-083行,显示了一些信息,然后等待一秒种后085行后面的程序,这段程序只是处理了一些中断返回前的一些善后工作,并无其他。

    总结一下,我们终于找到了限制20分钟的地方,其关键就是064--068行这几句的比较。

    下面,我们看看有没有什么办法来解决dosusb.com这个20分钟限制的问题,其实,经过以上的分析实在是太简单了,我们注意一下第068行,指令是:JB 078F,含义是如果小于20分钟则跳转到078Fh这个地址去继续执行,如果我们可以把这句改成JMP 078F,那么不管比较结果如何,都会跳转到078Fh去执行,自然20分钟的限制也就没有了。
    下面我们具体改改看:
DOSUSB 2.0 免费版的限制原理 - whowin - DOS编程技术
图9
 
    这个就是整个的修改过程,这样改完之后,你的dosusb.com就不会再有20分钟的限制了,可以说就什么限制都没有了,道理在上面用了那么大的篇幅都已经说过了,当然,你还可以改的更好,比如把那些涉及DEMO版本的提示改一改,让dosusb.com看上去更像是一个正式版的样子,这些可以自己去做,比起本文的内容,那些太简单了。

    本文目的在于可以让广大的DOS爱好者可以使用DOSUSB自己开发出一些涉及USB设备的驱动程序或者应用程序,希望读者不要把它用于商业目的,请尊重开发者的劳动,如果用于商业目的,还是希望想DOSUSB的开发者付费,对于个人来说,DOSUSB的费用确实有些贵,但对一个商业项目来说,几十欧元对成本来说基本上和没有差不多。谢谢!


  评论这张
 
阅读(4857)| 评论(13)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018