DOSUSB 2.0 免费版的限制原理

时间:2023-03-09 01:57:37
DOSUSB 2.0 免费版的限制原理

  两年前,我在写USB的文章时,多次提到了DOSUSB这个东东,这两年也没有关注这方面的变化,最近,有机会重新进入DOSUSB的官方网站(www.dosusb.net),欣喜地发现,这个网站不仅依然存在,而且还有所发展,相继推出了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.hengch.com/software/debug32.rar
  整个反编译工作实在虚拟机下完成的,当然也可以在一般的运行DOS的机器上完成。另外,我发现DOSUSB在Virsual Box下不能运行,会出现虚拟机崩溃的现象,没有研究其原因,也许就是有个中断冲突等小问题,所以,所有的运行试验都是在一个运行DOS的机器上完成的,实际环境为DOS 6.22。
  我们先来看一下启动DOSUSB时的实际情况:
DOSUSB 2.0 免费版的限制原理
在最上面的信息中,非常明确地指出,这是一个没有注册的版本,是有时间限制的Demo版本。
然后,我们运行一下随DOSUSB一起发行的usbview程序,在我的机器上运行结果如下:
DOSUSB 2.0 免费版的限制原理
图2
DOSUSB 2.0 免费版的限制原理
图3
DOSUSB 2.0 免费版的限制原理
图4 
DOSUSB 2.0 免费版的限制原理
图5 
    运行这个程序是为了说明DOSUSB是可以使用的,可以和20分钟后DOSUSB禁止使用时做比较。我们再看一下20分钟后,DOSUSB不能使用时的情况,我们再次运行usbview程序:
DOSUSB 2.0 免费版的限制原理
图6 
DOSUSB 2.0 免费版的限制原理
图7

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

  现在我们开始用debug反汇编dosusb.com这个程序。在dos提示符下输入:debug dosusb.com(也许是debug32 dosusb.com)
  下面是在我的虚拟机下反汇编出来的部分汇编代码,我们只选择了一些和这篇文章话题相关的代码,重要的地方都做了详细的注释,很多的子程序并没有列在这里,但注释中说明了其功能,为了说明方便,都加了行号: 
行号 内存地址  二进制码      反汇编指令                    注释
------------------------------------------------------------------------------------------------
  : E93D05        JMP
  ......(这里是一块数据区)
  : BBA386        MOV     BX,86A3               ; 新分配的段落块(16字节)数量
  : C1EB04        SHR     BX,                 ; ES=内存块段地址
  :             INC     BX
  : B44A          MOV     AH,4A
  : CD21          INT                         ; 修改分配的内存块
  :064B B8626B        MOV     AX,6B62
  :064E         ADD     AX,               ; 重新设置堆栈,栈底在6b62h
  : 8BE0          MOV     SP,AX                 ; 堆栈长度为800h
  : E8DE72        CALL                      ; 判断运行环境,设置内存策略
  ............(这里省略若干行代码)
  :069B E82673        CALL    79C4                  ; 显示DOSUSB的版本信息
  :069E BEBD5E        MOV     SI,5EBD               ; 指向字符串:Time restricted Demo Version
  :06A1 E83223        CALL    29D6                  ; 显示字符串
  :06A4             PUSHA
  :06A5 B42C          MOV     AH,2C                 ; DOS功能:取时间
  :06A7 CD21          INT           (DOS)
  :06A9 890E0360      MOV     [],CX             ; CH=小时,CL=分钟
  :06AD             POPA
  :06AE             PUSHA
  :06AF 8B0E0360      MOV     CX,[]
  :06B3 33C0          XOR     AX,AX
  :06B5 8AC5          MOV     AL,CH                 ; 小时(--)
  :06B7 B33C          MOV     BL,3C                 ; 3ch=,把小时数换算成分钟数
  :06B9 F6E3          MUL     BL                    ; AX中为当前时间的小时部分转换的分钟数
  :06BB B500          MOV     CH,
  :06BD 03C1          ADD     AX,CX                 ; 加上当前时间的分钟数,为相对于凌晨的分钟数
  :06BF A30F79        MOV     [790F],AX             ; word [790fh]存储启动程序时的分钟数
  :06C2 1E            PUSH    DS
  :06C3 33C0          XOR     AX,AX
  :06C5 8ED8          MOV     DS,AX
  :06C7 A0FE04        MOV     AL,[04FE]             ; :04feh在BIOS数据区,用这个位置记录程序的启动次数
  :06CA 3C0A          CMP     AL,0A                 ; 当启动次数达到10次时,将不能再次启动,需要重新启动计算机
  :06CC           JB      06E2                  ; <10次启动,可以运行
  :06CE             NOP
  :06CF             NOP
  :06D0 1F            POP     DS
  :06D1 BEE55E        MOV     SI,5EE5               ; Terminal Demo Version!
  :06D4 E8FF22        CALL    29D6                  ; 显示一个以\0结尾的字符串
  :06D7 BEE15F        MOV     SI,5FE1               ; 回车,换行
  :06DA E8F922        CALL    29D6                  ; 显示一个以\0结尾的字符串
  :06DD             POPA
  :06DE B44C          MOV     AH,4C                 ; DOS功能,退出应用程序
  :06E0 CD21          INT           (DOS)
  :06E2 FEC0          INC     AL                    ; 将启动次数+1后存回0:04feh的位置
  :06E4 A2FE04        MOV     [04FE],AL
  :06E7 1F            POP     DS
  :06E8             POPA
  :06E9 E9947C        JMP                       ; 继续进行初始化
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 免费版的限制原理
图8
  在上面屏幕上,我们看到的执行结果中BX中的值就是我们想要的偏移地址,我们现在再回到用debug反编译dosusb.com里面,看看这个偏移地址下的程序是啥东西。
行号 内存地址  二进制码      反汇编指令                    注释
------------------------------------------------------------------------------------------------
  :06EC EB09          JMP     06F7
  :06EE   4F     0A - 2E        DOSUSB....
  :06F7 2E            CS:
  :06F8 803E3E6B00    CMP     BYTE PTR [6B3E],
  :06FD 740E          JZ      070D
  :06FF             NOP
  :             NOP
  : EA00000000    JMP     :
  : 2E            CS:
  : 80263E6B00    AND     BYTE PTR [6B3E],
  :070C CB            RETF
  :070D 2E            CS:
  :070E 800E3E6B01    OR      BYTE PTR [6B3E],
  :             PUSHA
  :             PUSH    ES
  : 1E            PUSH    DS
  :             PUSH    DX
  : 1E            PUSH    DS
  : 0E            PUSH    CS
  : 0E            PUSH    CS
  :071A 1F            POP     DS
  :071B             POP     ES
  :071C BF426B        MOV     DI,6B42
  :071F A30D60        MOV     [600D],AX
  : 1F            POP     DS
  : 8BF2          MOV     SI,DX
  : FC            CLD
  : B92000        MOV     CX,
  : F3            REPZ
  :072A A4            MOVSB
  :072B 0E            PUSH    CS
  :072C 1F            POP     DS
  :072D             PUSHA
  :072E 1E            PUSH    DS
  :072F 0E            PUSH    CS
  : 1F            POP     DS
  : F8            CLC
  : B402          MOV     AH,                 ; 取CMOS时间
  : CD1A          INT     1A      (BIOS Clock)
  :           JNB                       ; 执行BIOS成功
  :             NOP
  :             NOP
  :073A 1F            POP     DS
  :073B             POPA
  :073C           JB      078F
  :073E             NOP
  :073F             NOP
  :             PUSH    BX
  : 8AC5          MOV     AL,CH                 ; 时间的小时部分
  : E85523        CALL    2A9B                  ; 将小时的BCD码转换成十进制数
  : 8AF8          MOV     BH,AL
  : 8AC1          MOV     AL,CL                 ; 时间的分钟部分
  :074A E84E23        CALL    2A9B                  ; 将分钟的BCD码转换成十进制数
  :074D 8AD8          MOV     BL,AL
  :074F 8BCB          MOV     CX,BX
  : 5B            POP     BX
  : 33C0          XOR     AX,AX
  : 8AC5          MOV     AL,CH                 ; 时间的小时数
  : B33C          MOV     BL,3C                 ; ,
  : F6E3          MUL     BL                    ; 将小时换算成分钟数
  :075A B500          MOV     CH,
  :075C 03C1          ADD     AX,CX                 ; AX=时间的分钟数
  :075E 2E            CS:
  :075F 2B060F79      SUB     AX,[790F]             ; [790Fh]存着程序启动时时间的分钟数
  : 3D1400        CMP     AX,               ; 20分钟
  : 1F            POP     DS
  :             POPA
  :           JB      078F                  ; 启动不到20分钟
  :076A             NOP
  :076B             NOP
  :076C             PUSHA
  :076D BEE55E        MOV     SI,5EE5               ; 指向字符串:Terminate Demo Version
  : E86322        CALL    29D6                  ; 显示字符串
  : BE015F        MOV     SI,5F01               ; 指向字符串:please unload DOSUSB
  : E85D22        CALL    29D6                  ; 显示字符串
  : BEE15F        MOV     SI,5FE1               ; 指向一个仅有回车换行的字符串
  :077C E85722        CALL    29D6                  ; 显示回车换行
  :077F B8E803        MOV     AX,03E8               ;
  : E8F521        CALL    297A                  ; 该子程序根据AX的值,延迟若干毫秒。延迟1秒
  :             POPA
  : C606476B42    MOV     BYTE PTR [6B47],
  :078B             NOP
  :078C E9E905        JMP     0D78
  ............
  :0D78 8B1EA061      MOV     BX,[61A0]
  :0D7C 83FB00        CMP     BX,+
  :0D7F           JZ      0D87
  :0D81             NOP
  :0D82             NOP
  :0D83 B43E          MOV     AH,3E
  :0D85 CD21          INT           (DOS)
  :0D87 2E            CS:
  :0D88 80263E6B00    AND     BYTE PTR [6B3E],
  :0D8D BE426B        MOV     SI,6B42
  :0D90 1E            PUSH    DS
  :0D91             POP     AX
  :0D92 5A            POP     DX
  :0D93 1F            POP     DS
  :0D94 1E            PUSH    DS
  :0D95             POP     ES
  :0D96             PUSH    AX
  :0D97 1F            POP     DS
  :0D98 8BFA          MOV     DI,DX
  :0D9A FC            CLD
  :0D9B B92000        MOV     CX,
  :0D9E F3            REPZ
  :0D9F A4            MOVSB
  :0DA0             PUSH    ES
  :0DA1 1F            POP     DS
  :0DA2             POP     ES
  :0DA3             POPA
  :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 免费版的限制原理
图9
  这个就是整个的修改过程,这样改完之后,你的dosusb.com就不会再有20分钟的限制了,可以说就什么限制都没有了,道理在上面用了那么大的篇幅都已经说过了,当然,你还可以改的更好,比如把那些涉及DEMO版本的提示改一改,让dosusb.com看上去更像是一个正式版的样子,这些可以自己去做,比起本文的内容,那些太简单了。
  本文目的在于可以让广大的DOS爱好者可以使用DOSUSB自己开发出一些涉及USB设备的驱动程序或者应用程序,希望读者不要把它用于商业目的,请尊重开发者的劳动,如果用于商业目的,还是希望想DOSUSB的开发者付费,对于个人来说,DOSUSB的费用确实有些贵,但对一个商业项目来说,几十欧元对成本来说基本上和没有差不多。谢谢!